1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2001-2003 Eddy De Greef <eddy_de_greef at scarlet dot be> 4141cc406Sopenharmony_ci This file is part of the SANE package. 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 7141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 8141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 9141cc406Sopenharmony_ci License, or (at your option) any later version. 10141cc406Sopenharmony_ci 11141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 12141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 13141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14141cc406Sopenharmony_ci General Public License for more details. 15141cc406Sopenharmony_ci 16141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 17141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 18141cc406Sopenharmony_ci 19141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 20141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 23141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 24141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 25141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 26141cc406Sopenharmony_ci account of linking the SANE library code into it. 27141cc406Sopenharmony_ci 28141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 29141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 30141cc406Sopenharmony_ci License. 31141cc406Sopenharmony_ci 32141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 33141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 34141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 35141cc406Sopenharmony_ci 36141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 37141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 38141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 39141cc406Sopenharmony_ci 40141cc406Sopenharmony_ci This file implements a SANE backend for Mustek PP flatbed _CIS_ scanners. 41141cc406Sopenharmony_ci*/ 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci/* 44141cc406Sopenharmony_ci Global picture 45141cc406Sopenharmony_ci 46141cc406Sopenharmony_ci Mustek_PP_handle -> Mustek_PP_dev 47141cc406Sopenharmony_ci -> priv = Mustek_PP_CIS_dev -> CIS 48141cc406Sopenharmony_ci*/ 49141cc406Sopenharmony_ci 50141cc406Sopenharmony_ci/* 51141cc406Sopenharmony_ci * This flag determines whether the scanner uses fast skipping at high 52141cc406Sopenharmony_ci * resolutions. It is possible that this fast skipping introduces 53141cc406Sopenharmony_ci * inaccuracies. It if turns out to be a problem, fast skipping can 54141cc406Sopenharmony_ci * be disabled by setting this flag to 0. 55141cc406Sopenharmony_ci */ 56141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_FAST_SKIP 1 57141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_WAIT_BANK 200 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci/* 60141cc406Sopenharmony_ci * These parameters determine where the scanable area starts at the top. 61141cc406Sopenharmony_ci * If there is a consistent offset error, you can tune it through these 62141cc406Sopenharmony_ci * parameters. Note that an inaccuracy in the order of 1 mm seems to be 63141cc406Sopenharmony_ci * normal for the Mustek 600/1200 CP series. 64141cc406Sopenharmony_ci */ 65141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_600CP_DEFAULT_SKIP 250 66141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_1200CP_DEFAULT_SKIP 330 67141cc406Sopenharmony_ci 68141cc406Sopenharmony_ci/* 69141cc406Sopenharmony_ci * Number of scan lines on which the average is taken to determine the 70141cc406Sopenharmony_ci * maximum number of color levels. 71141cc406Sopenharmony_ci */ 72141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_AVERAGE_COUNT 32 73141cc406Sopenharmony_ci 74141cc406Sopenharmony_ci#define MUSTEK_PP_CIS600 1 75141cc406Sopenharmony_ci#define MUSTEK_PP_CIS1200 2 76141cc406Sopenharmony_ci#define MUSTEK_PP_CIS1200PLUS 3 77141cc406Sopenharmony_ci 78141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_CHANNEL_RED 0 79141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_CHANNEL_GREEN 1 80141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_CHANNEL_BLUE 2 81141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_CHANNEL_GRAY 1 82141cc406Sopenharmony_ci 83141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_MAX_H_PIXEL 5118 84141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_MAX_V_PIXEL 7000 85141cc406Sopenharmony_ci 86141cc406Sopenharmony_ci#define MUSTEK_PP_CIS_MOTOR_REVERSE 0 87141cc406Sopenharmony_ci 88141cc406Sopenharmony_ci#include "../include/sane/config.h" 89141cc406Sopenharmony_ci 90141cc406Sopenharmony_ci#include <assert.h> 91141cc406Sopenharmony_ci#include <string.h> 92141cc406Sopenharmony_ci#include <stdlib.h> 93141cc406Sopenharmony_ci#include <stdio.h> 94141cc406Sopenharmony_ci#include <unistd.h> 95141cc406Sopenharmony_ci#include <math.h> 96141cc406Sopenharmony_ci#ifdef HAVE_SYS_SELECT_H 97141cc406Sopenharmony_ci# include <sys/select.h> 98141cc406Sopenharmony_ci#endif 99141cc406Sopenharmony_ci#include "../include/sane/sane.h" 100141cc406Sopenharmony_ci#include "../include/sane/sanei_pa4s2.h" 101141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 102141cc406Sopenharmony_ci#include "mustek_pp.h" 103141cc406Sopenharmony_ci#include "mustek_pp_decl.h" 104141cc406Sopenharmony_ci#include "mustek_pp_cis.h" 105141cc406Sopenharmony_ci 106141cc406Sopenharmony_ci/****************************************************************************** 107141cc406Sopenharmony_ci ****************************************************************************** 108141cc406Sopenharmony_ci *** MA1015 chipset related functionality *** 109141cc406Sopenharmony_ci ****************************************************************************** 110141cc406Sopenharmony_ci *****************************************************************************/ 111141cc406Sopenharmony_ci 112141cc406Sopenharmony_ci/* 113141cc406Sopenharmony_ci These defines control some debugging functionality 114141cc406Sopenharmony_ci 115141cc406Sopenharmony_ci #define M1015_TRACE_REGS -> trace the status of the internal registers 116141cc406Sopenharmony_ci #define M1015_LOG_HL -> create a high-level log file (register-level) 117141cc406Sopenharmony_ci #define M1015_LOG_LL -> create a low-level log file (byte-level) 118141cc406Sopenharmony_ci 119141cc406Sopenharmony_ci By default, all logging/tracing is turned off. 120141cc406Sopenharmony_ci*/ 121141cc406Sopenharmony_ci 122141cc406Sopenharmony_ci/****************************************************************************** 123141cc406Sopenharmony_ci * Low level logging: logs read and writes at the byte level, similar to 124141cc406Sopenharmony_ci * the sequences produced by tool of Jochen Eisinger 125141cc406Sopenharmony_ci * for analysing the TWAIN driver communication. 126141cc406Sopenharmony_ci * This simplifies comparison of the sequences. 127141cc406Sopenharmony_ci *****************************************************************************/ 128141cc406Sopenharmony_ci#ifdef M1015_LOG_LL 129141cc406Sopenharmony_ci 130141cc406Sopenharmony_ci static FILE* M1015_LOG_1; 131141cc406Sopenharmony_ci 132141cc406Sopenharmony_ci #define M1015_START_LL\ 133141cc406Sopenharmony_ci M1015_LOG_1 = fopen("cis_ll.log", "w"); 134141cc406Sopenharmony_ci 135141cc406Sopenharmony_ci #define M1015_STOP_LL\ 136141cc406Sopenharmony_ci fclose(M1015_LOG_1); 137141cc406Sopenharmony_ci 138141cc406Sopenharmony_ci #define SANEI_PA4S2_WRITEBYTE(fd, reg, val)\ 139141cc406Sopenharmony_ci do\ 140141cc406Sopenharmony_ci {\ 141141cc406Sopenharmony_ci sanei_pa4s2_writebyte (fd, reg, val);\ 142141cc406Sopenharmony_ci fprintf(M1015_LOG_1, "\tsanei_pa4s2_writebyte(fd, %d, 0x%02X);\n", \ 143141cc406Sopenharmony_ci reg, val);\ 144141cc406Sopenharmony_ci } while (0) 145141cc406Sopenharmony_ci 146141cc406Sopenharmony_ci static const char* cis_last_rreg_name; 147141cc406Sopenharmony_ci static int cis_read_count; 148141cc406Sopenharmony_ci 149141cc406Sopenharmony_ci #define SANEI_PA4S2_READBEGIN(fd, reg)\ 150141cc406Sopenharmony_ci do\ 151141cc406Sopenharmony_ci {\ 152141cc406Sopenharmony_ci cis_last_rreg_name = Mustek_PP_1015_reg_r_name(reg);\ 153141cc406Sopenharmony_ci cis_read_count = 0;\ 154141cc406Sopenharmony_ci sanei_pa4s2_readbegin(fd, reg);\ 155141cc406Sopenharmony_ci } while (0) 156141cc406Sopenharmony_ci 157141cc406Sopenharmony_ci #define SANEI_PA4S2_READBYTE(fd, val)\ 158141cc406Sopenharmony_ci do\ 159141cc406Sopenharmony_ci {\ 160141cc406Sopenharmony_ci sanei_pa4s2_readbyte(fd, val);\ 161141cc406Sopenharmony_ci ++cis_read_count;\ 162141cc406Sopenharmony_ci } while (0) 163141cc406Sopenharmony_ci 164141cc406Sopenharmony_ci #define SANEI_PA4S2_READEND(fd)\ 165141cc406Sopenharmony_ci do\ 166141cc406Sopenharmony_ci {\ 167141cc406Sopenharmony_ci sanei_pa4s2_readend(fd);\ 168141cc406Sopenharmony_ci fprintf(M1015_LOG_1, "\tread_reg(%s, %d);\n", \ 169141cc406Sopenharmony_ci cis_last_rreg_name, cis_read_count);\ 170141cc406Sopenharmony_ci } while (0) 171141cc406Sopenharmony_ci 172141cc406Sopenharmony_ci #define M1015_MARK_LL(info)\ 173141cc406Sopenharmony_ci fprintf(M1015_LOG_1, "* %s\n", info); 174141cc406Sopenharmony_ci 175141cc406Sopenharmony_ci#else /* M1015_LOG_LL */ 176141cc406Sopenharmony_ci 177141cc406Sopenharmony_ci #define M1015_START_LL 178141cc406Sopenharmony_ci #define M1015_STOP_LL 179141cc406Sopenharmony_ci 180141cc406Sopenharmony_ci #define SANEI_PA4S2_WRITEBYTE(fd, reg, val)\ 181141cc406Sopenharmony_ci sanei_pa4s2_writebyte (fd, reg, val) 182141cc406Sopenharmony_ci 183141cc406Sopenharmony_ci #define SANEI_PA4S2_READBEGIN(fd, reg)\ 184141cc406Sopenharmony_ci sanei_pa4s2_readbegin(fd, reg) 185141cc406Sopenharmony_ci 186141cc406Sopenharmony_ci #define SANEI_PA4S2_READBYTE(fd, val)\ 187141cc406Sopenharmony_ci sanei_pa4s2_readbyte(fd, val) 188141cc406Sopenharmony_ci 189141cc406Sopenharmony_ci #define SANEI_PA4S2_READEND(fd)\ 190141cc406Sopenharmony_ci sanei_pa4s2_readend(fd) 191141cc406Sopenharmony_ci 192141cc406Sopenharmony_ci #define M1015_MARK_LL(info) 193141cc406Sopenharmony_ci 194141cc406Sopenharmony_ci#endif /* M1015_LOG_LL */ 195141cc406Sopenharmony_ci 196141cc406Sopenharmony_ci 197141cc406Sopenharmony_ci/****************************************************************************** 198141cc406Sopenharmony_ci * High-level logging: traces the flow of the driver in a hierarchical way 199141cc406Sopenharmony_ci * up to the level of register accesses. 200141cc406Sopenharmony_ci *****************************************************************************/ 201141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 202141cc406Sopenharmony_ci 203141cc406Sopenharmony_ci static FILE* M1015_LOG_2; 204141cc406Sopenharmony_ci static char hl_prev_line[4096], hl_next_line[4096], hl_repeat_count; 205141cc406Sopenharmony_ci 206141cc406Sopenharmony_ci /* 207141cc406Sopenharmony_ci * A few variables for hierarchical log message indentation. 208141cc406Sopenharmony_ci */ 209141cc406Sopenharmony_ci 210141cc406Sopenharmony_ci static const char* cis_indent_start = 211141cc406Sopenharmony_ci " "; 212141cc406Sopenharmony_ci static const char* cis_indent; 213141cc406Sopenharmony_ci static const char* cis_indent_end; 214141cc406Sopenharmony_ci 215141cc406Sopenharmony_ci #define M1015_START_HL\ 216141cc406Sopenharmony_ci M1015_LOG_2 = fopen("cis_hl.log", "w");\ 217141cc406Sopenharmony_ci cis_indent = cis_indent_start + strlen(cis_indent_start);\ 218141cc406Sopenharmony_ci cis_indent_end = cis_indent;\ 219141cc406Sopenharmony_ci hl_prev_line[0] = 0;\ 220141cc406Sopenharmony_ci hl_next_line[0] = 0;\ 221141cc406Sopenharmony_ci hl_repeat_count = 0; 222141cc406Sopenharmony_ci 223141cc406Sopenharmony_ci #define M1015_FLUSH_HL\ 224141cc406Sopenharmony_ci if (strcmp(hl_prev_line, hl_next_line))\ 225141cc406Sopenharmony_ci {\ 226141cc406Sopenharmony_ci fprintf(M1015_LOG_2, &hl_prev_line[0]);\ 227141cc406Sopenharmony_ci strcpy(&hl_prev_line[0], &hl_next_line[0]);\ 228141cc406Sopenharmony_ci if (hl_repeat_count != 0)\ 229141cc406Sopenharmony_ci {\ 230141cc406Sopenharmony_ci fprintf(M1015_LOG_2, "%s [last message repeated %d times]\n",\ 231141cc406Sopenharmony_ci cis_indent, hl_repeat_count+1); \ 232141cc406Sopenharmony_ci }\ 233141cc406Sopenharmony_ci hl_repeat_count = 0;\ 234141cc406Sopenharmony_ci }\ 235141cc406Sopenharmony_ci else\ 236141cc406Sopenharmony_ci {\ 237141cc406Sopenharmony_ci hl_repeat_count += 1;\ 238141cc406Sopenharmony_ci } 239141cc406Sopenharmony_ci 240141cc406Sopenharmony_ci #define M1015_MARK(info)\ 241141cc406Sopenharmony_ci sprintf(&hl_next_line[0], "%s+ %s\n", cis_indent, info);\ 242141cc406Sopenharmony_ci M1015_FLUSH_HL 243141cc406Sopenharmony_ci 244141cc406Sopenharmony_ci #define M1015_STOP_HL\ 245141cc406Sopenharmony_ci hl_next_line[0] = 0;\ 246141cc406Sopenharmony_ci M1015_FLUSH_HL\ 247141cc406Sopenharmony_ci fclose(M1015_LOG_2); 248141cc406Sopenharmony_ci 249141cc406Sopenharmony_ci#else /* M1015_LOG_HL */ 250141cc406Sopenharmony_ci 251141cc406Sopenharmony_ci #define M1015_START_HL 252141cc406Sopenharmony_ci #define M1015_STOP_HL 253141cc406Sopenharmony_ci #define M1015_MARK(info) 254141cc406Sopenharmony_ci #define M1015_FLUSH_HL 255141cc406Sopenharmony_ci 256141cc406Sopenharmony_ci#endif /* M1015_LOG_HL */ 257141cc406Sopenharmony_ci 258141cc406Sopenharmony_ci#ifdef M1015_TRACE_REGS 259141cc406Sopenharmony_ci #define M1015_DISPLAY_REGS(dev, msg) Mustek_PP_1015_display_regs(dev, msg) 260141cc406Sopenharmony_ci #define M1015_DISPLAY_REG(msg, val) Mustek_PP_1015_display_reg(msg, val) 261141cc406Sopenharmony_ci#else 262141cc406Sopenharmony_ci #define M1015_DISPLAY_REGS(dev, msg) 263141cc406Sopenharmony_ci #define M1015_DISPLAY_REG(msg, val) 264141cc406Sopenharmony_ci#endif 265141cc406Sopenharmony_ci 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci#if defined (M1015_LOG_HL) || defined (M1015_LOG_LL) 268141cc406Sopenharmony_cistatic const char* 269141cc406Sopenharmony_ciMustek_PP_1015_reg_r_name(Mustek_PP_1015R_reg id) 270141cc406Sopenharmony_ci{ 271141cc406Sopenharmony_ci static const char* names[4] = { "ASIC", "SCAN_VAL", "MOTOR", "BANK_COUNT" }; 272141cc406Sopenharmony_ci return names[id & 0x03]; 273141cc406Sopenharmony_ci} 274141cc406Sopenharmony_ci 275141cc406Sopenharmony_cistatic const char* 276141cc406Sopenharmony_ciMustek_PP_1015_bit_name(Mustek_PP_1015R_bit id) 277141cc406Sopenharmony_ci{ 278141cc406Sopenharmony_ci static const char* names[4] = { "????", "MOTOR_HOME", "????", "MOTOR_BUSY" }; 279141cc406Sopenharmony_ci return names[id & 0x03]; 280141cc406Sopenharmony_ci} 281141cc406Sopenharmony_ci 282141cc406Sopenharmony_cistatic const char* 283141cc406Sopenharmony_ciMustek_PP_1015_reg_w_name(Mustek_PP_1015R_reg id) 284141cc406Sopenharmony_ci{ 285141cc406Sopenharmony_ci static const char* names[4][4] = 286141cc406Sopenharmony_ci { 287141cc406Sopenharmony_ci { "RED_REF", "GREEN_REF", "BLUE_REF", "DPI_CONTROL" }, 288141cc406Sopenharmony_ci { "BYTE_COUNT_HB", "BYTE_COUNT_LB", "SKIP_COUNT", "EXPOSE_TIME" }, 289141cc406Sopenharmony_ci { "SRAM_SOURCE_PC", "MOTOR_CONTROL", "UNKNOWN_42", "UNKNOWN_82" }, 290141cc406Sopenharmony_ci { "POWER_ON_DELAY", "CCD_TIMING", "CCD_TIMING_ADJ", "RIGHT_BOUND" } 291141cc406Sopenharmony_ci }; 292141cc406Sopenharmony_ci return names[(id & 0x30) >> 4][id & 0x03]; 293141cc406Sopenharmony_ci} 294141cc406Sopenharmony_ci#endif 295141cc406Sopenharmony_ci 296141cc406Sopenharmony_ci/****************************************************************************** 297141cc406Sopenharmony_ci * Converts a register value to a hex/dec/bin representation. 298141cc406Sopenharmony_ci *****************************************************************************/ 299141cc406Sopenharmony_cistatic const char* 300141cc406Sopenharmony_ciMustek_PP_1015_show_val(int val) 301141cc406Sopenharmony_ci{ 302141cc406Sopenharmony_ci /* 303141cc406Sopenharmony_ci Since we use a static temporary buffer, we must make sure that the 304141cc406Sopenharmony_ci buffer isn't altered while it is still in use (typically because 305141cc406Sopenharmony_ci more than one value is converted in a printf statement). 306141cc406Sopenharmony_ci Therefore the buffer is organized as a ring buffer. If should contain 307141cc406Sopenharmony_ci at least 21 elements in order to be able to display all registers 308141cc406Sopenharmony_ci with one printf statement. 309141cc406Sopenharmony_ci */ 310141cc406Sopenharmony_ci #define Mustek_PP_1015_RING_BUFFER_SIZE 50 311141cc406Sopenharmony_ci static char buf[Mustek_PP_1015_RING_BUFFER_SIZE][64]; 312141cc406Sopenharmony_ci static int index = 0; 313141cc406Sopenharmony_ci int i; 314141cc406Sopenharmony_ci char* current = (char*)buf[index++]; 315141cc406Sopenharmony_ci 316141cc406Sopenharmony_ci if (index >= Mustek_PP_1015_RING_BUFFER_SIZE) index = 0; 317141cc406Sopenharmony_ci 318141cc406Sopenharmony_ci if (val < 0) 319141cc406Sopenharmony_ci { 320141cc406Sopenharmony_ci /* The register has not been initialized yet. */ 321141cc406Sopenharmony_ci sprintf(current, "---- (---) --------"); 322141cc406Sopenharmony_ci } 323141cc406Sopenharmony_ci else 324141cc406Sopenharmony_ci { 325141cc406Sopenharmony_ci sprintf(current, "0x%02X (%3d) ", val & 0xFF, val & 0xFF); 326141cc406Sopenharmony_ci for (i=0; i<8; ++i) 327141cc406Sopenharmony_ci { 328141cc406Sopenharmony_ci sprintf(current+11+i, "%d", (val >> (7-i)) & 1); 329141cc406Sopenharmony_ci } 330141cc406Sopenharmony_ci } 331141cc406Sopenharmony_ci return current; 332141cc406Sopenharmony_ci} 333141cc406Sopenharmony_ci 334141cc406Sopenharmony_ci#ifdef M1015_TRACE_REGS 335141cc406Sopenharmony_ci/****************************************************************************** 336141cc406Sopenharmony_ci * Displays the contents of all registers of the scanner on stderr. 337141cc406Sopenharmony_ci *****************************************************************************/ 338141cc406Sopenharmony_cistatic void 339141cc406Sopenharmony_ciMustek_PP_1015_display_regs(Mustek_PP_CIS_dev * dev, const char* info) 340141cc406Sopenharmony_ci{ 341141cc406Sopenharmony_ci /* 342141cc406Sopenharmony_ci * Register naming convention: 343141cc406Sopenharmony_ci * Rx : read-only register no. x 344141cc406Sopenharmony_ci * ByWx : write-only register no. x of bank no. y 345141cc406Sopenharmony_ci */ 346141cc406Sopenharmony_ci 347141cc406Sopenharmony_ci fprintf(stderr, 348141cc406Sopenharmony_ci "\n" 349141cc406Sopenharmony_ci "Register status: %s\n" 350141cc406Sopenharmony_ci "\n" 351141cc406Sopenharmony_ci " R0: %s : ASIC info\n" 352141cc406Sopenharmony_ci " R1: %s : scan value\n" 353141cc406Sopenharmony_ci " R2: %s : CCD/motor info\n" 354141cc406Sopenharmony_ci " R3: %s : bank count\n" 355141cc406Sopenharmony_ci "\n" 356141cc406Sopenharmony_ci " B0W0: %s : red reference\n" 357141cc406Sopenharmony_ci " B0W1: %s : green reference\n" 358141cc406Sopenharmony_ci " B0W2: %s : blue reference\n" 359141cc406Sopenharmony_ci " B0W3: %s : DPI control\n" 360141cc406Sopenharmony_ci "\n" 361141cc406Sopenharmony_ci " B1W0: %s : byte count, high byte\n" 362141cc406Sopenharmony_ci " B1W1: %s : byte count, low byte\n" 363141cc406Sopenharmony_ci " B1W2: %s : skip x32 pixels\n" 364141cc406Sopenharmony_ci " B1W3: %s : expose time (CCDWIDTH)\n" 365141cc406Sopenharmony_ci "\n" 366141cc406Sopenharmony_ci " B2W0: %s : SRAM source PC\n" 367141cc406Sopenharmony_ci " B2W1: %s : motor control\n" 368141cc406Sopenharmony_ci " B2W2: %s : -\n" 369141cc406Sopenharmony_ci " B2W3: %s : -\n" 370141cc406Sopenharmony_ci "\n" 371141cc406Sopenharmony_ci " B3W0: %s : power on delay\n" 372141cc406Sopenharmony_ci " B3W1: %s : CCD timing - always 0x05\n" 373141cc406Sopenharmony_ci " B3W2: %s : CCD timing adjust - always 0x00\n" 374141cc406Sopenharmony_ci " B3W3: %s : right bound (not used)\n" 375141cc406Sopenharmony_ci "\n" 376141cc406Sopenharmony_ci " CHAN: %s : channel [%s]\n" 377141cc406Sopenharmony_ci "\n", 378141cc406Sopenharmony_ci info, 379141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.in_regs[0]), 380141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.in_regs[1]), 381141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.in_regs[2]), 382141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.in_regs[3]), 383141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[0][0]), 384141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[0][1]), 385141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[0][2]), 386141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[0][3]), 387141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[1][0]), 388141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[1][1]), 389141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[1][2]), 390141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[1][3]), 391141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[2][0]), 392141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[2][1]), 393141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[2][2]), 394141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[2][3]), 395141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[3][0]), 396141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[3][1]), 397141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[3][2]), 398141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.out_regs[3][3]), 399141cc406Sopenharmony_ci Mustek_PP_1015_show_val (dev->CIS.regs.channel), 400141cc406Sopenharmony_ci (dev->CIS.regs.channel == 0x80 ? "RED" : 401141cc406Sopenharmony_ci (dev->CIS.regs.channel == 0x40 ? "GREEN" : 402141cc406Sopenharmony_ci (dev->CIS.regs.channel == 0xC0 ? "BLUE" : "unknown"))) 403141cc406Sopenharmony_ci ); 404141cc406Sopenharmony_ci} 405141cc406Sopenharmony_ci 406141cc406Sopenharmony_ci/****************************************************************************** 407141cc406Sopenharmony_ci * Displays a single register value 408141cc406Sopenharmony_ci *****************************************************************************/ 409141cc406Sopenharmony_cistatic void 410141cc406Sopenharmony_ciMustek_PP_1015_display_reg(const char* info, int val) 411141cc406Sopenharmony_ci{ 412141cc406Sopenharmony_ci fprintf (stderr, "%s: %s\n", info, Mustek_PP_1015_show_val(val)); 413141cc406Sopenharmony_ci} 414141cc406Sopenharmony_ci 415141cc406Sopenharmony_ci#endif /* M1015_TRACE_REGS */ 416141cc406Sopenharmony_ci 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_ci/****************************************************************************** 419141cc406Sopenharmony_ci * 420141cc406Sopenharmony_ci * Reads one of the 4 internal registers of the scanner 421141cc406Sopenharmony_ci * 422141cc406Sopenharmony_ci * 0: ASIC identification 423141cc406Sopenharmony_ci * 1: scan values 424141cc406Sopenharmony_ci * 2: CCD info / motor info 425141cc406Sopenharmony_ci * 3: bank count info 426141cc406Sopenharmony_ci * 427141cc406Sopenharmony_ci *****************************************************************************/ 428141cc406Sopenharmony_cistatic SANE_Byte 429141cc406Sopenharmony_ciMustek_PP_1015_read_reg(Mustek_PP_CIS_dev * dev, Mustek_PP_1015R_reg reg) 430141cc406Sopenharmony_ci{ 431141cc406Sopenharmony_ci SANE_Byte tmp; 432141cc406Sopenharmony_ci assert(reg <= 3); 433141cc406Sopenharmony_ci 434141cc406Sopenharmony_ci SANEI_PA4S2_READBEGIN (dev->desc->fd, reg & 0x03); 435141cc406Sopenharmony_ci SANEI_PA4S2_READBYTE (dev->desc->fd, &tmp); 436141cc406Sopenharmony_ci SANEI_PA4S2_READEND (dev->desc->fd); 437141cc406Sopenharmony_ci 438141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 439141cc406Sopenharmony_ci sprintf(&hl_next_line[0], "%s read_reg(%s); [%s]\n", cis_indent, 440141cc406Sopenharmony_ci Mustek_PP_1015_reg_r_name(reg), Mustek_PP_1015_show_val(tmp)); 441141cc406Sopenharmony_ci M1015_FLUSH_HL; 442141cc406Sopenharmony_ci#endif 443141cc406Sopenharmony_ci 444141cc406Sopenharmony_ci#ifdef M1015_TRACE_REGS 445141cc406Sopenharmony_ci dev->CIS.regs.in_regs[reg & 0x03] = tmp; 446141cc406Sopenharmony_ci#endif 447141cc406Sopenharmony_ci 448141cc406Sopenharmony_ci return tmp; 449141cc406Sopenharmony_ci} 450141cc406Sopenharmony_ci 451141cc406Sopenharmony_ci/****************************************************************************** 452141cc406Sopenharmony_ci * 453141cc406Sopenharmony_ci * Waits for a bit of register to become 1 or 0. The period of checking can be 454141cc406Sopenharmony_ci * controlled through the sleep parameter (microseconds). 455141cc406Sopenharmony_ci * 456141cc406Sopenharmony_ci *****************************************************************************/ 457141cc406Sopenharmony_cistatic SANE_Bool 458141cc406Sopenharmony_ciMustek_PP_1015_wait_bit(Mustek_PP_CIS_dev * dev, Mustek_PP_1015R_reg reg, 459141cc406Sopenharmony_ci Mustek_PP_1015R_bit bit, SANE_Bool on, unsigned period) 460141cc406Sopenharmony_ci{ 461141cc406Sopenharmony_ci SANE_Byte tmp; 462141cc406Sopenharmony_ci SANE_Byte mask, val; 463141cc406Sopenharmony_ci int tries = 0; 464141cc406Sopenharmony_ci 465141cc406Sopenharmony_ci assert(reg <= 3); 466141cc406Sopenharmony_ci assert(bit <= 3); 467141cc406Sopenharmony_ci 468141cc406Sopenharmony_ci mask = 1 << bit; 469141cc406Sopenharmony_ci 470141cc406Sopenharmony_ci /* We don't want to wait forever */ 471141cc406Sopenharmony_ci while (dev->desc->state != STATE_CANCELLED) 472141cc406Sopenharmony_ci { 473141cc406Sopenharmony_ci#if defined (M1015_LOG_LL) || defined (M1015_LOG_HL) 474141cc406Sopenharmony_ci ++tries; 475141cc406Sopenharmony_ci#endif 476141cc406Sopenharmony_ci 477141cc406Sopenharmony_ci sanei_pa4s2_readbegin (dev->desc->fd, reg & 0x03); 478141cc406Sopenharmony_ci sanei_pa4s2_readbyte (dev->desc->fd, &tmp); 479141cc406Sopenharmony_ci sanei_pa4s2_readend (dev->desc->fd); 480141cc406Sopenharmony_ci 481141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 482141cc406Sopenharmony_ci sprintf(&hl_next_line[0], "%s wait_bit(%s, %s, %d): %s %s;\n", cis_indent, 483141cc406Sopenharmony_ci Mustek_PP_1015_reg_r_name(reg), Mustek_PP_1015_bit_name(bit), 484141cc406Sopenharmony_ci on?1:0, Mustek_PP_1015_show_val(mask), Mustek_PP_1015_show_val(tmp)); 485141cc406Sopenharmony_ci M1015_FLUSH_HL; 486141cc406Sopenharmony_ci#endif 487141cc406Sopenharmony_ci val = ((on == SANE_TRUE) ? tmp : ~tmp ) & mask; 488141cc406Sopenharmony_ci 489141cc406Sopenharmony_ci if (val != 0) break; 490141cc406Sopenharmony_ci 491141cc406Sopenharmony_ci if (period) usleep(period); 492141cc406Sopenharmony_ci 493141cc406Sopenharmony_ci if (tries > 50000) 494141cc406Sopenharmony_ci { 495141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 496141cc406Sopenharmony_ci sprintf(&hl_next_line[0], "%s wait_bit(%s, %s, %d): failed;\n", cis_indent, 497141cc406Sopenharmony_ci Mustek_PP_1015_reg_r_name(reg), Mustek_PP_1015_bit_name(bit), on?1:0); 498141cc406Sopenharmony_ci M1015_FLUSH_HL; 499141cc406Sopenharmony_ci#endif 500141cc406Sopenharmony_ci DBG(2, "Mustek_PP_1015_wait_bit: failed (reg %d, bit %d, on: %d)\n", 501141cc406Sopenharmony_ci reg, bit, on?1:0); 502141cc406Sopenharmony_ci return SANE_FALSE; 503141cc406Sopenharmony_ci } 504141cc406Sopenharmony_ci } 505141cc406Sopenharmony_ci 506141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 507141cc406Sopenharmony_ci sprintf(&hl_next_line[0], "%s wait_bit(%s, %s, %d);\n", cis_indent, 508141cc406Sopenharmony_ci Mustek_PP_1015_reg_r_name(reg), Mustek_PP_1015_bit_name(bit), on?1:0); 509141cc406Sopenharmony_ci M1015_FLUSH_HL; 510141cc406Sopenharmony_ci#endif 511141cc406Sopenharmony_ci#ifdef M1015_LOG_LL 512141cc406Sopenharmony_ci fprintf(M1015_LOG_1, "\tread_reg(%s, %d);\n", Mustek_PP_1015_reg_r_name(reg), 513141cc406Sopenharmony_ci tries); 514141cc406Sopenharmony_ci#endif 515141cc406Sopenharmony_ci 516141cc406Sopenharmony_ci#ifdef M1015_TRACE_REGS 517141cc406Sopenharmony_ci dev->CIS.regs.in_regs[reg & 0x03] = tmp; 518141cc406Sopenharmony_ci#endif 519141cc406Sopenharmony_ci return dev->desc->state != STATE_CANCELLED ? SANE_TRUE : SANE_FALSE; 520141cc406Sopenharmony_ci} 521141cc406Sopenharmony_ci 522141cc406Sopenharmony_ci/****************************************************************************** 523141cc406Sopenharmony_ci * 524141cc406Sopenharmony_ci * Writes one out of 4 registers of one of the 4 register banks (I guess) 525141cc406Sopenharmony_ci * 526141cc406Sopenharmony_ci * Bank 0 527141cc406Sopenharmony_ci * 0: voltage red --+ 528141cc406Sopenharmony_ci * 1: voltage green +-> always set to 0x96 529141cc406Sopenharmony_ci * 2: voltage blue --+ 530141cc406Sopenharmony_ci * 3: DPI control 531141cc406Sopenharmony_ci * 532141cc406Sopenharmony_ci * Bank 1 533141cc406Sopenharmony_ci * 0: line adjust (?) - high byte 534141cc406Sopenharmony_ci * 1: line adjust (?) - low byte 535141cc406Sopenharmony_ci * 2: unknown (values seen: 0x00, 0x02, 0x03, 0x1D) 536141cc406Sopenharmony_ci * 3: expose time (?) (values seen: 0xAA, 0xFD, 0xFE, 0xFF) 537141cc406Sopenharmony_ci * 538141cc406Sopenharmony_ci * Bank 2 539141cc406Sopenharmony_ci * 0: unknown, used to start linear sequence during calibration 540141cc406Sopenharmony_ci * 1: motor control code (forward, return home, ...) 541141cc406Sopenharmony_ci * 2: never used 542141cc406Sopenharmony_ci * 3: never used 543141cc406Sopenharmony_ci * 544141cc406Sopenharmony_ci * Bank 3 545141cc406Sopenharmony_ci * 0: reduction factor (16bit internal -> 8bit) -> target for calibration 546141cc406Sopenharmony_ci * 1: unknown -> always set to 0x05 547141cc406Sopenharmony_ci * 2: unknown -> always set to 0x00 548141cc406Sopenharmony_ci * 3: never used 549141cc406Sopenharmony_ci * 550141cc406Sopenharmony_ci *****************************************************************************/ 551141cc406Sopenharmony_ci 552141cc406Sopenharmony_cistatic void 553141cc406Sopenharmony_ciMustek_PP_1015_write_reg(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, SANE_Byte val) 554141cc406Sopenharmony_ci{ 555141cc406Sopenharmony_ci 556141cc406Sopenharmony_ci SANE_Byte regBank = (reg & 0xF0) >> 4; 557141cc406Sopenharmony_ci SANE_Byte regNo = (reg & 0x0F); 558141cc406Sopenharmony_ci 559141cc406Sopenharmony_ci assert (regNo <= 3); 560141cc406Sopenharmony_ci assert (regBank <= 3); 561141cc406Sopenharmony_ci 562141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (4+regNo))+ regBank); 563141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val); 564141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, regBank); 565141cc406Sopenharmony_ci 566141cc406Sopenharmony_ci#ifdef M1015_TRACE_REGS 567141cc406Sopenharmony_ci dev->CIS.regs.out_regs[regBank][regNo] = val; 568141cc406Sopenharmony_ci#endif 569141cc406Sopenharmony_ci 570141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 571141cc406Sopenharmony_ci sprintf(&hl_next_line[0], "%s write_reg(%s, 0x%02X);\n", cis_indent, 572141cc406Sopenharmony_ci Mustek_PP_1015_reg_w_name(reg), val); 573141cc406Sopenharmony_ci M1015_FLUSH_HL; 574141cc406Sopenharmony_ci#endif 575141cc406Sopenharmony_ci} 576141cc406Sopenharmony_ci 577141cc406Sopenharmony_ci/****************************************************************************** 578141cc406Sopenharmony_ci * 579141cc406Sopenharmony_ci * Writes 2 values to 2 adjecent registers. 580141cc406Sopenharmony_ci * It is probably equivalent to 2 simple write operations (but I'm not sure). 581141cc406Sopenharmony_ci * 582141cc406Sopenharmony_ci * val1 is written to register[regNo] 583141cc406Sopenharmony_ci * val2 is written to register[regNo+1] 584141cc406Sopenharmony_ci * 585141cc406Sopenharmony_ci *****************************************************************************/ 586141cc406Sopenharmony_cistatic void 587141cc406Sopenharmony_ciMustek_PP_1015_write_reg2(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, 588141cc406Sopenharmony_ci SANE_Byte val1, SANE_Byte val2) 589141cc406Sopenharmony_ci{ 590141cc406Sopenharmony_ci SANE_Byte regBank = (reg & 0xF0) >> 4; 591141cc406Sopenharmony_ci SANE_Byte regNo = (reg & 0x0F); 592141cc406Sopenharmony_ci 593141cc406Sopenharmony_ci assert (regNo <= 2); 594141cc406Sopenharmony_ci assert (regBank <= 3); 595141cc406Sopenharmony_ci 596141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (4+regNo))+ regBank); 597141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val1); 598141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (5+regNo))+ regBank); 599141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val2); 600141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, regBank); 601141cc406Sopenharmony_ci 602141cc406Sopenharmony_ci#ifdef M1015_TRACE_REGS 603141cc406Sopenharmony_ci dev->CIS.regs.out_regs[regBank][regNo] = val1; 604141cc406Sopenharmony_ci dev->CIS.regs.out_regs[regBank][regNo+1] = val2; 605141cc406Sopenharmony_ci#endif 606141cc406Sopenharmony_ci 607141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 608141cc406Sopenharmony_ci sprintf(&hl_next_line[0], "%s write_reg2(%s, 0x%02X, 0x%02X);\n", 609141cc406Sopenharmony_ci cis_indent, Mustek_PP_1015_reg_w_name(reg), val1, val2); 610141cc406Sopenharmony_ci M1015_FLUSH_HL; 611141cc406Sopenharmony_ci#endif 612141cc406Sopenharmony_ci} 613141cc406Sopenharmony_ci 614141cc406Sopenharmony_ci/****************************************************************************** 615141cc406Sopenharmony_ci * 616141cc406Sopenharmony_ci * Writes 3 values to 3 adjecent registers. 617141cc406Sopenharmony_ci * It is probably equivalent to 3 simple write operations (but I'm not sure). 618141cc406Sopenharmony_ci * 619141cc406Sopenharmony_ci * val1 is written to register[regNo] 620141cc406Sopenharmony_ci * val2 is written to register[regNo+1] 621141cc406Sopenharmony_ci * val3 is written to register[regNo+2] 622141cc406Sopenharmony_ci * 623141cc406Sopenharmony_ci *****************************************************************************/ 624141cc406Sopenharmony_cistatic void 625141cc406Sopenharmony_ciMustek_PP_1015_write_reg3(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, 626141cc406Sopenharmony_ci SANE_Byte val1, SANE_Byte val2, SANE_Byte val3) 627141cc406Sopenharmony_ci{ 628141cc406Sopenharmony_ci SANE_Byte regBank = (reg & 0xF0) >> 4; 629141cc406Sopenharmony_ci SANE_Byte regNo = (reg & 0x0F); 630141cc406Sopenharmony_ci 631141cc406Sopenharmony_ci assert (regNo <= 1); 632141cc406Sopenharmony_ci assert (regBank <= 3); 633141cc406Sopenharmony_ci 634141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (4+regNo))+ regBank); 635141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val1); 636141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (5+regNo))+ regBank); 637141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val2); 638141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (6+regNo))+ regBank); 639141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val3); 640141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, regBank); 641141cc406Sopenharmony_ci 642141cc406Sopenharmony_ci#ifdef M1015_TRACE_REGS 643141cc406Sopenharmony_ci dev->CIS.regs.out_regs[regBank][regNo ] = val1; 644141cc406Sopenharmony_ci dev->CIS.regs.out_regs[regBank][regNo+1] = val2; 645141cc406Sopenharmony_ci dev->CIS.regs.out_regs[regBank][regNo+2] = val3; 646141cc406Sopenharmony_ci#endif 647141cc406Sopenharmony_ci 648141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 649141cc406Sopenharmony_ci sprintf(&hl_next_line[0], "%s write_reg3(%s, 0x%02X, 0x%02X, 0x%02X);\n", 650141cc406Sopenharmony_ci cis_indent, Mustek_PP_1015_reg_w_name(reg), val1, val2, val3); 651141cc406Sopenharmony_ci M1015_FLUSH_HL; 652141cc406Sopenharmony_ci#endif 653141cc406Sopenharmony_ci} 654141cc406Sopenharmony_ci 655141cc406Sopenharmony_ci/****************************************************************************** 656141cc406Sopenharmony_ci * Opens a register for a (series of) write operation(s). 657141cc406Sopenharmony_ci *****************************************************************************/ 658141cc406Sopenharmony_cistatic void 659141cc406Sopenharmony_ciMustek_PP_1015_write_reg_start(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg) 660141cc406Sopenharmony_ci{ 661141cc406Sopenharmony_ci SANE_Byte regBank = (reg & 0xF0) >> 4; 662141cc406Sopenharmony_ci SANE_Byte regNo = (reg & 0x0F); 663141cc406Sopenharmony_ci 664141cc406Sopenharmony_ci assert (regNo <= 3); 665141cc406Sopenharmony_ci assert (regBank <= 3); 666141cc406Sopenharmony_ci 667141cc406Sopenharmony_ci dev->CIS.regs.current_write_reg = reg; 668141cc406Sopenharmony_ci 669141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 670141cc406Sopenharmony_ci dev->CIS.regs.write_count = 0; 671141cc406Sopenharmony_ci#endif 672141cc406Sopenharmony_ci 673141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (4+regNo))+ regBank); 674141cc406Sopenharmony_ci} 675141cc406Sopenharmony_ci 676141cc406Sopenharmony_ci/****************************************************************************** 677141cc406Sopenharmony_ci * Writes a value to the currently open register. 678141cc406Sopenharmony_ci *****************************************************************************/ 679141cc406Sopenharmony_cistatic void 680141cc406Sopenharmony_ciMustek_PP_1015_write_reg_val(Mustek_PP_CIS_dev * dev, SANE_Byte val) 681141cc406Sopenharmony_ci{ 682141cc406Sopenharmony_ci#ifdef M1015_TRACE_REGS 683141cc406Sopenharmony_ci SANE_Byte regBank = (dev->CIS.regs.current_write_reg & 0xF0) >> 4; 684141cc406Sopenharmony_ci SANE_Byte regNo = (dev->CIS.regs.current_write_reg & 0x0F); 685141cc406Sopenharmony_ci 686141cc406Sopenharmony_ci assert (regNo <= 3); 687141cc406Sopenharmony_ci assert (regBank <= 3); 688141cc406Sopenharmony_ci 689141cc406Sopenharmony_ci dev->CIS.regs.out_regs[regBank][regNo] = val; 690141cc406Sopenharmony_ci#endif 691141cc406Sopenharmony_ci 692141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val); 693141cc406Sopenharmony_ci 694141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 695141cc406Sopenharmony_ci ++dev->CIS.regs.write_count; 696141cc406Sopenharmony_ci#endif 697141cc406Sopenharmony_ci} 698141cc406Sopenharmony_ci 699141cc406Sopenharmony_ci/****************************************************************************** 700141cc406Sopenharmony_ci * Closes a register after a (series of) write operation(s). 701141cc406Sopenharmony_ci *****************************************************************************/ 702141cc406Sopenharmony_cistatic void 703141cc406Sopenharmony_ciMustek_PP_1015_write_reg_stop(Mustek_PP_CIS_dev * dev) 704141cc406Sopenharmony_ci{ 705141cc406Sopenharmony_ci SANE_Byte regBank = (dev->CIS.regs.current_write_reg & 0xF0) >> 4; 706141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 707141cc406Sopenharmony_ci SANE_Byte regNo = (dev->CIS.regs.current_write_reg & 0x0F); 708141cc406Sopenharmony_ci assert (regNo <= 3); 709141cc406Sopenharmony_ci 710141cc406Sopenharmony_ci sprintf(&hl_next_line[0], "%s write_reg_multi(%s, *%d);\n", cis_indent, 711141cc406Sopenharmony_ci Mustek_PP_1015_reg_w_name(dev->CIS.regs.current_write_reg), 712141cc406Sopenharmony_ci dev->CIS.regs.write_count); 713141cc406Sopenharmony_ci M1015_FLUSH_HL; 714141cc406Sopenharmony_ci#endif 715141cc406Sopenharmony_ci assert (regBank <= 3); 716141cc406Sopenharmony_ci 717141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, regBank); 718141cc406Sopenharmony_ci} 719141cc406Sopenharmony_ci 720141cc406Sopenharmony_ci/****************************************************************************** 721141cc406Sopenharmony_ci * 722141cc406Sopenharmony_ci * Sends a command to the scanner. The command should not access one of the 723141cc406Sopenharmony_ci * internal registers, ie., the 3rd bit should not be zero. 724141cc406Sopenharmony_ci * 725141cc406Sopenharmony_ci *****************************************************************************/ 726141cc406Sopenharmony_cistatic void 727141cc406Sopenharmony_ciMustek_PP_1015_send_command(Mustek_PP_CIS_dev * dev, SANE_Byte command) 728141cc406Sopenharmony_ci{ 729141cc406Sopenharmony_ci assert (command & 0x04); 730141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, command); 731141cc406Sopenharmony_ci 732141cc406Sopenharmony_ci#ifdef M1015_LOG_HL 733141cc406Sopenharmony_ci sprintf(&hl_next_line[0], "%s send_command(0x%02X);\n", cis_indent, command); 734141cc406Sopenharmony_ci M1015_FLUSH_HL; 735141cc406Sopenharmony_ci#endif 736141cc406Sopenharmony_ci} 737141cc406Sopenharmony_ci 738141cc406Sopenharmony_ci/****************************************************************************** 739141cc406Sopenharmony_ci ############################################################################## 740141cc406Sopenharmony_ci ## CIS driver ## 741141cc406Sopenharmony_ci ############################################################################## 742141cc406Sopenharmony_ci *****************************************************************************/ 743141cc406Sopenharmony_ci 744141cc406Sopenharmony_ci/****************************************************************************** 745141cc406Sopenharmony_ci * Resolution conversion functions 746141cc406Sopenharmony_ci *****************************************************************************/ 747141cc406Sopenharmony_cistatic int 748141cc406Sopenharmony_cimax2hw_hres(Mustek_PP_CIS_dev *dev, int dist) 749141cc406Sopenharmony_ci{ 750141cc406Sopenharmony_ci return (int)((dist * dev->CIS.hw_hres) / dev->desc->dev->maxres + 0.5); 751141cc406Sopenharmony_ci} 752141cc406Sopenharmony_ci 753141cc406Sopenharmony_ci#ifdef NOT_USED 754141cc406Sopenharmony_cistatic int 755141cc406Sopenharmony_cimax2hw_vres(Mustek_PP_CIS_dev *dev, int dist) 756141cc406Sopenharmony_ci{ 757141cc406Sopenharmony_ci return (int)((dist * dev->CIS.hw_vres) / dev->desc->dev->maxres + 0.5); 758141cc406Sopenharmony_ci} 759141cc406Sopenharmony_ci#endif 760141cc406Sopenharmony_ci 761141cc406Sopenharmony_cistatic int 762141cc406Sopenharmony_cimax2cis_hres(Mustek_PP_CIS_dev *dev, int dist) 763141cc406Sopenharmony_ci{ 764141cc406Sopenharmony_ci return (int)((dist * dev->CIS.cisRes) / dev->desc->dev->maxres + 0.5); 765141cc406Sopenharmony_ci} 766141cc406Sopenharmony_ci 767141cc406Sopenharmony_cistatic int 768141cc406Sopenharmony_cicis2max_res(Mustek_PP_CIS_dev *dev, int dist) 769141cc406Sopenharmony_ci{ 770141cc406Sopenharmony_ci return (int)((dist * dev->desc->dev->maxres) / dev->CIS.cisRes + 0.5); 771141cc406Sopenharmony_ci} 772141cc406Sopenharmony_ci 773141cc406Sopenharmony_ci#ifdef NOT_USED 774141cc406Sopenharmony_cistatic int 775141cc406Sopenharmony_cihw2max_vres(Mustek_PP_CIS_dev *dev, int dist) 776141cc406Sopenharmony_ci{ 777141cc406Sopenharmony_ci return (int)((dist * dev->desc->dev->maxres) / dev->CIS.hw_vres + 0.5); 778141cc406Sopenharmony_ci} 779141cc406Sopenharmony_ci#endif 780141cc406Sopenharmony_ci 781141cc406Sopenharmony_ci/****************************************************************************** 782141cc406Sopenharmony_ci * Attempts to extract the current bank no. 783141cc406Sopenharmony_ci *****************************************************************************/ 784141cc406Sopenharmony_cistatic void 785141cc406Sopenharmony_cicis_get_bank_count(Mustek_PP_CIS_dev *dev) 786141cc406Sopenharmony_ci{ 787141cc406Sopenharmony_ci dev->bank_count = (Mustek_PP_1015_read_reg(dev, MA1015R_BANK_COUNT) & 0x7); 788141cc406Sopenharmony_ci if (dev->CIS.use8KBank) dev->bank_count >>= 1; 789141cc406Sopenharmony_ci} 790141cc406Sopenharmony_ci 791141cc406Sopenharmony_ci/****************************************************************************** 792141cc406Sopenharmony_ci * Triggers a bank switch (I assume). 793141cc406Sopenharmony_ci *****************************************************************************/ 794141cc406Sopenharmony_cistatic void 795141cc406Sopenharmony_cicis_set_sti(Mustek_PP_CIS_dev *dev) 796141cc406Sopenharmony_ci{ 797141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE(dev->desc->fd, 3, 0xFF); 798141cc406Sopenharmony_ci dev->bank_count++; 799141cc406Sopenharmony_ci dev->bank_count &= (dev->CIS.use8KBank == SANE_TRUE) ? 3 : 7; 800141cc406Sopenharmony_ci} 801141cc406Sopenharmony_ci 802141cc406Sopenharmony_ci/****************************************************************************** 803141cc406Sopenharmony_ci * Wait till the bank with a given number becomes available. 804141cc406Sopenharmony_ci *****************************************************************************/ 805141cc406Sopenharmony_cistatic SANE_Bool 806141cc406Sopenharmony_cicis_wait_bank_change (Mustek_PP_CIS_dev * dev, int bankcount) 807141cc406Sopenharmony_ci{ 808141cc406Sopenharmony_ci struct timeval start, end; 809141cc406Sopenharmony_ci unsigned long diff; 810141cc406Sopenharmony_ci int firsttime = 1; 811141cc406Sopenharmony_ci 812141cc406Sopenharmony_ci gettimeofday (&start, NULL); 813141cc406Sopenharmony_ci 814141cc406Sopenharmony_ci do 815141cc406Sopenharmony_ci { 816141cc406Sopenharmony_ci if (1 /*niceload*/) 817141cc406Sopenharmony_ci { 818141cc406Sopenharmony_ci if (firsttime) 819141cc406Sopenharmony_ci firsttime = 0; 820141cc406Sopenharmony_ci else 821141cc406Sopenharmony_ci usleep (10); /* for a little nicer load */ 822141cc406Sopenharmony_ci } 823141cc406Sopenharmony_ci cis_get_bank_count (dev); 824141cc406Sopenharmony_ci 825141cc406Sopenharmony_ci gettimeofday (&end, NULL); 826141cc406Sopenharmony_ci diff = (end.tv_sec * 1000 + end.tv_usec / 1000) - 827141cc406Sopenharmony_ci (start.tv_sec * 1000 + start.tv_usec / 1000); 828141cc406Sopenharmony_ci 829141cc406Sopenharmony_ci } 830141cc406Sopenharmony_ci while ((dev->bank_count != bankcount) && (diff < MUSTEK_PP_CIS_WAIT_BANK)); 831141cc406Sopenharmony_ci 832141cc406Sopenharmony_ci if (dev->bank_count != bankcount && dev->desc->state != STATE_CANCELLED) 833141cc406Sopenharmony_ci { 834141cc406Sopenharmony_ci u_char tmp; 835141cc406Sopenharmony_ci tmp = Mustek_PP_1015_read_reg(dev, 3); 836141cc406Sopenharmony_ci DBG(2, "cis_wait_bank_change: Missed a bank: got %d [%s], " 837141cc406Sopenharmony_ci "wanted %d, waited %d msec\n", 838141cc406Sopenharmony_ci dev->bank_count, Mustek_PP_1015_show_val(tmp), bankcount, 839141cc406Sopenharmony_ci MUSTEK_PP_CIS_WAIT_BANK); 840141cc406Sopenharmony_ci } 841141cc406Sopenharmony_ci 842141cc406Sopenharmony_ci return dev->bank_count == bankcount ? SANE_TRUE : SANE_FALSE; 843141cc406Sopenharmony_ci} 844141cc406Sopenharmony_ci 845141cc406Sopenharmony_ci/****************************************************************************** 846141cc406Sopenharmony_ci * Configure the CIS for a given resolution. 847141cc406Sopenharmony_ci * 848141cc406Sopenharmony_ci * CIS scanners seem to have 2 modes: 849141cc406Sopenharmony_ci * 850141cc406Sopenharmony_ci * low resolution (50-300 DPI) and 851141cc406Sopenharmony_ci * high resolution (300-600 DPI). 852141cc406Sopenharmony_ci * 853141cc406Sopenharmony_ci * Depending on the resolution requested by the user, the scanner is used 854141cc406Sopenharmony_ci * in high or low resolution mode. In high resolution mode, the motor step 855141cc406Sopenharmony_ci * sizes are also reduced by a factor of two. 856141cc406Sopenharmony_ci * 857141cc406Sopenharmony_ci *****************************************************************************/ 858141cc406Sopenharmony_cistatic void 859141cc406Sopenharmony_cicis_set_dpi_value (Mustek_PP_CIS_dev * dev) 860141cc406Sopenharmony_ci{ 861141cc406Sopenharmony_ci u_char val = 0; 862141cc406Sopenharmony_ci 863141cc406Sopenharmony_ci if (dev->model == MUSTEK_PP_CIS1200PLUS) 864141cc406Sopenharmony_ci { 865141cc406Sopenharmony_ci /* Toshiba CIS: only 600 DPI + decimation */ 866141cc406Sopenharmony_ci switch (dev->CIS.hw_hres) 867141cc406Sopenharmony_ci { 868141cc406Sopenharmony_ci case 75: 869141cc406Sopenharmony_ci val = 0x48; /* 1/8 */ 870141cc406Sopenharmony_ci break; 871141cc406Sopenharmony_ci case 100: 872141cc406Sopenharmony_ci val = 0x08; /* 1/6 */ 873141cc406Sopenharmony_ci break; 874141cc406Sopenharmony_ci case 200: 875141cc406Sopenharmony_ci val = 0x00; /* 1/3 */ 876141cc406Sopenharmony_ci break; 877141cc406Sopenharmony_ci case 300: 878141cc406Sopenharmony_ci val = 0x50; /* 2/4 */ 879141cc406Sopenharmony_ci break; 880141cc406Sopenharmony_ci case 400: 881141cc406Sopenharmony_ci val = 0x10; /* 2/3 */ 882141cc406Sopenharmony_ci break; 883141cc406Sopenharmony_ci case 600: 884141cc406Sopenharmony_ci val = 0x20; /* 3/3 */ 885141cc406Sopenharmony_ci break; 886141cc406Sopenharmony_ci default: 887141cc406Sopenharmony_ci assert (0); 888141cc406Sopenharmony_ci } 889141cc406Sopenharmony_ci } 890141cc406Sopenharmony_ci else 891141cc406Sopenharmony_ci { 892141cc406Sopenharmony_ci /* Canon CIS: sensor can use 300 or 600 DPI */ 893141cc406Sopenharmony_ci switch (dev->CIS.hw_hres) 894141cc406Sopenharmony_ci { 895141cc406Sopenharmony_ci case 50: 896141cc406Sopenharmony_ci val = 0x08; /* 1/6 */ 897141cc406Sopenharmony_ci break; 898141cc406Sopenharmony_ci case 100: 899141cc406Sopenharmony_ci val = 0x00; /* 1/3 */ 900141cc406Sopenharmony_ci break; 901141cc406Sopenharmony_ci case 200: 902141cc406Sopenharmony_ci val = 0x10; /* 2/3 */ 903141cc406Sopenharmony_ci break; 904141cc406Sopenharmony_ci case 300: 905141cc406Sopenharmony_ci val = 0x20; /* 3/3 */ 906141cc406Sopenharmony_ci break; 907141cc406Sopenharmony_ci case 400: 908141cc406Sopenharmony_ci val = 0x10; /* 2/3 */ 909141cc406Sopenharmony_ci break; 910141cc406Sopenharmony_ci case 600: 911141cc406Sopenharmony_ci val = 0x20; /* 3/3 */ 912141cc406Sopenharmony_ci break; 913141cc406Sopenharmony_ci default: 914141cc406Sopenharmony_ci assert (0); 915141cc406Sopenharmony_ci } 916141cc406Sopenharmony_ci } 917141cc406Sopenharmony_ci 918141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_DPI_CONTROL, val | 0x04); 919141cc406Sopenharmony_ci 920141cc406Sopenharmony_ci DBG (4, "cis_set_dpi_value: dpi: %d -> value 0x%02x\n", dev->CIS.hw_hres, val); 921141cc406Sopenharmony_ci} 922141cc406Sopenharmony_ci 923141cc406Sopenharmony_cistatic void 924141cc406Sopenharmony_cicis_set_ccd_channel (Mustek_PP_CIS_dev * dev) 925141cc406Sopenharmony_ci{ 926141cc406Sopenharmony_ci 927141cc406Sopenharmony_ci SANE_Byte codes[] = { 0x84, 0x44, 0xC4 }; 928141cc406Sopenharmony_ci SANE_Byte chancode; 929141cc406Sopenharmony_ci 930141cc406Sopenharmony_ci assert (dev->CIS.channel < 3); 931141cc406Sopenharmony_ci 932141cc406Sopenharmony_ci chancode = codes[dev->CIS.channel]; 933141cc406Sopenharmony_ci 934141cc406Sopenharmony_ci /* 935141cc406Sopenharmony_ci The TWAIN driver sets an extra bit in lineart mode. 936141cc406Sopenharmony_ci When I do this too, I don't see any effect on the image. 937141cc406Sopenharmony_ci Moreover, for 1 resolution, namely 400 dpi, the bank counter seems 938141cc406Sopenharmony_ci to behave strangely, and the synchronization get completely lost. 939141cc406Sopenharmony_ci I guess the software conversion from gray to lineart is good enough, 940141cc406Sopenharmony_ci so I'll leave it like that. 941141cc406Sopenharmony_ci 942141cc406Sopenharmony_ci if (dev->CIS.setParameters) 943141cc406Sopenharmony_ci { 944141cc406Sopenharmony_ci chancode |= (dev->desc->mode == MODE_BW) ? 0x20: 0; 945141cc406Sopenharmony_ci } 946141cc406Sopenharmony_ci */ 947141cc406Sopenharmony_ci 948141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, chancode); 949141cc406Sopenharmony_ci 950141cc406Sopenharmony_ci#ifdef M1015_TRACE_REGS 951141cc406Sopenharmony_ci dev->CIS.regs.channel = chancode; 952141cc406Sopenharmony_ci#endif 953141cc406Sopenharmony_ci} 954141cc406Sopenharmony_ci 955141cc406Sopenharmony_cistatic void 956141cc406Sopenharmony_cicis_config_ccd (Mustek_PP_CIS_dev * dev) 957141cc406Sopenharmony_ci{ 958141cc406Sopenharmony_ci SANE_Int skipCount, byteCount; 959141cc406Sopenharmony_ci 960141cc406Sopenharmony_ci if (dev->CIS.res != 0) 961141cc406Sopenharmony_ci dev->CIS.hres_step = 962141cc406Sopenharmony_ci SANE_FIX ((float) dev->CIS.hw_hres / (float) dev->CIS.res); 963141cc406Sopenharmony_ci 964141cc406Sopenharmony_ci /* CIS: <= 300 dpi -> 0x86 965141cc406Sopenharmony_ci > 300 dpi -> 0x96 */ 966141cc406Sopenharmony_ci 967141cc406Sopenharmony_ci if (dev->CIS.cisRes == 600) 968141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, 0x96); 969141cc406Sopenharmony_ci else 970141cc406Sopenharmony_ci SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, 0x86); 971141cc406Sopenharmony_ci 972141cc406Sopenharmony_ci cis_set_dpi_value(dev); 973141cc406Sopenharmony_ci 974141cc406Sopenharmony_ci if (dev->CIS.setParameters) 975141cc406Sopenharmony_ci { 976141cc406Sopenharmony_ci dev->CIS.channel = dev->desc->mode == MODE_COLOR ? 977141cc406Sopenharmony_ci MUSTEK_PP_CIS_CHANNEL_RED : MUSTEK_PP_CIS_CHANNEL_GRAY; 978141cc406Sopenharmony_ci } 979141cc406Sopenharmony_ci else 980141cc406Sopenharmony_ci { 981141cc406Sopenharmony_ci dev->CIS.channel = MUSTEK_PP_CIS_CHANNEL_GRAY; 982141cc406Sopenharmony_ci } 983141cc406Sopenharmony_ci 984141cc406Sopenharmony_ci cis_set_ccd_channel (dev); 985141cc406Sopenharmony_ci 986141cc406Sopenharmony_ci Mustek_PP_1015_write_reg (dev, MA1015W_POWER_ON_DELAY, 0xAA); 987141cc406Sopenharmony_ci Mustek_PP_1015_write_reg (dev, MA1015W_CCD_TIMING, 0x05); 988141cc406Sopenharmony_ci Mustek_PP_1015_write_reg (dev, MA1015W_CCD_TIMING_ADJ, 0x00); 989141cc406Sopenharmony_ci 990141cc406Sopenharmony_ci Mustek_PP_1015_send_command (dev, 0x45); /* or 0x05 for no 8kbank */ 991141cc406Sopenharmony_ci 992141cc406Sopenharmony_ci /* 993141cc406Sopenharmony_ci * Unknown sequence. 994141cc406Sopenharmony_ci * Seems to be always the same during configuration, independent of the 995141cc406Sopenharmony_ci * mode and the resolution. 996141cc406Sopenharmony_ci */ 997141cc406Sopenharmony_ci CIS_CLEAR_FULLFLAG(dev); 998141cc406Sopenharmony_ci CIS_INC_READ(dev); 999141cc406Sopenharmony_ci CIS_CLEAR_READ_BANK(dev); 1000141cc406Sopenharmony_ci CIS_CLEAR_WRITE_ADDR(dev); 1001141cc406Sopenharmony_ci CIS_CLEAR_WRITE_BANK(dev); 1002141cc406Sopenharmony_ci CIS_CLEAR_TOGGLE(dev); 1003141cc406Sopenharmony_ci 1004141cc406Sopenharmony_ci /* 1005141cc406Sopenharmony_ci # SkipImage = expressed in max resolution (600 DPI) 1006141cc406Sopenharmony_ci # 1007141cc406Sopenharmony_ci # Formulas 1008141cc406Sopenharmony_ci # 1009141cc406Sopenharmony_ci # <= 300 DPI: 1010141cc406Sopenharmony_ci # 1011141cc406Sopenharmony_ci # Skip = 67 + skipimage/2 1012141cc406Sopenharmony_ci # 1013141cc406Sopenharmony_ci # Skip1 = Skip / 32 1014141cc406Sopenharmony_ci # Skip2 = Skip % 32 1015141cc406Sopenharmony_ci # 1016141cc406Sopenharmony_ci # Bytes = Skip2 * hw_hres/300 + (imagebytes * hw_hres/res) + 2 1017141cc406Sopenharmony_ci # 1018141cc406Sopenharmony_ci # > 300 DPI 1019141cc406Sopenharmony_ci # 1020141cc406Sopenharmony_ci # Skip = 67 + skipimage 1021141cc406Sopenharmony_ci # 1022141cc406Sopenharmony_ci # Skip1 = Skip / 32 1023141cc406Sopenharmony_ci # Skip2 = Skip % 32 1024141cc406Sopenharmony_ci # 1025141cc406Sopenharmony_ci # Bytes = Skip2*hw_hres/600 + (imagebytes * hw_hres/res) + 2 1026141cc406Sopenharmony_ci # 1027141cc406Sopenharmony_ci */ 1028141cc406Sopenharmony_ci 1029141cc406Sopenharmony_ci skipCount = 67; /* Hardware parameter - fixed */ 1030141cc406Sopenharmony_ci 1031141cc406Sopenharmony_ci if (dev->CIS.setParameters == SANE_TRUE) 1032141cc406Sopenharmony_ci { 1033141cc406Sopenharmony_ci /* 1034141cc406Sopenharmony_ci * It seems that the TWAIN driver always adds 2 mm extra. When I do the 1035141cc406Sopenharmony_ci * inverse calculation from the parameters that driver sends, I always 1036141cc406Sopenharmony_ci * get a difference of exactly 2mm, at every resolution and for 1037141cc406Sopenharmony_ci * different positions of the scan area. Moreover, when I don't add this 1038141cc406Sopenharmony_ci * offset, the resulting scan seems to start 2mm to soon. 1039141cc406Sopenharmony_ci * I can't find this back in the backend of the TWAIN driver, but I 1040141cc406Sopenharmony_ci * assume that this 2mm offset is taken care off at the higher levels. 1041141cc406Sopenharmony_ci */ 1042141cc406Sopenharmony_ci DBG(4, "cis_config_ccd: Skip count: %d\n", skipCount); 1043141cc406Sopenharmony_ci skipCount += max2cis_hres(dev, dev->CIS.skipimagebytes); 1044141cc406Sopenharmony_ci DBG(4, "cis_config_ccd: Skip count: %d (cis res: %d)\n", skipCount, 1045141cc406Sopenharmony_ci dev->CIS.cisRes); 1046141cc406Sopenharmony_ci skipCount += (int)(2.0/25.4*dev->CIS.cisRes); 1047141cc406Sopenharmony_ci DBG(4, "cis_config_ccd: Skip count: %d\n", skipCount); 1048141cc406Sopenharmony_ci 1049141cc406Sopenharmony_ci Mustek_PP_1015_write_reg (dev, MA1015W_SKIP_COUNT, skipCount / 32); 1050141cc406Sopenharmony_ci DBG(4, "cis_config_ccd: Skip count: %d (x32)\n", skipCount / 32); 1051141cc406Sopenharmony_ci } 1052141cc406Sopenharmony_ci else 1053141cc406Sopenharmony_ci { 1054141cc406Sopenharmony_ci Mustek_PP_1015_write_reg (dev, MA1015W_SKIP_COUNT, 0); 1055141cc406Sopenharmony_ci DBG(4, "cis_config_ccd: Skip count: 67 (x32)\n"); 1056141cc406Sopenharmony_ci } 1057141cc406Sopenharmony_ci 1058141cc406Sopenharmony_ci skipCount %= 32; 1059141cc406Sopenharmony_ci skipCount = cis2max_res(dev, skipCount); /* Back to max res */ 1060141cc406Sopenharmony_ci 1061141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_EXPOSE_TIME, dev->CIS.exposeTime); 1062141cc406Sopenharmony_ci 1063141cc406Sopenharmony_ci DBG(4, "cis_config_ccd: skipcount: %d imagebytes: %d\n", skipCount, dev->CIS.imagebytes); 1064141cc406Sopenharmony_ci /* set_initial_skip_1015 (dev); */ 1065141cc406Sopenharmony_ci if (dev->CIS.setParameters == SANE_TRUE) 1066141cc406Sopenharmony_ci { 1067141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_EXPOSE_TIME, dev->CIS.exposeTime); 1068141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_POWER_ON_DELAY, 0xAA); 1069141cc406Sopenharmony_ci /* The TWAIN drivers always sends the same value: 0x96 */ 1070141cc406Sopenharmony_ci Mustek_PP_1015_write_reg3(dev, MA1015W_RED_REF, 0x96, 0x96, 0x96); 1071141cc406Sopenharmony_ci dev->CIS.adjustskip = max2hw_hres(dev, skipCount); 1072141cc406Sopenharmony_ci byteCount = max2hw_hres(dev, skipCount + dev->CIS.imagebytes) + 2; 1073141cc406Sopenharmony_ci dev->CIS.setParameters = SANE_FALSE; 1074141cc406Sopenharmony_ci } 1075141cc406Sopenharmony_ci else 1076141cc406Sopenharmony_ci { 1077141cc406Sopenharmony_ci dev->CIS.adjustskip = 0; 1078141cc406Sopenharmony_ci byteCount = max2hw_hres(dev, skipCount); 1079141cc406Sopenharmony_ci } 1080141cc406Sopenharmony_ci DBG(4, "cis_config_ccd: adjust skip: %d bytecount: %d\n", 1081141cc406Sopenharmony_ci dev->CIS.adjustskip, byteCount); 1082141cc406Sopenharmony_ci 1083141cc406Sopenharmony_ci Mustek_PP_1015_write_reg2(dev, MA1015W_BYTE_COUNT_HB, 1084141cc406Sopenharmony_ci byteCount >> 8, byteCount & 0xFF); 1085141cc406Sopenharmony_ci 1086141cc406Sopenharmony_ci cis_get_bank_count (dev); 1087141cc406Sopenharmony_ci DBG(5, "cis_config_ccd: done\n"); 1088141cc406Sopenharmony_ci} 1089141cc406Sopenharmony_ci 1090141cc406Sopenharmony_cistatic SANE_Bool 1091141cc406Sopenharmony_cicis_wait_motor_stable (Mustek_PP_CIS_dev * dev) 1092141cc406Sopenharmony_ci{ 1093141cc406Sopenharmony_ci static struct timeval timeoutVal; 1094141cc406Sopenharmony_ci SANE_Bool ret = 1095141cc406Sopenharmony_ci Mustek_PP_1015_wait_bit (dev, MA1015R_MOTOR, MA1015B_MOTOR_STABLE, 1096141cc406Sopenharmony_ci SANE_FALSE, 0); 1097141cc406Sopenharmony_ci#ifdef HAVE_SYS_SELECT_H 1098141cc406Sopenharmony_ci if (dev->engine_delay > 0) 1099141cc406Sopenharmony_ci { 1100141cc406Sopenharmony_ci timeoutVal.tv_sec = 0; 1101141cc406Sopenharmony_ci timeoutVal.tv_usec = dev->engine_delay*1000; 1102141cc406Sopenharmony_ci select(0, NULL, NULL, NULL, &timeoutVal); 1103141cc406Sopenharmony_ci } 1104141cc406Sopenharmony_ci#endif 1105141cc406Sopenharmony_ci return ret; 1106141cc406Sopenharmony_ci} 1107141cc406Sopenharmony_ci 1108141cc406Sopenharmony_cistatic void 1109141cc406Sopenharmony_cicis_motor_forward (Mustek_PP_CIS_dev * dev) 1110141cc406Sopenharmony_ci{ 1111141cc406Sopenharmony_ci SANE_Byte control; 1112141cc406Sopenharmony_ci 1113141cc406Sopenharmony_ci if (dev->model == MUSTEK_PP_CIS600) 1114141cc406Sopenharmony_ci { 1115141cc406Sopenharmony_ci switch (dev->CIS.hw_vres) 1116141cc406Sopenharmony_ci { 1117141cc406Sopenharmony_ci case 150: 1118141cc406Sopenharmony_ci control = 0x7B; 1119141cc406Sopenharmony_ci break; 1120141cc406Sopenharmony_ci case 300: 1121141cc406Sopenharmony_ci control = 0x73; 1122141cc406Sopenharmony_ci break; 1123141cc406Sopenharmony_ci case 600: 1124141cc406Sopenharmony_ci control = 0x13; 1125141cc406Sopenharmony_ci break; 1126141cc406Sopenharmony_ci default: 1127141cc406Sopenharmony_ci exit(1); 1128141cc406Sopenharmony_ci } 1129141cc406Sopenharmony_ci } 1130141cc406Sopenharmony_ci else 1131141cc406Sopenharmony_ci { 1132141cc406Sopenharmony_ci switch (dev->CIS.hw_vres) 1133141cc406Sopenharmony_ci { 1134141cc406Sopenharmony_ci case 300: 1135141cc406Sopenharmony_ci control = 0x7B; 1136141cc406Sopenharmony_ci break; 1137141cc406Sopenharmony_ci case 600: 1138141cc406Sopenharmony_ci control = 0x73; 1139141cc406Sopenharmony_ci break; 1140141cc406Sopenharmony_ci case 1200: 1141141cc406Sopenharmony_ci control = 0x13; 1142141cc406Sopenharmony_ci break; 1143141cc406Sopenharmony_ci default: 1144141cc406Sopenharmony_ci exit(1); 1145141cc406Sopenharmony_ci } 1146141cc406Sopenharmony_ci } 1147141cc406Sopenharmony_ci 1148141cc406Sopenharmony_ci#if MUSTEK_PP_CIS_MOTOR_REVERSE == 1 1149141cc406Sopenharmony_ci control ^= 0x10; 1150141cc406Sopenharmony_ci#endif 1151141cc406Sopenharmony_ci 1152141cc406Sopenharmony_ci DBG(4, "cis_motor_forward: @%d dpi: 0x%02X.\n", dev->CIS.hw_vres, control); 1153141cc406Sopenharmony_ci if (!cis_wait_motor_stable (dev)) 1154141cc406Sopenharmony_ci return; 1155141cc406Sopenharmony_ci 1156141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_MOTOR_CONTROL, control); 1157141cc406Sopenharmony_ci} 1158141cc406Sopenharmony_ci 1159141cc406Sopenharmony_cistatic void 1160141cc406Sopenharmony_cicis_move_motor (Mustek_PP_CIS_dev * dev, SANE_Int steps) /* steps @ maxres */ 1161141cc406Sopenharmony_ci{ 1162141cc406Sopenharmony_ci /* Note: steps is expressed at maximum resolution */ 1163141cc406Sopenharmony_ci SANE_Byte fullStep = 0x13, biStep = 0x73, quadStep = 0x7B; 1164141cc406Sopenharmony_ci SANE_Int fullSteps, biSteps, quadSteps; 1165141cc406Sopenharmony_ci /* 1166141cc406Sopenharmony_ci * During a multi-step feed, the expose time is fixed. The value depends 1167141cc406Sopenharmony_ci * on the type of the motor (600/1200 CP) 1168141cc406Sopenharmony_ci */ 1169141cc406Sopenharmony_ci SANE_Byte savedExposeTime = dev->CIS.exposeTime; 1170141cc406Sopenharmony_ci dev->CIS.exposeTime = 85; 1171141cc406Sopenharmony_ci 1172141cc406Sopenharmony_ci DBG(4, "cis_move_motor: Moving motor %d steps.\n", steps); 1173141cc406Sopenharmony_ci 1174141cc406Sopenharmony_ci /* Just in case ... */ 1175141cc406Sopenharmony_ci if (steps < 0) 1176141cc406Sopenharmony_ci { 1177141cc406Sopenharmony_ci DBG(1, "cis_move_motor: trying to move negative steps: %d\n", steps); 1178141cc406Sopenharmony_ci steps = 0; /* We must go through the configuration procedure */ 1179141cc406Sopenharmony_ci } 1180141cc406Sopenharmony_ci 1181141cc406Sopenharmony_ci /* 1182141cc406Sopenharmony_ci * Using the parameter settings for the 600 CP on a 1200 CP scanner 1183141cc406Sopenharmony_ci * doesn't work: the engine doesn't move and makes a sharp noise, which 1184141cc406Sopenharmony_ci * doesn't sound too healthy. It could be harmful to the motor ! 1185141cc406Sopenharmony_ci * Apparently, the same happens on a real 600 CP (reported by Disma 1186141cc406Sopenharmony_ci * Goggia), so it's probably better to always use the 1200 CP settings. 1187141cc406Sopenharmony_ci */ 1188141cc406Sopenharmony_ci dev->CIS.exposeTime <<= 1; 1189141cc406Sopenharmony_ci cis_config_ccd(dev); 1190141cc406Sopenharmony_ci dev->CIS.exposeTime = savedExposeTime; 1191141cc406Sopenharmony_ci 1192141cc406Sopenharmony_ci /* 1193141cc406Sopenharmony_ci * This is a minor speed optimization: when we are using the high 1194141cc406Sopenharmony_ci * resolution mode, long feeds (eg, to move to a scan area at the bottom 1195141cc406Sopenharmony_ci * of the page) can be made almost twice as fast by using double motor 1196141cc406Sopenharmony_ci * steps as much as possible. 1197141cc406Sopenharmony_ci * It is possible, though, that fast skipping (which is the default) is 1198141cc406Sopenharmony_ci * not very accurate on some scanners. Therefore, the user can disable 1199141cc406Sopenharmony_ci * this through the configuration file. 1200141cc406Sopenharmony_ci */ 1201141cc406Sopenharmony_ci 1202141cc406Sopenharmony_ci fullSteps = steps & 1; 1203141cc406Sopenharmony_ci biSteps = steps >> 1; 1204141cc406Sopenharmony_ci if (dev->fast_skip) { 1205141cc406Sopenharmony_ci quadSteps = biSteps >> 1; 1206141cc406Sopenharmony_ci biSteps &= 1; 1207141cc406Sopenharmony_ci } 1208141cc406Sopenharmony_ci else { 1209141cc406Sopenharmony_ci quadSteps = 0; 1210141cc406Sopenharmony_ci } 1211141cc406Sopenharmony_ci 1212141cc406Sopenharmony_ci M1015_DISPLAY_REGS(dev, "Before move"); 1213141cc406Sopenharmony_ci 1214141cc406Sopenharmony_ci#if MUSTEK_PP_CIS_MOTOR_REVERSE == 1 1215141cc406Sopenharmony_ci fullStep ^= 0x10; 1216141cc406Sopenharmony_ci biStep ^= 0x10; 1217141cc406Sopenharmony_ci quadStep ^= 0x10; 1218141cc406Sopenharmony_ci#endif 1219141cc406Sopenharmony_ci 1220141cc406Sopenharmony_ci DBG(4, "cis_move_motor: 4x%d 2x%d 1x%d\n", quadSteps, biSteps, fullSteps); 1221141cc406Sopenharmony_ci /* Note: the TWAIN driver opens the motor control register only 1222141cc406Sopenharmony_ci once before the loop, and closes it after the loop. I've tried this 1223141cc406Sopenharmony_ci too, but it resulted in inaccurate skip distances; therefore, the 1224141cc406Sopenharmony_ci motor control register is now opened and closed for each step. */ 1225141cc406Sopenharmony_ci 1226141cc406Sopenharmony_ci while (quadSteps-- > 0 && dev->desc->state != STATE_CANCELLED) 1227141cc406Sopenharmony_ci { 1228141cc406Sopenharmony_ci cis_wait_motor_stable (dev); 1229141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_MOTOR_CONTROL, quadStep); 1230141cc406Sopenharmony_ci } 1231141cc406Sopenharmony_ci 1232141cc406Sopenharmony_ci while (biSteps-- > 0 && dev->desc->state != STATE_CANCELLED) 1233141cc406Sopenharmony_ci { 1234141cc406Sopenharmony_ci cis_wait_motor_stable (dev); 1235141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_MOTOR_CONTROL, biStep); 1236141cc406Sopenharmony_ci } 1237141cc406Sopenharmony_ci 1238141cc406Sopenharmony_ci while (fullSteps-- > 0 && dev->desc->state != STATE_CANCELLED) 1239141cc406Sopenharmony_ci { 1240141cc406Sopenharmony_ci cis_wait_motor_stable (dev); 1241141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_MOTOR_CONTROL, fullStep); 1242141cc406Sopenharmony_ci } 1243141cc406Sopenharmony_ci} 1244141cc406Sopenharmony_ci 1245141cc406Sopenharmony_cistatic void 1246141cc406Sopenharmony_cicis_set_et_pd_sti (Mustek_PP_CIS_dev * dev) 1247141cc406Sopenharmony_ci{ 1248141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_EXPOSE_TIME, 1249141cc406Sopenharmony_ci dev->CIS.exposeTime); 1250141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_POWER_ON_DELAY, 1251141cc406Sopenharmony_ci dev->CIS.powerOnDelay[dev->CIS.channel]); 1252141cc406Sopenharmony_ci cis_set_ccd_channel (dev); 1253141cc406Sopenharmony_ci cis_set_sti (dev); 1254141cc406Sopenharmony_ci} 1255141cc406Sopenharmony_ci 1256141cc406Sopenharmony_ci/* 1257141cc406Sopenharmony_ci * Prepare the scanner for catching the next channel and, if necessary, 1258141cc406Sopenharmony_ci * move the head one step further. 1259141cc406Sopenharmony_ci */ 1260141cc406Sopenharmony_cistatic SANE_Bool 1261141cc406Sopenharmony_cicis_wait_next_channel (Mustek_PP_CIS_dev * dev) 1262141cc406Sopenharmony_ci{ 1263141cc406Sopenharmony_ci int moveAtChannel = dev->desc->mode == MODE_COLOR ? 1264141cc406Sopenharmony_ci MUSTEK_PP_CIS_CHANNEL_BLUE : MUSTEK_PP_CIS_CHANNEL_GRAY; 1265141cc406Sopenharmony_ci 1266141cc406Sopenharmony_ci if (!cis_wait_bank_change (dev, dev->bank_count)) 1267141cc406Sopenharmony_ci { 1268141cc406Sopenharmony_ci DBG(2, "cis_wait_next_channel: Could not get next bank.\n"); 1269141cc406Sopenharmony_ci return SANE_FALSE; 1270141cc406Sopenharmony_ci } 1271141cc406Sopenharmony_ci 1272141cc406Sopenharmony_ci moveAtChannel = (dev->desc->mode == MODE_COLOR) ? 1273141cc406Sopenharmony_ci MUSTEK_PP_CIS_CHANNEL_BLUE : MUSTEK_PP_CIS_CHANNEL_GRAY; 1274141cc406Sopenharmony_ci 1275141cc406Sopenharmony_ci if (dev->CIS.channel == moveAtChannel && !dev->CIS.dontMove) 1276141cc406Sopenharmony_ci { 1277141cc406Sopenharmony_ci cis_motor_forward (dev); 1278141cc406Sopenharmony_ci } 1279141cc406Sopenharmony_ci 1280141cc406Sopenharmony_ci cis_set_et_pd_sti (dev); 1281141cc406Sopenharmony_ci 1282141cc406Sopenharmony_ci if (dev->desc->mode == MODE_COLOR) 1283141cc406Sopenharmony_ci { 1284141cc406Sopenharmony_ci ++dev->CIS.channel; 1285141cc406Sopenharmony_ci dev->CIS.channel %= 3; 1286141cc406Sopenharmony_ci } 1287141cc406Sopenharmony_ci 1288141cc406Sopenharmony_ci return SANE_TRUE; 1289141cc406Sopenharmony_ci} 1290141cc406Sopenharmony_ci 1291141cc406Sopenharmony_ci/* 1292141cc406Sopenharmony_ci * Wait for the device to be ready for scanning. Cycles through the different 1293141cc406Sopenharmony_ci * channels and sets the parameters (only green channel in gray/lineart). 1294141cc406Sopenharmony_ci */ 1295141cc406Sopenharmony_cistatic SANE_Bool 1296141cc406Sopenharmony_cicis_wait_read_ready (Mustek_PP_CIS_dev * dev) 1297141cc406Sopenharmony_ci{ 1298141cc406Sopenharmony_ci int channel; 1299141cc406Sopenharmony_ci dev->CIS.dontIncRead = SANE_TRUE; 1300141cc406Sopenharmony_ci 1301141cc406Sopenharmony_ci dev->CIS.channel = dev->desc->mode == MODE_COLOR ? 1302141cc406Sopenharmony_ci MUSTEK_PP_CIS_CHANNEL_RED : MUSTEK_PP_CIS_CHANNEL_GRAY; 1303141cc406Sopenharmony_ci 1304141cc406Sopenharmony_ci for (channel = 0; channel < 3; ++channel) 1305141cc406Sopenharmony_ci { 1306141cc406Sopenharmony_ci if (!cis_wait_next_channel(dev)) return SANE_FALSE; 1307141cc406Sopenharmony_ci } 1308141cc406Sopenharmony_ci return SANE_TRUE; 1309141cc406Sopenharmony_ci} 1310141cc406Sopenharmony_ci 1311141cc406Sopenharmony_cistatic int 1312141cc406Sopenharmony_cidelay_read (int delay) 1313141cc406Sopenharmony_ci{ 1314141cc406Sopenharmony_ci /* 1315141cc406Sopenharmony_ci * A (very) smart compiler may complete optimize the delay loop away. By 1316141cc406Sopenharmony_ci * adding some difficult data dependencies, we can try to prevent this. 1317141cc406Sopenharmony_ci */ 1318141cc406Sopenharmony_ci static int prevent_removal, i; 1319141cc406Sopenharmony_ci for (i = 0; i<delay; ++i) 1320141cc406Sopenharmony_ci { 1321141cc406Sopenharmony_ci prevent_removal = sqrt(prevent_removal+1.); /* Just waste some cycles */ 1322141cc406Sopenharmony_ci } 1323141cc406Sopenharmony_ci return prevent_removal; /* another data dependency */ 1324141cc406Sopenharmony_ci} 1325141cc406Sopenharmony_ci 1326141cc406Sopenharmony_ci/* 1327141cc406Sopenharmony_ci** Reads one line of pixels 1328141cc406Sopenharmony_ci*/ 1329141cc406Sopenharmony_cistatic void 1330141cc406Sopenharmony_cicis_read_line_low_level (Mustek_PP_CIS_dev * dev, SANE_Byte * buf, 1331141cc406Sopenharmony_ci SANE_Int pixel, SANE_Byte * calib_low, 1332141cc406Sopenharmony_ci SANE_Byte * calib_hi, SANE_Int * gamma) 1333141cc406Sopenharmony_ci{ 1334141cc406Sopenharmony_ci u_char color; 1335141cc406Sopenharmony_ci int ctr, skips = dev->CIS.adjustskip, cval; 1336141cc406Sopenharmony_ci int bpos = 0; 1337141cc406Sopenharmony_ci SANE_Byte low_val = 0, hi_val = 255; 1338141cc406Sopenharmony_ci 1339141cc406Sopenharmony_ci if (pixel <= 0) 1340141cc406Sopenharmony_ci return; 1341141cc406Sopenharmony_ci 1342141cc406Sopenharmony_ci SANEI_PA4S2_READBEGIN (dev->desc->fd, 1); 1343141cc406Sopenharmony_ci 1344141cc406Sopenharmony_ci while(skips-- >= 0) 1345141cc406Sopenharmony_ci { 1346141cc406Sopenharmony_ci if (dev->CIS.delay) delay_read(dev->CIS.delay); 1347141cc406Sopenharmony_ci SANEI_PA4S2_READBYTE (dev->desc->fd, &color); 1348141cc406Sopenharmony_ci } 1349141cc406Sopenharmony_ci 1350141cc406Sopenharmony_ci if (dev->CIS.hw_hres == dev->CIS.res) 1351141cc406Sopenharmony_ci { 1352141cc406Sopenharmony_ci /* One-to one mapping */ 1353141cc406Sopenharmony_ci DBG (6, "cis_read_line_low_level: one-to-one\n"); 1354141cc406Sopenharmony_ci for (ctr = 0; ctr < pixel; ctr++) 1355141cc406Sopenharmony_ci { 1356141cc406Sopenharmony_ci if (dev->CIS.delay) delay_read(dev->CIS.delay); 1357141cc406Sopenharmony_ci SANEI_PA4S2_READBYTE (dev->desc->fd, &color); 1358141cc406Sopenharmony_ci 1359141cc406Sopenharmony_ci cval = color; 1360141cc406Sopenharmony_ci 1361141cc406Sopenharmony_ci if (calib_low) { 1362141cc406Sopenharmony_ci low_val = calib_low[ctr] ; 1363141cc406Sopenharmony_ci } 1364141cc406Sopenharmony_ci 1365141cc406Sopenharmony_ci if (calib_hi) { 1366141cc406Sopenharmony_ci hi_val = calib_hi[ctr] ; 1367141cc406Sopenharmony_ci } 1368141cc406Sopenharmony_ci 1369141cc406Sopenharmony_ci cval -= low_val ; 1370141cc406Sopenharmony_ci cval <<= 8 ; 1371141cc406Sopenharmony_ci cval /= hi_val-low_val ; 1372141cc406Sopenharmony_ci 1373141cc406Sopenharmony_ci if (cval < 0) cval = 0; 1374141cc406Sopenharmony_ci else if (cval > 255) cval = 255; 1375141cc406Sopenharmony_ci 1376141cc406Sopenharmony_ci if (gamma) 1377141cc406Sopenharmony_ci cval = gamma[cval]; 1378141cc406Sopenharmony_ci 1379141cc406Sopenharmony_ci buf[ctr] = cval; 1380141cc406Sopenharmony_ci } 1381141cc406Sopenharmony_ci } 1382141cc406Sopenharmony_ci else if (dev->CIS.hw_hres > dev->CIS.res) 1383141cc406Sopenharmony_ci { 1384141cc406Sopenharmony_ci /* Sub-sampling */ 1385141cc406Sopenharmony_ci 1386141cc406Sopenharmony_ci int pos = 0; 1387141cc406Sopenharmony_ci DBG (6, "cis_read_line_low_level: sub-sampling\n"); 1388141cc406Sopenharmony_ci ctr = 0; 1389141cc406Sopenharmony_ci do 1390141cc406Sopenharmony_ci { 1391141cc406Sopenharmony_ci if (dev->CIS.delay) delay_read(dev->CIS.delay); 1392141cc406Sopenharmony_ci SANEI_PA4S2_READBYTE (dev->desc->fd, &color); 1393141cc406Sopenharmony_ci 1394141cc406Sopenharmony_ci cval = color; 1395141cc406Sopenharmony_ci if (ctr < (pos >> SANE_FIXED_SCALE_SHIFT)) 1396141cc406Sopenharmony_ci { 1397141cc406Sopenharmony_ci ctr++; 1398141cc406Sopenharmony_ci continue; 1399141cc406Sopenharmony_ci } 1400141cc406Sopenharmony_ci 1401141cc406Sopenharmony_ci ctr++; 1402141cc406Sopenharmony_ci pos += dev->CIS.hres_step; 1403141cc406Sopenharmony_ci 1404141cc406Sopenharmony_ci if (calib_low) { 1405141cc406Sopenharmony_ci low_val = calib_low[bpos] ; 1406141cc406Sopenharmony_ci } 1407141cc406Sopenharmony_ci 1408141cc406Sopenharmony_ci if (calib_hi) { 1409141cc406Sopenharmony_ci hi_val = calib_hi[bpos] ; 1410141cc406Sopenharmony_ci } 1411141cc406Sopenharmony_ci cval -= low_val ; 1412141cc406Sopenharmony_ci cval <<= 8 ; 1413141cc406Sopenharmony_ci cval /= hi_val-low_val ; 1414141cc406Sopenharmony_ci 1415141cc406Sopenharmony_ci if (cval < 0) cval = 0 ; 1416141cc406Sopenharmony_ci else if (cval > 255) cval = 255 ; 1417141cc406Sopenharmony_ci 1418141cc406Sopenharmony_ci if (gamma) cval = gamma[cval]; 1419141cc406Sopenharmony_ci 1420141cc406Sopenharmony_ci buf[bpos++] = cval; 1421141cc406Sopenharmony_ci } 1422141cc406Sopenharmony_ci while (bpos < pixel); 1423141cc406Sopenharmony_ci } 1424141cc406Sopenharmony_ci else 1425141cc406Sopenharmony_ci { 1426141cc406Sopenharmony_ci int calctr = 0; 1427141cc406Sopenharmony_ci SANE_Int pos = 0, nextPos = 1; 1428141cc406Sopenharmony_ci /* Step: eg: 600 DPI -> 700 DPI -> hres_step = 6/7 -> step = 1/7 */ 1429141cc406Sopenharmony_ci SANE_Int step = SANE_FIX(1) - dev->CIS.hres_step; 1430141cc406Sopenharmony_ci 1431141cc406Sopenharmony_ci /* Super-sampling */ 1432141cc406Sopenharmony_ci DBG (6, "cis_read_line_low_level: super-sampling\n"); 1433141cc406Sopenharmony_ci do 1434141cc406Sopenharmony_ci { 1435141cc406Sopenharmony_ci if (dev->CIS.delay) delay_read(dev->CIS.delay); 1436141cc406Sopenharmony_ci SANEI_PA4S2_READBYTE (dev->desc->fd, &color); 1437141cc406Sopenharmony_ci 1438141cc406Sopenharmony_ci cval = color; 1439141cc406Sopenharmony_ci 1440141cc406Sopenharmony_ci if (calib_low) { 1441141cc406Sopenharmony_ci low_val = calib_low[calctr] ; 1442141cc406Sopenharmony_ci } 1443141cc406Sopenharmony_ci 1444141cc406Sopenharmony_ci if (calib_hi) { 1445141cc406Sopenharmony_ci hi_val = calib_hi[calctr] ; 1446141cc406Sopenharmony_ci } 1447141cc406Sopenharmony_ci 1448141cc406Sopenharmony_ci if (++calctr >= dev->calib_pixels) { 1449141cc406Sopenharmony_ci /* Avoid array boundary violations due to rounding errors 1450141cc406Sopenharmony_ci (due to the incremental calculation, the current position 1451141cc406Sopenharmony_ci may be inaccurate to up to two pixels, so we may need to 1452141cc406Sopenharmony_ci read a few extra bytes -> use the last calibration value) */ 1453141cc406Sopenharmony_ci calctr = dev->calib_pixels - 1; 1454141cc406Sopenharmony_ci DBG (3, "cis_read_line_low_level: calibration overshoot\n"); 1455141cc406Sopenharmony_ci } 1456141cc406Sopenharmony_ci 1457141cc406Sopenharmony_ci cval -= low_val ; 1458141cc406Sopenharmony_ci cval <<= 8 ; 1459141cc406Sopenharmony_ci cval /= hi_val-low_val ; 1460141cc406Sopenharmony_ci 1461141cc406Sopenharmony_ci if (cval < 0) cval = 0 ; 1462141cc406Sopenharmony_ci else if (cval > 255) cval = 255 ; 1463141cc406Sopenharmony_ci 1464141cc406Sopenharmony_ci if (gamma) 1465141cc406Sopenharmony_ci cval = gamma[cval]; 1466141cc406Sopenharmony_ci 1467141cc406Sopenharmony_ci pos += step; 1468141cc406Sopenharmony_ci 1469141cc406Sopenharmony_ci if ((pos >> SANE_FIXED_SCALE_SHIFT) >= nextPos) 1470141cc406Sopenharmony_ci { 1471141cc406Sopenharmony_ci nextPos++; 1472141cc406Sopenharmony_ci 1473141cc406Sopenharmony_ci /* Insert an interpolated value */ 1474141cc406Sopenharmony_ci buf[bpos] = (buf[bpos-1] + cval)/2; /* Interpolate */ 1475141cc406Sopenharmony_ci ++bpos; 1476141cc406Sopenharmony_ci 1477141cc406Sopenharmony_ci /* Store the plain value, but only if we still need pixels */ 1478141cc406Sopenharmony_ci if (bpos < pixel) 1479141cc406Sopenharmony_ci buf[bpos++] = cval; 1480141cc406Sopenharmony_ci 1481141cc406Sopenharmony_ci pos += step; /* Take interpolated value into account for pos */ 1482141cc406Sopenharmony_ci } 1483141cc406Sopenharmony_ci else 1484141cc406Sopenharmony_ci { 1485141cc406Sopenharmony_ci buf[bpos++] = cval; 1486141cc406Sopenharmony_ci } 1487141cc406Sopenharmony_ci } 1488141cc406Sopenharmony_ci while (bpos < pixel); 1489141cc406Sopenharmony_ci } 1490141cc406Sopenharmony_ci 1491141cc406Sopenharmony_ci SANEI_PA4S2_READEND (dev->desc->fd); 1492141cc406Sopenharmony_ci DBG (6, "cis_read_line_low_level: done\n"); 1493141cc406Sopenharmony_ci} 1494141cc406Sopenharmony_ci 1495141cc406Sopenharmony_cistatic SANE_Bool 1496141cc406Sopenharmony_cicis_read_line (Mustek_PP_CIS_dev * dev, SANE_Byte* buf, SANE_Int pixel, 1497141cc406Sopenharmony_ci SANE_Bool raw) 1498141cc406Sopenharmony_ci{ 1499141cc406Sopenharmony_ci if (!dev->CIS.dontIncRead) 1500141cc406Sopenharmony_ci CIS_INC_READ(dev); 1501141cc406Sopenharmony_ci else 1502141cc406Sopenharmony_ci dev->CIS.dontIncRead = SANE_FALSE; 1503141cc406Sopenharmony_ci 1504141cc406Sopenharmony_ci 1505141cc406Sopenharmony_ci if (raw) 1506141cc406Sopenharmony_ci { 1507141cc406Sopenharmony_ci /* No color correction; raw data */ 1508141cc406Sopenharmony_ci cis_read_line_low_level (dev, buf, pixel, NULL, NULL, NULL); 1509141cc406Sopenharmony_ci } 1510141cc406Sopenharmony_ci else 1511141cc406Sopenharmony_ci { 1512141cc406Sopenharmony_ci /* Color correction */ 1513141cc406Sopenharmony_ci cis_read_line_low_level (dev, buf, pixel, 1514141cc406Sopenharmony_ci dev->calib_low[dev->CIS.channel], 1515141cc406Sopenharmony_ci dev->calib_hi[dev->CIS.channel], 1516141cc406Sopenharmony_ci (dev->desc->val[OPT_CUSTOM_GAMMA].w ? 1517141cc406Sopenharmony_ci dev->desc->gamma_table[dev->CIS.channel] : NULL)); 1518141cc406Sopenharmony_ci } 1519141cc406Sopenharmony_ci 1520141cc406Sopenharmony_ci return cis_wait_next_channel(dev); 1521141cc406Sopenharmony_ci} 1522141cc406Sopenharmony_ci 1523141cc406Sopenharmony_cistatic void 1524141cc406Sopenharmony_cicis_get_next_line (Mustek_PP_CIS_dev * dev, SANE_Byte * buf) 1525141cc406Sopenharmony_ci{ 1526141cc406Sopenharmony_ci SANE_Byte *dest, *tmpbuf = dev->tmpbuf; 1527141cc406Sopenharmony_ci int ctr, channel, first, last, stride, step = dev->CIS.line_step; 1528141cc406Sopenharmony_ci SANE_Byte gotline; 1529141cc406Sopenharmony_ci 1530141cc406Sopenharmony_ci if (dev->desc->mode == MODE_COLOR) 1531141cc406Sopenharmony_ci { 1532141cc406Sopenharmony_ci first = MUSTEK_PP_CIS_CHANNEL_RED; 1533141cc406Sopenharmony_ci last = MUSTEK_PP_CIS_CHANNEL_BLUE; 1534141cc406Sopenharmony_ci stride = 3; 1535141cc406Sopenharmony_ci } 1536141cc406Sopenharmony_ci else 1537141cc406Sopenharmony_ci { 1538141cc406Sopenharmony_ci first = MUSTEK_PP_CIS_CHANNEL_GRAY; 1539141cc406Sopenharmony_ci last = MUSTEK_PP_CIS_CHANNEL_GRAY; 1540141cc406Sopenharmony_ci stride = 1; 1541141cc406Sopenharmony_ci } 1542141cc406Sopenharmony_ci 1543141cc406Sopenharmony_ci gotline = SANE_FALSE; 1544141cc406Sopenharmony_ci do 1545141cc406Sopenharmony_ci { 1546141cc406Sopenharmony_ci dev->ccd_line++; 1547141cc406Sopenharmony_ci if ((dev->line_diff >> SANE_FIXED_SCALE_SHIFT) != dev->ccd_line) 1548141cc406Sopenharmony_ci { 1549141cc406Sopenharmony_ci cis_motor_forward (dev); 1550141cc406Sopenharmony_ci continue; 1551141cc406Sopenharmony_ci } 1552141cc406Sopenharmony_ci 1553141cc406Sopenharmony_ci dev->line_diff += step; 1554141cc406Sopenharmony_ci 1555141cc406Sopenharmony_ci for (channel = first; channel <= last; ++channel) 1556141cc406Sopenharmony_ci { 1557141cc406Sopenharmony_ci if (!cis_read_line(dev, tmpbuf, dev->desc->params.pixels_per_line, 1558141cc406Sopenharmony_ci SANE_FALSE)) 1559141cc406Sopenharmony_ci return; 1560141cc406Sopenharmony_ci 1561141cc406Sopenharmony_ci dest = buf + channel - first; 1562141cc406Sopenharmony_ci for (ctr = 0; ctr < dev->desc->params.pixels_per_line; ctr++) 1563141cc406Sopenharmony_ci { 1564141cc406Sopenharmony_ci *dest = tmpbuf[ctr]; 1565141cc406Sopenharmony_ci dest += stride; 1566141cc406Sopenharmony_ci } 1567141cc406Sopenharmony_ci } 1568141cc406Sopenharmony_ci gotline = SANE_TRUE; 1569141cc406Sopenharmony_ci } 1570141cc406Sopenharmony_ci while (!gotline && dev->desc->state != STATE_CANCELLED); 1571141cc406Sopenharmony_ci} 1572141cc406Sopenharmony_ci 1573141cc406Sopenharmony_cistatic void 1574141cc406Sopenharmony_cicis_get_grayscale_line (Mustek_PP_CIS_dev * dev, SANE_Byte * buf) 1575141cc406Sopenharmony_ci{ 1576141cc406Sopenharmony_ci cis_get_next_line(dev, buf); 1577141cc406Sopenharmony_ci} 1578141cc406Sopenharmony_ci 1579141cc406Sopenharmony_cistatic void 1580141cc406Sopenharmony_cicis_get_lineart_line (Mustek_PP_CIS_dev * dev, SANE_Byte * buf) 1581141cc406Sopenharmony_ci{ 1582141cc406Sopenharmony_ci int ctr; 1583141cc406Sopenharmony_ci SANE_Byte gbuf[MUSTEK_PP_CIS_MAX_H_PIXEL * 2]; 1584141cc406Sopenharmony_ci 1585141cc406Sopenharmony_ci cis_get_grayscale_line (dev, gbuf); 1586141cc406Sopenharmony_ci memset (buf, 0xFF, dev->desc->params.bytes_per_line); 1587141cc406Sopenharmony_ci 1588141cc406Sopenharmony_ci for (ctr = 0; ctr < dev->desc->params.pixels_per_line; ctr++) 1589141cc406Sopenharmony_ci buf[ctr >> 3] ^= ((gbuf[ctr] > dev->bw_limit) ? (1 << (7 - ctr % 8)) : 0); 1590141cc406Sopenharmony_ci} 1591141cc406Sopenharmony_ci 1592141cc406Sopenharmony_cistatic void 1593141cc406Sopenharmony_cicis_get_color_line (Mustek_PP_CIS_dev * dev, SANE_Byte * buf) 1594141cc406Sopenharmony_ci{ 1595141cc406Sopenharmony_ci cis_get_next_line(dev, buf); 1596141cc406Sopenharmony_ci} 1597141cc406Sopenharmony_ci 1598141cc406Sopenharmony_ci 1599141cc406Sopenharmony_ci/****************************************************************************** 1600141cc406Sopenharmony_ci * Saves the state of the device during reset and calibration. 1601141cc406Sopenharmony_ci *****************************************************************************/ 1602141cc406Sopenharmony_cistatic void 1603141cc406Sopenharmony_cicis_save_state (Mustek_PP_CIS_dev * dev) 1604141cc406Sopenharmony_ci{ 1605141cc406Sopenharmony_ci dev->Saved_CIS = dev->CIS; 1606141cc406Sopenharmony_ci} 1607141cc406Sopenharmony_ci 1608141cc406Sopenharmony_ci/****************************************************************************** 1609141cc406Sopenharmony_ci * Restores the state of the device after reset and calibration. 1610141cc406Sopenharmony_ci *****************************************************************************/ 1611141cc406Sopenharmony_cistatic void 1612141cc406Sopenharmony_cicis_restore_state (Mustek_PP_CIS_dev * dev) 1613141cc406Sopenharmony_ci{ 1614141cc406Sopenharmony_ci dev->CIS = dev->Saved_CIS; 1615141cc406Sopenharmony_ci} 1616141cc406Sopenharmony_ci 1617141cc406Sopenharmony_ci#define CIS_TOO_BRIGHT 1 1618141cc406Sopenharmony_ci#define CIS_OK 0 1619141cc406Sopenharmony_ci#define CIS_TOO_DARK -1 1620141cc406Sopenharmony_ci 1621141cc406Sopenharmony_cistatic int 1622141cc406Sopenharmony_cicis_check_result(SANE_Byte* buffer, int pixel) 1623141cc406Sopenharmony_ci{ 1624141cc406Sopenharmony_ci int i, maxVal = 0; 1625141cc406Sopenharmony_ci 1626141cc406Sopenharmony_ci for (i=0;i<pixel;++i) 1627141cc406Sopenharmony_ci if (buffer[i] > maxVal) maxVal = buffer[i]; 1628141cc406Sopenharmony_ci 1629141cc406Sopenharmony_ci if (maxVal > 250) return CIS_TOO_BRIGHT; 1630141cc406Sopenharmony_ci if (maxVal < 240) return CIS_TOO_DARK; 1631141cc406Sopenharmony_ci return CIS_OK; 1632141cc406Sopenharmony_ci} 1633141cc406Sopenharmony_ci 1634141cc406Sopenharmony_cistatic SANE_Bool 1635141cc406Sopenharmony_cicis_maximize_dynamic_range(Mustek_PP_CIS_dev * dev) 1636141cc406Sopenharmony_ci{ 1637141cc406Sopenharmony_ci /* The device is in its final configuration already. */ 1638141cc406Sopenharmony_ci int i, j, pixel, channel, minExposeTime, first, last; 1639141cc406Sopenharmony_ci SANE_Byte powerOnDelayLower[3], powerOnDelayUpper[3], exposeTime[3]; 1640141cc406Sopenharmony_ci SANE_Byte buf[3][MUSTEK_PP_CIS_MAX_H_PIXEL]; 1641141cc406Sopenharmony_ci SANE_Int pixels = dev->calib_pixels; 1642141cc406Sopenharmony_ci 1643141cc406Sopenharmony_ci DBG(3, "cis_maximize_dynamic_range: starting\n"); 1644141cc406Sopenharmony_ci 1645141cc406Sopenharmony_ci for (channel = 0; channel < 3; ++channel) 1646141cc406Sopenharmony_ci { 1647141cc406Sopenharmony_ci exposeTime[channel] = 254; 1648141cc406Sopenharmony_ci dev->CIS.powerOnDelay[channel] = 170; 1649141cc406Sopenharmony_ci powerOnDelayLower[channel] = 1; 1650141cc406Sopenharmony_ci powerOnDelayUpper[channel] = 254; 1651141cc406Sopenharmony_ci } 1652141cc406Sopenharmony_ci dev->CIS.setParameters = SANE_TRUE; 1653141cc406Sopenharmony_ci dev->CIS.exposeTime = exposeTime[MUSTEK_PP_CIS_CHANNEL_GREEN]; 1654141cc406Sopenharmony_ci cis_config_ccd(dev); 1655141cc406Sopenharmony_ci 1656141cc406Sopenharmony_ci M1015_DISPLAY_REGS(dev, "before maximizing dynamic range"); 1657141cc406Sopenharmony_ci dev->CIS.dontMove = SANE_TRUE; /* Don't move while calibrating */ 1658141cc406Sopenharmony_ci 1659141cc406Sopenharmony_ci if (!cis_wait_read_ready(dev) && dev->desc->state != STATE_CANCELLED) 1660141cc406Sopenharmony_ci { 1661141cc406Sopenharmony_ci DBG(2, "cis_maximize_dynamic_range: DEVICE NOT READY!\n"); 1662141cc406Sopenharmony_ci return SANE_FALSE; 1663141cc406Sopenharmony_ci } 1664141cc406Sopenharmony_ci 1665141cc406Sopenharmony_ci if (dev->desc->mode == MODE_COLOR) 1666141cc406Sopenharmony_ci { 1667141cc406Sopenharmony_ci first = MUSTEK_PP_CIS_CHANNEL_RED; 1668141cc406Sopenharmony_ci last = MUSTEK_PP_CIS_CHANNEL_BLUE; 1669141cc406Sopenharmony_ci } 1670141cc406Sopenharmony_ci else 1671141cc406Sopenharmony_ci { 1672141cc406Sopenharmony_ci first = MUSTEK_PP_CIS_CHANNEL_GRAY; 1673141cc406Sopenharmony_ci last = MUSTEK_PP_CIS_CHANNEL_GRAY; 1674141cc406Sopenharmony_ci } 1675141cc406Sopenharmony_ci 1676141cc406Sopenharmony_ci dev->CIS.channel = first; 1677141cc406Sopenharmony_ci 1678141cc406Sopenharmony_ci /* Perform a kind of binary search. In the worst case, we should find 1679141cc406Sopenharmony_ci the optimal power delay values after 8 iterations */ 1680141cc406Sopenharmony_ci for( i=0; i<8; i++) 1681141cc406Sopenharmony_ci { 1682141cc406Sopenharmony_ci for (channel = first; channel <= last; ++channel) 1683141cc406Sopenharmony_ci { 1684141cc406Sopenharmony_ci dev->CIS.powerOnDelay[channel] = (powerOnDelayLower[channel] + 1685141cc406Sopenharmony_ci powerOnDelayUpper[channel]) / 2; 1686141cc406Sopenharmony_ci } 1687141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_POWER_ON_DELAY, 1688141cc406Sopenharmony_ci dev->CIS.powerOnDelay[1]); /* Green */ 1689141cc406Sopenharmony_ci 1690141cc406Sopenharmony_ci for (pixel = 0; pixel < pixels; ++pixel) 1691141cc406Sopenharmony_ci { 1692141cc406Sopenharmony_ci buf[0][pixel] = buf[1][pixel] = buf[2][pixel] = 255; 1693141cc406Sopenharmony_ci } 1694141cc406Sopenharmony_ci 1695141cc406Sopenharmony_ci /* Scan 4 lines, but ignore the first 3 ones. */ 1696141cc406Sopenharmony_ci for (j = 0; j < 4; ++j) 1697141cc406Sopenharmony_ci { 1698141cc406Sopenharmony_ci for (channel = first; channel <= last; ++channel) 1699141cc406Sopenharmony_ci { 1700141cc406Sopenharmony_ci if (!cis_read_line(dev, &buf[channel][0], pixels, 1701141cc406Sopenharmony_ci /* raw = */ SANE_TRUE)) 1702141cc406Sopenharmony_ci return SANE_FALSE; 1703141cc406Sopenharmony_ci } 1704141cc406Sopenharmony_ci } 1705141cc406Sopenharmony_ci 1706141cc406Sopenharmony_ci for (channel = first; channel <= last; ++channel) 1707141cc406Sopenharmony_ci { 1708141cc406Sopenharmony_ci switch (cis_check_result(buf[channel], pixels)) 1709141cc406Sopenharmony_ci { 1710141cc406Sopenharmony_ci case CIS_TOO_BRIGHT: 1711141cc406Sopenharmony_ci powerOnDelayLower[channel] = dev->CIS.powerOnDelay[channel]; 1712141cc406Sopenharmony_ci break; 1713141cc406Sopenharmony_ci 1714141cc406Sopenharmony_ci case CIS_TOO_DARK: 1715141cc406Sopenharmony_ci powerOnDelayUpper[channel] = dev->CIS.powerOnDelay[channel]; 1716141cc406Sopenharmony_ci break; 1717141cc406Sopenharmony_ci 1718141cc406Sopenharmony_ci default: 1719141cc406Sopenharmony_ci break; 1720141cc406Sopenharmony_ci } 1721141cc406Sopenharmony_ci } 1722141cc406Sopenharmony_ci DBG (4, "cis_maximize_dynamic_range: power on delay %3d %3d %3d\n", 1723141cc406Sopenharmony_ci dev->CIS.powerOnDelay[0], dev->CIS.powerOnDelay[1], 1724141cc406Sopenharmony_ci dev->CIS.powerOnDelay[2]); 1725141cc406Sopenharmony_ci } 1726141cc406Sopenharmony_ci dev->CIS.dontMove = SANE_FALSE; 1727141cc406Sopenharmony_ci 1728141cc406Sopenharmony_ci DBG (3, "cis_maximize_dynamic_range: power on delay %3d %3d %3d\n", 1729141cc406Sopenharmony_ci dev->CIS.powerOnDelay[0], dev->CIS.powerOnDelay[1], 1730141cc406Sopenharmony_ci dev->CIS.powerOnDelay[2]); 1731141cc406Sopenharmony_ci 1732141cc406Sopenharmony_ci minExposeTime = (dev->CIS.hw_hres <= 300) ? 170 : 253; 1733141cc406Sopenharmony_ci 1734141cc406Sopenharmony_ci for (channel = first; channel <= last; ++channel) 1735141cc406Sopenharmony_ci { 1736141cc406Sopenharmony_ci dev->CIS.powerOnDelay[channel] = (powerOnDelayLower[channel] + 1737141cc406Sopenharmony_ci powerOnDelayUpper[channel]) / 2; 1738141cc406Sopenharmony_ci exposeTime[channel] -= dev->CIS.powerOnDelay[channel] - 1; 1739141cc406Sopenharmony_ci dev->CIS.powerOnDelay[channel] = 1; 1740141cc406Sopenharmony_ci 1741141cc406Sopenharmony_ci if (exposeTime[channel] < minExposeTime) 1742141cc406Sopenharmony_ci { 1743141cc406Sopenharmony_ci dev->CIS.powerOnDelay[channel] += 1744141cc406Sopenharmony_ci minExposeTime - exposeTime[channel]; 1745141cc406Sopenharmony_ci exposeTime[channel] = minExposeTime; 1746141cc406Sopenharmony_ci } 1747141cc406Sopenharmony_ci } 1748141cc406Sopenharmony_ci 1749141cc406Sopenharmony_ci dev->CIS.exposeTime = exposeTime[MUSTEK_PP_CIS_CHANNEL_GREEN]; 1750141cc406Sopenharmony_ci 1751141cc406Sopenharmony_ci DBG (3, "cis_maximize_dynamic_range: expose time: %3d\n", exposeTime[1]); 1752141cc406Sopenharmony_ci DBG (3, "cis_maximize_dynamic_range: power on delay %3d %3d %3d\n", 1753141cc406Sopenharmony_ci dev->CIS.powerOnDelay[0], dev->CIS.powerOnDelay[1], 1754141cc406Sopenharmony_ci dev->CIS.powerOnDelay[2]); 1755141cc406Sopenharmony_ci 1756141cc406Sopenharmony_ci /* 1757141cc406Sopenharmony_ci * Short the calibration. Temporary, to find out what is wrong with 1758141cc406Sopenharmony_ci * the calibration on a 600 CP. 1759141cc406Sopenharmony_ci * 1760141cc406Sopenharmony_ci dev->CIS.exposeTime = 170; 1761141cc406Sopenharmony_ci dev->CIS.powerOnDelay[0] = 120; 1762141cc406Sopenharmony_ci dev->CIS.powerOnDelay[1] = 120; 1763141cc406Sopenharmony_ci dev->CIS.powerOnDelay[2] = 120; 1764141cc406Sopenharmony_ci */ 1765141cc406Sopenharmony_ci return SANE_TRUE; 1766141cc406Sopenharmony_ci} 1767141cc406Sopenharmony_ci 1768141cc406Sopenharmony_cistatic SANE_Bool 1769141cc406Sopenharmony_cicis_measure_extremes(Mustek_PP_CIS_dev * dev, SANE_Byte* calib[3], 1770141cc406Sopenharmony_ci SANE_Int pixels, SANE_Int first, SANE_Int last) 1771141cc406Sopenharmony_ci{ 1772141cc406Sopenharmony_ci SANE_Byte buf[3][MUSTEK_PP_CIS_MAX_H_PIXEL]; 1773141cc406Sopenharmony_ci SANE_Byte min[3][MUSTEK_PP_CIS_MAX_H_PIXEL]; 1774141cc406Sopenharmony_ci SANE_Byte max[3][MUSTEK_PP_CIS_MAX_H_PIXEL]; 1775141cc406Sopenharmony_ci SANE_Int sum[3][MUSTEK_PP_CIS_MAX_H_PIXEL]; 1776141cc406Sopenharmony_ci int channel, cnt, p; 1777141cc406Sopenharmony_ci 1778141cc406Sopenharmony_ci memset((void*)&min, 255, 3*MUSTEK_PP_CIS_MAX_H_PIXEL*sizeof(SANE_Byte)); 1779141cc406Sopenharmony_ci memset((void*)&max, 0, 3*MUSTEK_PP_CIS_MAX_H_PIXEL*sizeof(SANE_Byte)); 1780141cc406Sopenharmony_ci memset((void*)&sum, 0, 3*MUSTEK_PP_CIS_MAX_H_PIXEL*sizeof(SANE_Int)); 1781141cc406Sopenharmony_ci 1782141cc406Sopenharmony_ci dev->CIS.channel = first; 1783141cc406Sopenharmony_ci 1784141cc406Sopenharmony_ci /* Purge the banks first (there's always a 3-cycle delay) */ 1785141cc406Sopenharmony_ci for (channel = first; channel <= last; ++channel) 1786141cc406Sopenharmony_ci { 1787141cc406Sopenharmony_ci if (!cis_read_line(dev, &buf[channel%3][0], pixels, 1788141cc406Sopenharmony_ci /* raw = */ SANE_TRUE)) 1789141cc406Sopenharmony_ci return SANE_FALSE; 1790141cc406Sopenharmony_ci } 1791141cc406Sopenharmony_ci --dev->CIS.skipsToOrigin; 1792141cc406Sopenharmony_ci 1793141cc406Sopenharmony_ci for (cnt = 0; cnt < MUSTEK_PP_CIS_AVERAGE_COUNT + 2; ++cnt) 1794141cc406Sopenharmony_ci { 1795141cc406Sopenharmony_ci for (channel = first; channel <= last; ++channel) 1796141cc406Sopenharmony_ci { 1797141cc406Sopenharmony_ci DBG(4, "cis_measure_extremes: Reading line %d - channel %d\n", 1798141cc406Sopenharmony_ci cnt, channel); 1799141cc406Sopenharmony_ci if (!cis_read_line(dev, &buf[channel][0], pixels, 1800141cc406Sopenharmony_ci /* raw = */ SANE_TRUE)) 1801141cc406Sopenharmony_ci return SANE_FALSE; 1802141cc406Sopenharmony_ci 1803141cc406Sopenharmony_ci for (p = 0; p < pixels; ++p) 1804141cc406Sopenharmony_ci { 1805141cc406Sopenharmony_ci SANE_Byte val = buf[channel][p]; 1806141cc406Sopenharmony_ci if (val < min[channel][p]) min[channel][p] = val; 1807141cc406Sopenharmony_ci if (val > max[channel][p]) max[channel][p] = val; 1808141cc406Sopenharmony_ci sum[channel][p] += val; 1809141cc406Sopenharmony_ci } 1810141cc406Sopenharmony_ci } 1811141cc406Sopenharmony_ci --dev->CIS.skipsToOrigin; 1812141cc406Sopenharmony_ci } 1813141cc406Sopenharmony_ci DBG(4, "cis_measure_extremes: Averaging\n"); 1814141cc406Sopenharmony_ci for (channel = first; channel <= last; ++channel) 1815141cc406Sopenharmony_ci { 1816141cc406Sopenharmony_ci /* Ignore the extreme values and take the average of the others. */ 1817141cc406Sopenharmony_ci for (p = 0; p < pixels; ++p) 1818141cc406Sopenharmony_ci { 1819141cc406Sopenharmony_ci sum[channel][p] -= min[channel][p] + max[channel][p]; 1820141cc406Sopenharmony_ci sum[channel][p] /= MUSTEK_PP_CIS_AVERAGE_COUNT; 1821141cc406Sopenharmony_ci if (calib[channel]) calib[channel][p] = sum[channel][p]; 1822141cc406Sopenharmony_ci } 1823141cc406Sopenharmony_ci } 1824141cc406Sopenharmony_ci DBG(4, "cis_measure_extremes: Done\n"); 1825141cc406Sopenharmony_ci return SANE_TRUE; 1826141cc406Sopenharmony_ci} 1827141cc406Sopenharmony_ci 1828141cc406Sopenharmony_cistatic SANE_Bool 1829141cc406Sopenharmony_cicis_normalize_ranges(Mustek_PP_CIS_dev * dev) 1830141cc406Sopenharmony_ci{ 1831141cc406Sopenharmony_ci SANE_Byte cal_low, cal_hi ; 1832141cc406Sopenharmony_ci SANE_Byte powerOnDelay[3] ; 1833141cc406Sopenharmony_ci SANE_Int pixels = dev->calib_pixels; 1834141cc406Sopenharmony_ci SANE_Int channel, p, first, last; 1835141cc406Sopenharmony_ci 1836141cc406Sopenharmony_ci if (dev->desc->mode == MODE_COLOR) 1837141cc406Sopenharmony_ci { 1838141cc406Sopenharmony_ci first = MUSTEK_PP_CIS_CHANNEL_RED; 1839141cc406Sopenharmony_ci last = MUSTEK_PP_CIS_CHANNEL_BLUE; 1840141cc406Sopenharmony_ci } 1841141cc406Sopenharmony_ci else 1842141cc406Sopenharmony_ci { 1843141cc406Sopenharmony_ci first = MUSTEK_PP_CIS_CHANNEL_GRAY; 1844141cc406Sopenharmony_ci last = MUSTEK_PP_CIS_CHANNEL_GRAY; 1845141cc406Sopenharmony_ci } 1846141cc406Sopenharmony_ci 1847141cc406Sopenharmony_ci DBG(3, "cis_normalize_ranges: Measuring high extremes\n"); 1848141cc406Sopenharmony_ci /* Measure extremes with normal lighting */ 1849141cc406Sopenharmony_ci if (!cis_measure_extremes(dev, dev->calib_hi, pixels, first, last)) { 1850141cc406Sopenharmony_ci return SANE_FALSE; 1851141cc406Sopenharmony_ci } 1852141cc406Sopenharmony_ci 1853141cc406Sopenharmony_ci /* Measure extremes without lighting */ 1854141cc406Sopenharmony_ci for (channel=first; channel<=last; ++channel) { 1855141cc406Sopenharmony_ci powerOnDelay[channel] = dev->CIS.powerOnDelay[channel]; 1856141cc406Sopenharmony_ci dev->CIS.powerOnDelay[channel] = dev->CIS.exposeTime; 1857141cc406Sopenharmony_ci } 1858141cc406Sopenharmony_ci 1859141cc406Sopenharmony_ci DBG(3, "cis_normalize_ranges: Measuring low extremes\n"); 1860141cc406Sopenharmony_ci if (!cis_measure_extremes(dev, dev->calib_low, pixels, first, last)) { 1861141cc406Sopenharmony_ci return SANE_FALSE; 1862141cc406Sopenharmony_ci } 1863141cc406Sopenharmony_ci 1864141cc406Sopenharmony_ci /* Restore settings */ 1865141cc406Sopenharmony_ci for (channel=first; channel<=last; ++channel) { 1866141cc406Sopenharmony_ci dev->CIS.powerOnDelay[channel] = powerOnDelay[channel]; 1867141cc406Sopenharmony_ci } 1868141cc406Sopenharmony_ci 1869141cc406Sopenharmony_ci /* Make sure calib_hi is greater than calib_low */ 1870141cc406Sopenharmony_ci for (channel = first; channel <= last; ++channel) { 1871141cc406Sopenharmony_ci for (p = 0; p<pixels; p++) { 1872141cc406Sopenharmony_ci if (dev->calib_low[channel]) { 1873141cc406Sopenharmony_ci cal_low = dev->calib_low[channel][p]; 1874141cc406Sopenharmony_ci } else { 1875141cc406Sopenharmony_ci cal_low = 0; 1876141cc406Sopenharmony_ci } 1877141cc406Sopenharmony_ci if (dev->calib_hi[channel]) { 1878141cc406Sopenharmony_ci cal_hi = dev->calib_hi[channel][p]; 1879141cc406Sopenharmony_ci } else { 1880141cc406Sopenharmony_ci cal_hi = 255; 1881141cc406Sopenharmony_ci } 1882141cc406Sopenharmony_ci if (cal_hi <= cal_low) { 1883141cc406Sopenharmony_ci if(cal_hi<255) { 1884141cc406Sopenharmony_ci /* calib_hi exists, else cal_hi would be 255 */ 1885141cc406Sopenharmony_ci dev->calib_hi[channel][p] = cal_low+1; 1886141cc406Sopenharmony_ci } else { 1887141cc406Sopenharmony_ci /* calib_low exists, else cal_low would be 0, < 255 */ 1888141cc406Sopenharmony_ci dev->calib_low[channel][p] = cal_hi-1; 1889141cc406Sopenharmony_ci } 1890141cc406Sopenharmony_ci } 1891141cc406Sopenharmony_ci } 1892141cc406Sopenharmony_ci } 1893141cc406Sopenharmony_ci DBG(3, "cis_normalize_ranges: calibration done\n"); 1894141cc406Sopenharmony_ci return SANE_TRUE; 1895141cc406Sopenharmony_ci} 1896141cc406Sopenharmony_ci 1897141cc406Sopenharmony_ci/* 1898141cc406Sopenharmony_ci * This routine measures the time that we have to wait between reading 1899141cc406Sopenharmony_ci * to pixels from the scanner. Especially at low resolutions, but also 1900141cc406Sopenharmony_ci * for narrow-width scans at high resolutions, reading too fast cause 1901141cc406Sopenharmony_ci * color stability problems. 1902141cc406Sopenharmony_ci * This routine sends a test pattern to the scanner memory banks and tries 1903141cc406Sopenharmony_ci * to measure how fast it can be retrieved without errors. 1904141cc406Sopenharmony_ci * The same is done by the TWAIN driver (TESTIO.CPP:TestDelay). 1905141cc406Sopenharmony_ci */ 1906141cc406Sopenharmony_cistatic SANE_Bool 1907141cc406Sopenharmony_cicis_measure_delay(Mustek_PP_CIS_dev * dev) 1908141cc406Sopenharmony_ci{ 1909141cc406Sopenharmony_ci SANE_Byte buf[2][2048]; 1910141cc406Sopenharmony_ci unsigned i, j, d; 1911141cc406Sopenharmony_ci int saved_res; 1912141cc406Sopenharmony_ci SANE_Bool error = SANE_FALSE; 1913141cc406Sopenharmony_ci 1914141cc406Sopenharmony_ci CIS_CLEAR_FULLFLAG(dev); 1915141cc406Sopenharmony_ci CIS_CLEAR_WRITE_ADDR(dev); 1916141cc406Sopenharmony_ci CIS_CLEAR_WRITE_BANK(dev); 1917141cc406Sopenharmony_ci CIS_INC_READ(dev); 1918141cc406Sopenharmony_ci CIS_CLEAR_READ_BANK(dev); 1919141cc406Sopenharmony_ci 1920141cc406Sopenharmony_ci M1015_DISPLAY_REGS(dev, "Before delay measurement"); 1921141cc406Sopenharmony_ci assert(dev->CIS.adjustskip == 0); 1922141cc406Sopenharmony_ci 1923141cc406Sopenharmony_ci /* Sawtooth */ 1924141cc406Sopenharmony_ci for (i=0; i<2048; ++i) 1925141cc406Sopenharmony_ci { 1926141cc406Sopenharmony_ci buf[0][i] = i % 255; /* Why 255 ? Seems to have no real importance */ 1927141cc406Sopenharmony_ci } 1928141cc406Sopenharmony_ci 1929141cc406Sopenharmony_ci Mustek_PP_1015_write_reg_start(dev, MA1015W_SRAM_SOURCE_PC); 1930141cc406Sopenharmony_ci for (i=0; i<2048; ++i) 1931141cc406Sopenharmony_ci { 1932141cc406Sopenharmony_ci Mustek_PP_1015_write_reg_val(dev, buf[0][i]); 1933141cc406Sopenharmony_ci } 1934141cc406Sopenharmony_ci Mustek_PP_1015_write_reg_stop(dev); 1935141cc406Sopenharmony_ci 1936141cc406Sopenharmony_ci /* Bank offset measurement */ 1937141cc406Sopenharmony_ci dev->CIS.delay = 0; /* Initialize to zero, measure next */ 1938141cc406Sopenharmony_ci 1939141cc406Sopenharmony_ci saved_res = dev->CIS.res; 1940141cc406Sopenharmony_ci dev->CIS.res = dev->CIS.hw_hres; 1941141cc406Sopenharmony_ci 1942141cc406Sopenharmony_ci /* 1943141cc406Sopenharmony_ci * Note: the TWAIN driver seems to have a fast EPP mode too. That one is 1944141cc406Sopenharmony_ci * tried first, and then they try the normal mode. I haven't figured out 1945141cc406Sopenharmony_ci * yet how the fast mode works, so I'll only check the normal mode for now. 1946141cc406Sopenharmony_ci * Moreover, from the behaviour that I've witnessed from the TWAIN driver, 1947141cc406Sopenharmony_ci * I must conclude that the fast mode probably doesn't work on my computer, 1948141cc406Sopenharmony_ci * so I can't test it anyhow. 1949141cc406Sopenharmony_ci */ 1950141cc406Sopenharmony_ci /* Gradually increase the delay till we have no more errors */ 1951141cc406Sopenharmony_ci for (d = 0; d < 75 /* 255 */ && dev->desc->state != STATE_CANCELLED; d += 5) 1952141cc406Sopenharmony_ci { 1953141cc406Sopenharmony_ci dev->CIS.delay = d; 1954141cc406Sopenharmony_ci 1955141cc406Sopenharmony_ci /* 1956141cc406Sopenharmony_ci * We read the line 5 times to make sure that all garbage is flushed. 1957141cc406Sopenharmony_ci */ 1958141cc406Sopenharmony_ci for (i=0; i<5; ++i) 1959141cc406Sopenharmony_ci { 1960141cc406Sopenharmony_ci CIS_INC_READ(dev); 1961141cc406Sopenharmony_ci CIS_CLEAR_READ_BANK(dev); 1962141cc406Sopenharmony_ci cis_read_line_low_level (dev, &buf[1][0], 2048, NULL, NULL, NULL); 1963141cc406Sopenharmony_ci if (dev->desc->state == STATE_CANCELLED) return SANE_FALSE; 1964141cc406Sopenharmony_ci } 1965141cc406Sopenharmony_ci 1966141cc406Sopenharmony_ci error = SANE_FALSE; 1967141cc406Sopenharmony_ci /* Check 100 times whether we can read without errors. */ 1968141cc406Sopenharmony_ci for (i=0; i<100 && !error; ++i) 1969141cc406Sopenharmony_ci { 1970141cc406Sopenharmony_ci CIS_INC_READ(dev); 1971141cc406Sopenharmony_ci CIS_CLEAR_READ_BANK(dev); 1972141cc406Sopenharmony_ci cis_read_line_low_level (dev, &buf[1][0], 2048, NULL, NULL, NULL); 1973141cc406Sopenharmony_ci if (dev->desc->state == STATE_CANCELLED) return SANE_FALSE; 1974141cc406Sopenharmony_ci 1975141cc406Sopenharmony_ci for (j=0; j<2048; ++j) 1976141cc406Sopenharmony_ci { 1977141cc406Sopenharmony_ci if (buf[0][j] != buf[1][j]) 1978141cc406Sopenharmony_ci { 1979141cc406Sopenharmony_ci error = SANE_TRUE; 1980141cc406Sopenharmony_ci break; 1981141cc406Sopenharmony_ci } 1982141cc406Sopenharmony_ci } 1983141cc406Sopenharmony_ci } 1984141cc406Sopenharmony_ci 1985141cc406Sopenharmony_ci DBG (3, "cis_measure_delay: delay %d\n", dev->CIS.delay); 1986141cc406Sopenharmony_ci if (!error) 1987141cc406Sopenharmony_ci break; 1988141cc406Sopenharmony_ci } 1989141cc406Sopenharmony_ci 1990141cc406Sopenharmony_ci dev->CIS.res = saved_res; 1991141cc406Sopenharmony_ci 1992141cc406Sopenharmony_ci if (error) 1993141cc406Sopenharmony_ci { 1994141cc406Sopenharmony_ci fprintf(stderr, "mustek_pp_cis: failed to measure delay.\n"); 1995141cc406Sopenharmony_ci fprintf(stderr, "Buffer contents:\n"); 1996141cc406Sopenharmony_ci for (j = 0; j < 20; ++j) 1997141cc406Sopenharmony_ci { 1998141cc406Sopenharmony_ci fprintf(stderr, "%d ", buf[1][j]); 1999141cc406Sopenharmony_ci } 2000141cc406Sopenharmony_ci fprintf(stderr, "\n"); 2001141cc406Sopenharmony_ci dev->CIS.delay = 0; 2002141cc406Sopenharmony_ci } 2003141cc406Sopenharmony_ci 2004141cc406Sopenharmony_ci DBG (3, "cis_measure_delay: delay %d\n", dev->CIS.delay); 2005141cc406Sopenharmony_ci return SANE_TRUE; 2006141cc406Sopenharmony_ci} 2007141cc406Sopenharmony_ci 2008141cc406Sopenharmony_cistatic void 2009141cc406Sopenharmony_cicis_motor_control (Mustek_PP_CIS_dev * dev, u_char control) 2010141cc406Sopenharmony_ci{ 2011141cc406Sopenharmony_ci cis_wait_motor_stable (dev); 2012141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(dev, MA1015W_MOTOR_CONTROL, control); 2013141cc406Sopenharmony_ci} 2014141cc406Sopenharmony_ci 2015141cc406Sopenharmony_cistatic void 2016141cc406Sopenharmony_cicis_return_home (Mustek_PP_CIS_dev * dev, SANE_Bool nowait) 2017141cc406Sopenharmony_ci{ 2018141cc406Sopenharmony_ci SANE_Byte savedExposeTime = dev->CIS.exposeTime; 2019141cc406Sopenharmony_ci DBG(4, "cis_return_home: returning home; nowait: %d\n", nowait); 2020141cc406Sopenharmony_ci /* During a return-home, the expose time is fixed. */ 2021141cc406Sopenharmony_ci dev->CIS.exposeTime = 170; 2022141cc406Sopenharmony_ci cis_config_ccd(dev); 2023141cc406Sopenharmony_ci dev->CIS.exposeTime = savedExposeTime; 2024141cc406Sopenharmony_ci 2025141cc406Sopenharmony_ci cis_motor_control (dev, 0xEB); 2026141cc406Sopenharmony_ci 2027141cc406Sopenharmony_ci if (nowait == SANE_FALSE) 2028141cc406Sopenharmony_ci Mustek_PP_1015_wait_bit(dev, MA1015R_MOTOR, MA1015B_MOTOR_HOME, 2029141cc406Sopenharmony_ci SANE_TRUE, 1000); 2030141cc406Sopenharmony_ci} 2031141cc406Sopenharmony_ci 2032141cc406Sopenharmony_ci/****************************************************************************** 2033141cc406Sopenharmony_ci * Does a full reset of the device, ie. configures the CIS to a default 2034141cc406Sopenharmony_ci * resolution of 300 DPI (in high or low resolution mode, depending on the 2035141cc406Sopenharmony_ci * resolution requested by the user). 2036141cc406Sopenharmony_ci *****************************************************************************/ 2037141cc406Sopenharmony_cistatic void 2038141cc406Sopenharmony_cicis_reset_device (Mustek_PP_CIS_dev * dev) 2039141cc406Sopenharmony_ci{ 2040141cc406Sopenharmony_ci DBG(4, "cis_reset_device: resetting device\n"); 2041141cc406Sopenharmony_ci dev->CIS.adjustskip = 0; 2042141cc406Sopenharmony_ci dev->CIS.dontIncRead = SANE_TRUE; 2043141cc406Sopenharmony_ci dev->CIS.dontMove = SANE_FALSE; 2044141cc406Sopenharmony_ci 2045141cc406Sopenharmony_ci cis_save_state(dev); 2046141cc406Sopenharmony_ci 2047141cc406Sopenharmony_ci dev->CIS.hw_hres = 300; 2048141cc406Sopenharmony_ci dev->CIS.channel = MUSTEK_PP_CIS_CHANNEL_GREEN; 2049141cc406Sopenharmony_ci dev->CIS.setParameters = SANE_FALSE; 2050141cc406Sopenharmony_ci dev->CIS.exposeTime = 0xAA; 2051141cc406Sopenharmony_ci 2052141cc406Sopenharmony_ci cis_config_ccd (dev); 2053141cc406Sopenharmony_ci 2054141cc406Sopenharmony_ci cis_restore_state(dev); 2055141cc406Sopenharmony_ci 2056141cc406Sopenharmony_ci} 2057141cc406Sopenharmony_ci 2058141cc406Sopenharmony_cistatic SANE_Bool 2059141cc406Sopenharmony_cicis_calibrate (Mustek_PP_CIS_dev * dev) 2060141cc406Sopenharmony_ci{ 2061141cc406Sopenharmony_ci int i, saved_res = dev->CIS.res, saved_vres = dev->CIS.hw_vres; 2062141cc406Sopenharmony_ci 2063141cc406Sopenharmony_ci /* 2064141cc406Sopenharmony_ci * Flow of operation observed from the twain driver 2065141cc406Sopenharmony_ci * (it is assumed that the lamp is at the origin, and that the CIS is 2066141cc406Sopenharmony_ci * configured for 300 DPI, ie. cis_reset_device has been called.) 2067141cc406Sopenharmony_ci * 2068141cc406Sopenharmony_ci * - Reset the device and return the lamp to its home position 2069141cc406Sopenharmony_ci * 2070141cc406Sopenharmony_ci * - Unknown short sequence 2071141cc406Sopenharmony_ci * 2072141cc406Sopenharmony_ci * - Send a sawtooth-like pattern to one of the memory banks. 2073141cc406Sopenharmony_ci * 2074141cc406Sopenharmony_ci * - Repetitive read_line of 2048 bytes, interleaved with an unknown 2075141cc406Sopenharmony_ci * command. The number varies between 102 and 170 times, but there 2076141cc406Sopenharmony_ci * doesn't seem to be any correlation with the current mode of the 2077141cc406Sopenharmony_ci * scanner, so I assume that the exact number isn't really relevant. 2078141cc406Sopenharmony_ci * The values that are read are the one that were sent to the bank, 2079141cc406Sopenharmony_ci * rotated by 1 byte in my case. 2080141cc406Sopenharmony_ci * 2081141cc406Sopenharmony_ci * 2082141cc406Sopenharmony_ci * It seems that the width of the black border is being measured at 2083141cc406Sopenharmony_ci * this stage, possibly multiple times till it stabilizes. 2084141cc406Sopenharmony_ci * I assume that the buffer is read 100 times to allow the lamp to 2085141cc406Sopenharmony_ci * warm up and that the width of the black border is then being 2086141cc406Sopenharmony_ci * measured till it stabilizes. That would explain the minimum number 2087141cc406Sopenharmony_ci * of 102 iterations that I've seen. 2088141cc406Sopenharmony_ci * 2089141cc406Sopenharmony_ci * - reset the device 2090141cc406Sopenharmony_ci * 2091141cc406Sopenharmony_ci * - move the motor 110 steps forward. The TWAIN driver moves 90 steps, 2092141cc406Sopenharmony_ci * and I've used 90 steps for a long time too, but occasionally, 2093141cc406Sopenharmony_ci * 90 steps is a fraction to short to reach the start of the 2094141cc406Sopenharmony_ci * calibration strip (the motor movements are not very accurate; 2095141cc406Sopenharmony_ci * an offset of 1 mm is not unusual). Therefore, I've increased it to 2096141cc406Sopenharmony_ci * 110 steps. This gives us an additional 1.6 mm slack, which should 2097141cc406Sopenharmony_ci * prevent calibration errors. 2098141cc406Sopenharmony_ci * (Note that the MUSTEK_PP_CIS_????CP_DEFAULT_SKIP constants have to 2099141cc406Sopenharmony_ci * be adjusted if the number of steps is altered.) 2100141cc406Sopenharmony_ci * 2101141cc406Sopenharmony_ci * - configure the CIS : actual resolution + set parameters 2102141cc406Sopenharmony_ci * 2103141cc406Sopenharmony_ci */ 2104141cc406Sopenharmony_ci 2105141cc406Sopenharmony_ci /* 2106141cc406Sopenharmony_ci * We must make sure that we are in the scanning state; otherwise we may 2107141cc406Sopenharmony_ci * still be in the canceled state from a previous scan (even if terminated 2108141cc406Sopenharmony_ci * normally), and the whole calibration would go wrong. 2109141cc406Sopenharmony_ci */ 2110141cc406Sopenharmony_ci dev->desc->state = STATE_SCANNING; 2111141cc406Sopenharmony_ci 2112141cc406Sopenharmony_ci cis_reset_device (dev); 2113141cc406Sopenharmony_ci cis_return_home (dev, SANE_FALSE); /* Wait till it's home */ 2114141cc406Sopenharmony_ci 2115141cc406Sopenharmony_ci /* Use maximum resolution during calibration; otherwise we may calibrate 2116141cc406Sopenharmony_ci past the calibration strip. */ 2117141cc406Sopenharmony_ci dev->CIS.hw_vres = dev->desc->dev->maxres; 2118141cc406Sopenharmony_ci /* This field remembers how many steps we still have to go @ max res */ 2119141cc406Sopenharmony_ci dev->CIS.skipsToOrigin = dev->top_skip; /*max2hw_vres(dev, dev->top_skip); */ 2120141cc406Sopenharmony_ci 2121141cc406Sopenharmony_ci if (!cis_measure_delay(dev)) 2122141cc406Sopenharmony_ci return SANE_FALSE; 2123141cc406Sopenharmony_ci 2124141cc406Sopenharmony_ci cis_reset_device (dev); 2125141cc406Sopenharmony_ci 2126141cc406Sopenharmony_ci /* Move motor 110 steps @ 300 DPI */ 2127141cc406Sopenharmony_ci Mustek_PP_1015_write_reg_start(dev, MA1015W_MOTOR_CONTROL); 2128141cc406Sopenharmony_ci for (i=0; i<110; ++i) 2129141cc406Sopenharmony_ci { 2130141cc406Sopenharmony_ci if (dev->model == MUSTEK_PP_CIS600) 2131141cc406Sopenharmony_ci { 2132141cc406Sopenharmony_ci Mustek_PP_1015_write_reg_val (dev, 0x73); 2133141cc406Sopenharmony_ci } 2134141cc406Sopenharmony_ci else 2135141cc406Sopenharmony_ci { 2136141cc406Sopenharmony_ci Mustek_PP_1015_write_reg_val (dev, 0x7B); 2137141cc406Sopenharmony_ci } 2138141cc406Sopenharmony_ci cis_wait_motor_stable (dev); 2139141cc406Sopenharmony_ci } 2140141cc406Sopenharmony_ci Mustek_PP_1015_write_reg_stop(dev); 2141141cc406Sopenharmony_ci 2142141cc406Sopenharmony_ci /* Next, we maximize the dynamic range of the scanner. During calibration 2143141cc406Sopenharmony_ci we don't want to extrapolate, so we limit the resolution if necessary */ 2144141cc406Sopenharmony_ci 2145141cc406Sopenharmony_ci if (dev->CIS.hw_hres < dev->CIS.res) 2146141cc406Sopenharmony_ci dev->CIS.res = dev->CIS.hw_hres; 2147141cc406Sopenharmony_ci 2148141cc406Sopenharmony_ci if (!cis_maximize_dynamic_range(dev)) 2149141cc406Sopenharmony_ci return SANE_FALSE; 2150141cc406Sopenharmony_ci 2151141cc406Sopenharmony_ci if (!cis_normalize_ranges(dev)) 2152141cc406Sopenharmony_ci return SANE_FALSE; 2153141cc406Sopenharmony_ci 2154141cc406Sopenharmony_ci dev->CIS.res = saved_res; 2155141cc406Sopenharmony_ci dev->CIS.hw_vres = saved_vres; 2156141cc406Sopenharmony_ci 2157141cc406Sopenharmony_ci /* Convert steps back to max res size, which are used during skipping */ 2158141cc406Sopenharmony_ci/* dev->CIS.skipsToOrigin = hw2max_vres(dev, dev->CIS.skipsToOrigin); */ 2159141cc406Sopenharmony_ci 2160141cc406Sopenharmony_ci /* Move to the origin */ 2161141cc406Sopenharmony_ci DBG(3, "cis_calibrate: remaining skips to origin @maxres: %d\n", 2162141cc406Sopenharmony_ci dev->CIS.skipsToOrigin); 2163141cc406Sopenharmony_ci cis_move_motor(dev, dev->CIS.skipsToOrigin); 2164141cc406Sopenharmony_ci 2165141cc406Sopenharmony_ci if (dev->calib_mode) 2166141cc406Sopenharmony_ci { 2167141cc406Sopenharmony_ci /* In calibration mode, we scan the interior of the scanner before the 2168141cc406Sopenharmony_ci glass plate in order to find the position of the calibration strip 2169141cc406Sopenharmony_ci and the start of the glass plate. */ 2170141cc406Sopenharmony_ci DBG(3, "cis_calibrate: running in calibration mode. Returning home.\n"); 2171141cc406Sopenharmony_ci cis_return_home (dev, SANE_FALSE); /* Wait till it's home */ 2172141cc406Sopenharmony_ci } 2173141cc406Sopenharmony_ci 2174141cc406Sopenharmony_ci return dev->desc->state != STATE_CANCELLED ? SANE_TRUE : SANE_FALSE; 2175141cc406Sopenharmony_ci 2176141cc406Sopenharmony_ci} 2177141cc406Sopenharmony_ci 2178141cc406Sopenharmony_ci/****************************************************************************** 2179141cc406Sopenharmony_ci ****************************************************************************** 2180141cc406Sopenharmony_ci *** Mustek PP interface *** 2181141cc406Sopenharmony_ci ****************************************************************************** 2182141cc406Sopenharmony_ci *****************************************************************************/ 2183141cc406Sopenharmony_ci 2184141cc406Sopenharmony_ci/****************************************************************************** 2185141cc406Sopenharmony_ci* Init * 2186141cc406Sopenharmony_ci******************************************************************************/ 2187141cc406Sopenharmony_ci 2188141cc406Sopenharmony_ci/* Shared initialization routine */ 2189141cc406Sopenharmony_cistatic SANE_Status cis_attach(SANE_String_Const port, 2190141cc406Sopenharmony_ci SANE_String_Const name, 2191141cc406Sopenharmony_ci SANE_Attach_Callback attach, 2192141cc406Sopenharmony_ci SANE_Int driverNo, 2193141cc406Sopenharmony_ci SANE_Int info) 2194141cc406Sopenharmony_ci{ 2195141cc406Sopenharmony_ci int fd; 2196141cc406Sopenharmony_ci SANE_Status status; 2197141cc406Sopenharmony_ci u_char asic; 2198141cc406Sopenharmony_ci 2199141cc406Sopenharmony_ci status = sanei_pa4s2_open (port, &fd); 2200141cc406Sopenharmony_ci 2201141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2202141cc406Sopenharmony_ci { 2203141cc406Sopenharmony_ci SANE_Status altStatus; 2204141cc406Sopenharmony_ci SANE_String_Const altPort; 2205141cc406Sopenharmony_ci 2206141cc406Sopenharmony_ci DBG (2, "cis_attach: couldn't attach to `%s' (%s)\n", port, 2207141cc406Sopenharmony_ci sane_strstatus (status)); 2208141cc406Sopenharmony_ci 2209141cc406Sopenharmony_ci /* Make migration to libieee1284 painless for users that used 2210141cc406Sopenharmony_ci direct io in the past */ 2211141cc406Sopenharmony_ci if (strcmp(port, "0x378") == 0) altPort = "parport0"; 2212141cc406Sopenharmony_ci else if (strcmp(port, "0x278") == 0) altPort = "parport1"; 2213141cc406Sopenharmony_ci else if (strcmp(port, "0x3BC") == 0) altPort = "parport2"; 2214141cc406Sopenharmony_ci else return status; 2215141cc406Sopenharmony_ci 2216141cc406Sopenharmony_ci DBG (2, "cis_attach: trying alternative port name: %s\n", altPort); 2217141cc406Sopenharmony_ci 2218141cc406Sopenharmony_ci altStatus = sanei_pa4s2_open (altPort, &fd); 2219141cc406Sopenharmony_ci if (altStatus != SANE_STATUS_GOOD) 2220141cc406Sopenharmony_ci { 2221141cc406Sopenharmony_ci DBG (2, "cis_attach: couldn't attach to alternative port `%s' " 2222141cc406Sopenharmony_ci "(%s)\n", altPort, sane_strstatus (altStatus)); 2223141cc406Sopenharmony_ci return status; /* Return original status, not alternative status */ 2224141cc406Sopenharmony_ci } 2225141cc406Sopenharmony_ci } 2226141cc406Sopenharmony_ci 2227141cc406Sopenharmony_ci M1015_START_LL; 2228141cc406Sopenharmony_ci M1015_START_HL; 2229141cc406Sopenharmony_ci 2230141cc406Sopenharmony_ci 2231141cc406Sopenharmony_ci sanei_pa4s2_enable (fd, SANE_TRUE); 2232141cc406Sopenharmony_ci SANEI_PA4S2_READBEGIN (fd, 0); 2233141cc406Sopenharmony_ci SANEI_PA4S2_READBYTE (fd, &asic); 2234141cc406Sopenharmony_ci SANEI_PA4S2_READEND (fd); 2235141cc406Sopenharmony_ci sanei_pa4s2_enable (fd, SANE_FALSE); 2236141cc406Sopenharmony_ci 2237141cc406Sopenharmony_ci sanei_pa4s2_close (fd); 2238141cc406Sopenharmony_ci 2239141cc406Sopenharmony_ci if (asic != 0xA5) /* Identifies the MA1015 chipset */ 2240141cc406Sopenharmony_ci { 2241141cc406Sopenharmony_ci /* CIS driver only works for MA1015 chipset */ 2242141cc406Sopenharmony_ci DBG (2, "cis_attach: asic id (0x%02x) not recognized\n", asic); 2243141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2244141cc406Sopenharmony_ci } 2245141cc406Sopenharmony_ci 2246141cc406Sopenharmony_ci DBG (3, "cis_attach: device %s attached\n", name); 2247141cc406Sopenharmony_ci DBG (3, "cis_attach: asic 0x%02x\n", asic); 2248141cc406Sopenharmony_ci 2249141cc406Sopenharmony_ci return attach(port, name, driverNo, info); 2250141cc406Sopenharmony_ci} 2251141cc406Sopenharmony_ci 2252141cc406Sopenharmony_ciSANE_Status cis600_drv_init(SANE_Int options, SANE_String_Const port, 2253141cc406Sopenharmony_ci SANE_String_Const name, SANE_Attach_Callback attach) 2254141cc406Sopenharmony_ci{ 2255141cc406Sopenharmony_ci if (options != CAP_NOTHING) 2256141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2257141cc406Sopenharmony_ci 2258141cc406Sopenharmony_ci return cis_attach(port, name, attach, MUSTEK_PP_CIS600, MUSTEK_PP_CIS600); 2259141cc406Sopenharmony_ci} 2260141cc406Sopenharmony_ci 2261141cc406Sopenharmony_ciSANE_Status cis1200_drv_init(SANE_Int options, SANE_String_Const port, 2262141cc406Sopenharmony_ci SANE_String_Const name, SANE_Attach_Callback attach) 2263141cc406Sopenharmony_ci{ 2264141cc406Sopenharmony_ci if (options != CAP_NOTHING) 2265141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2266141cc406Sopenharmony_ci 2267141cc406Sopenharmony_ci return cis_attach(port, name, attach, MUSTEK_PP_CIS1200, MUSTEK_PP_CIS1200); 2268141cc406Sopenharmony_ci} 2269141cc406Sopenharmony_ci 2270141cc406Sopenharmony_ciSANE_Status cis1200p_drv_init(SANE_Int options, SANE_String_Const port, 2271141cc406Sopenharmony_ci SANE_String_Const name, SANE_Attach_Callback attach) 2272141cc406Sopenharmony_ci{ 2273141cc406Sopenharmony_ci if (options != CAP_NOTHING) 2274141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2275141cc406Sopenharmony_ci 2276141cc406Sopenharmony_ci return cis_attach(port, name, attach, MUSTEK_PP_CIS1200PLUS, MUSTEK_PP_CIS1200PLUS); 2277141cc406Sopenharmony_ci} 2278141cc406Sopenharmony_ci 2279141cc406Sopenharmony_ci/****************************************************************************** 2280141cc406Sopenharmony_ci* Capabilities * 2281141cc406Sopenharmony_ci******************************************************************************/ 2282141cc406Sopenharmony_civoid cis_drv_capabilities(SANE_Int info, SANE_String *model, 2283141cc406Sopenharmony_ci SANE_String *vendor, SANE_String *type, 2284141cc406Sopenharmony_ci SANE_Int *maxres, SANE_Int *minres, 2285141cc406Sopenharmony_ci SANE_Int *maxhsize, SANE_Int *maxvsize, 2286141cc406Sopenharmony_ci SANE_Int *caps) 2287141cc406Sopenharmony_ci{ 2288141cc406Sopenharmony_ci *vendor = strdup("Mustek"); 2289141cc406Sopenharmony_ci *type = strdup("flatbed scanner"); 2290141cc406Sopenharmony_ci *caps = CAP_NOTHING; 2291141cc406Sopenharmony_ci 2292141cc406Sopenharmony_ci switch(info) 2293141cc406Sopenharmony_ci { 2294141cc406Sopenharmony_ci case MUSTEK_PP_CIS600: 2295141cc406Sopenharmony_ci *model = strdup("600CP"); 2296141cc406Sopenharmony_ci *maxres = 600; 2297141cc406Sopenharmony_ci *minres = 50; 2298141cc406Sopenharmony_ci *maxhsize = MUSTEK_PP_CIS_MAX_H_PIXEL; 2299141cc406Sopenharmony_ci *maxvsize = MUSTEK_PP_CIS_MAX_V_PIXEL; 2300141cc406Sopenharmony_ci break; 2301141cc406Sopenharmony_ci case MUSTEK_PP_CIS1200: 2302141cc406Sopenharmony_ci *model = strdup("1200CP"); 2303141cc406Sopenharmony_ci *maxres = 1200; 2304141cc406Sopenharmony_ci *minres = 50; 2305141cc406Sopenharmony_ci *maxhsize = MUSTEK_PP_CIS_MAX_H_PIXEL*2; 2306141cc406Sopenharmony_ci *maxvsize = MUSTEK_PP_CIS_MAX_V_PIXEL*2; 2307141cc406Sopenharmony_ci break; 2308141cc406Sopenharmony_ci case MUSTEK_PP_CIS1200PLUS: 2309141cc406Sopenharmony_ci *model = strdup("1200CP+"); 2310141cc406Sopenharmony_ci *maxres = 1200; 2311141cc406Sopenharmony_ci *minres = 50; 2312141cc406Sopenharmony_ci *maxhsize = MUSTEK_PP_CIS_MAX_H_PIXEL*2; 2313141cc406Sopenharmony_ci *maxvsize = MUSTEK_PP_CIS_MAX_V_PIXEL*2; 2314141cc406Sopenharmony_ci break; 2315141cc406Sopenharmony_ci } 2316141cc406Sopenharmony_ci} 2317141cc406Sopenharmony_ci 2318141cc406Sopenharmony_ci/****************************************************************************** 2319141cc406Sopenharmony_ci* Open * 2320141cc406Sopenharmony_ci******************************************************************************/ 2321141cc406Sopenharmony_ciSANE_Status cis_drv_open (SANE_String port, SANE_Int caps, SANE_Int *fd) 2322141cc406Sopenharmony_ci{ 2323141cc406Sopenharmony_ci SANE_Status status; 2324141cc406Sopenharmony_ci 2325141cc406Sopenharmony_ci if (caps != CAP_NOTHING) 2326141cc406Sopenharmony_ci { 2327141cc406Sopenharmony_ci DBG (1, "cis_drv_open: called with unknown capabilities (0x%02X)\n", caps); 2328141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2329141cc406Sopenharmony_ci } 2330141cc406Sopenharmony_ci 2331141cc406Sopenharmony_ci DBG (3, "cis_drv_open: called for port %s\n", port); 2332141cc406Sopenharmony_ci 2333141cc406Sopenharmony_ci status = sanei_pa4s2_open (port, fd); 2334141cc406Sopenharmony_ci 2335141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2336141cc406Sopenharmony_ci { 2337141cc406Sopenharmony_ci SANE_Status altStatus; 2338141cc406Sopenharmony_ci SANE_String_Const altPort; 2339141cc406Sopenharmony_ci 2340141cc406Sopenharmony_ci DBG (2, "cis_attach: couldn't attach to `%s' (%s)\n", port, 2341141cc406Sopenharmony_ci sane_strstatus (status)); 2342141cc406Sopenharmony_ci 2343141cc406Sopenharmony_ci /* Make migration to libieee1284 painless for users that used 2344141cc406Sopenharmony_ci direct io in the past */ 2345141cc406Sopenharmony_ci if (strcmp(port, "0x378") == 0) altPort = "parport0"; 2346141cc406Sopenharmony_ci else if (strcmp(port, "0x278") == 0) altPort = "parport1"; 2347141cc406Sopenharmony_ci else if (strcmp(port, "0x3BC") == 0) altPort = "parport2"; 2348141cc406Sopenharmony_ci else return status; 2349141cc406Sopenharmony_ci 2350141cc406Sopenharmony_ci DBG (2, "cis_attach: trying alternative port name: %s\n", altPort); 2351141cc406Sopenharmony_ci 2352141cc406Sopenharmony_ci altStatus = sanei_pa4s2_open (altPort, fd); 2353141cc406Sopenharmony_ci if (altStatus != SANE_STATUS_GOOD) 2354141cc406Sopenharmony_ci { 2355141cc406Sopenharmony_ci DBG (2, "cis_attach: couldn't attach to alternative port `%s' " 2356141cc406Sopenharmony_ci "(%s)\n", altPort, sane_strstatus (altStatus)); 2357141cc406Sopenharmony_ci return status; /* Return original status, not alternative status */ 2358141cc406Sopenharmony_ci } 2359141cc406Sopenharmony_ci } 2360141cc406Sopenharmony_ci 2361141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2362141cc406Sopenharmony_ci} 2363141cc406Sopenharmony_ci 2364141cc406Sopenharmony_ci/****************************************************************************** 2365141cc406Sopenharmony_ci* Setup * 2366141cc406Sopenharmony_ci******************************************************************************/ 2367141cc406Sopenharmony_civoid cis_drv_setup (SANE_Handle hndl) 2368141cc406Sopenharmony_ci{ 2369141cc406Sopenharmony_ci Mustek_pp_Handle *dev = hndl; 2370141cc406Sopenharmony_ci Mustek_PP_CIS_dev *cisdev; 2371141cc406Sopenharmony_ci cisdev = (Mustek_PP_CIS_dev*)malloc(sizeof(Mustek_PP_CIS_dev)); 2372141cc406Sopenharmony_ci if (cisdev == NULL) 2373141cc406Sopenharmony_ci { 2374141cc406Sopenharmony_ci DBG (2, "cis_drv_setup: not enough memory for device descriptor\n"); 2375141cc406Sopenharmony_ci sanei_pa4s2_close (dev->fd); 2376141cc406Sopenharmony_ci return; 2377141cc406Sopenharmony_ci } 2378141cc406Sopenharmony_ci memset(cisdev, 0, sizeof(Mustek_PP_CIS_dev)); 2379141cc406Sopenharmony_ci DBG(3, "cis_drv_setup: cis device allocated\n"); 2380141cc406Sopenharmony_ci 2381141cc406Sopenharmony_ci dev->lamp_on = 0; 2382141cc406Sopenharmony_ci dev->priv = cisdev; 2383141cc406Sopenharmony_ci 2384141cc406Sopenharmony_ci cisdev->desc = dev; 2385141cc406Sopenharmony_ci cisdev->model = dev->dev->info; 2386141cc406Sopenharmony_ci cisdev->CIS.hw_hres = 300; 2387141cc406Sopenharmony_ci cisdev->CIS.cisRes = 300; 2388141cc406Sopenharmony_ci cisdev->CIS.hw_vres = 300; 2389141cc406Sopenharmony_ci 2390141cc406Sopenharmony_ci /* Default values for configurable parameters; configuration file 2391141cc406Sopenharmony_ci may override them. */ 2392141cc406Sopenharmony_ci cisdev->fast_skip = SANE_TRUE; 2393141cc406Sopenharmony_ci cisdev->bw_limit = 127; 2394141cc406Sopenharmony_ci cisdev->calib_mode = SANE_FALSE; 2395141cc406Sopenharmony_ci cisdev->engine_delay = 0; 2396141cc406Sopenharmony_ci if (cisdev->model == MUSTEK_PP_CIS600) 2397141cc406Sopenharmony_ci { 2398141cc406Sopenharmony_ci cisdev->top_skip = MUSTEK_PP_CIS_600CP_DEFAULT_SKIP; 2399141cc406Sopenharmony_ci } 2400141cc406Sopenharmony_ci else 2401141cc406Sopenharmony_ci { 2402141cc406Sopenharmony_ci cisdev->top_skip = MUSTEK_PP_CIS_1200CP_DEFAULT_SKIP; 2403141cc406Sopenharmony_ci } 2404141cc406Sopenharmony_ci} 2405141cc406Sopenharmony_ci 2406141cc406Sopenharmony_ci/****************************************************************************** 2407141cc406Sopenharmony_ci* Config * 2408141cc406Sopenharmony_ci******************************************************************************/ 2409141cc406Sopenharmony_ciSANE_Status cis_drv_config(SANE_Handle hndl, SANE_String_Const optname, 2410141cc406Sopenharmony_ci SANE_String_Const optval) 2411141cc406Sopenharmony_ci{ 2412141cc406Sopenharmony_ci Mustek_pp_Handle *dev = hndl; 2413141cc406Sopenharmony_ci Mustek_PP_CIS_dev *cisdev = dev->priv; 2414141cc406Sopenharmony_ci int value = 0; 2415141cc406Sopenharmony_ci double dvalue = 0; 2416141cc406Sopenharmony_ci DBG (3, "cis_drv_cfg option: %s=%s\n", optname, optval ? optval : ""); 2417141cc406Sopenharmony_ci if (!strcmp(optname, "top_adjust")) 2418141cc406Sopenharmony_ci { 2419141cc406Sopenharmony_ci if (!optval) 2420141cc406Sopenharmony_ci { 2421141cc406Sopenharmony_ci DBG (1, "cis_drv_config: missing value for option top_adjust\n"); 2422141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2423141cc406Sopenharmony_ci } 2424141cc406Sopenharmony_ci dvalue = atof(optval); 2425141cc406Sopenharmony_ci 2426141cc406Sopenharmony_ci /* An adjustment of +/- 5 mm should be sufficient and safe */ 2427141cc406Sopenharmony_ci if (dvalue < -5.0) 2428141cc406Sopenharmony_ci { 2429141cc406Sopenharmony_ci DBG (1, "cis_drv_config: value for option top_adjust too small: " 2430141cc406Sopenharmony_ci "%.2f < -5; limiting to -5 mm\n", dvalue); 2431141cc406Sopenharmony_ci dvalue = -5.0; 2432141cc406Sopenharmony_ci } 2433141cc406Sopenharmony_ci if (dvalue > 5.0) 2434141cc406Sopenharmony_ci { 2435141cc406Sopenharmony_ci DBG (1, "cis_drv_config: value for option top_adjust too large: " 2436141cc406Sopenharmony_ci "%.2f > 5; limiting to 5 mm\n", dvalue); 2437141cc406Sopenharmony_ci dvalue = 5.0; 2438141cc406Sopenharmony_ci } 2439141cc406Sopenharmony_ci /* In practice, there is a lower bound on the value that can be used, 2440141cc406Sopenharmony_ci but if the top_skip value is smaller than that value, the only result 2441141cc406Sopenharmony_ci will be that the driver tries to move the head a negative number 2442141cc406Sopenharmony_ci of steps after calibration. The move routine just ignores negative 2443141cc406Sopenharmony_ci steps, so no harm can be done. */ 2444141cc406Sopenharmony_ci cisdev->top_skip += MM_TO_PIXEL(dvalue, dev->dev->maxres); 2445141cc406Sopenharmony_ci DBG (3, "cis_drv_config: setting top skip value to %d\n", 2446141cc406Sopenharmony_ci cisdev->top_skip); 2447141cc406Sopenharmony_ci 2448141cc406Sopenharmony_ci /* Just to be cautious; we don't want the head to hit the bottom */ 2449141cc406Sopenharmony_ci if (cisdev->top_skip > 600) cisdev->top_skip = 600; 2450141cc406Sopenharmony_ci if (cisdev->top_skip < -600) cisdev->top_skip = -600; 2451141cc406Sopenharmony_ci } 2452141cc406Sopenharmony_ci else if (!strcmp(optname, "slow_skip")) 2453141cc406Sopenharmony_ci { 2454141cc406Sopenharmony_ci if (optval) 2455141cc406Sopenharmony_ci { 2456141cc406Sopenharmony_ci DBG (1, "cis_drv_config: unexpected value for option slow_skip\n"); 2457141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2458141cc406Sopenharmony_ci } 2459141cc406Sopenharmony_ci DBG (3, "cis_drv_config: disabling fast skipping\n"); 2460141cc406Sopenharmony_ci cisdev->fast_skip = SANE_FALSE; 2461141cc406Sopenharmony_ci } 2462141cc406Sopenharmony_ci else if (!strcmp(optname, "bw")) 2463141cc406Sopenharmony_ci { 2464141cc406Sopenharmony_ci if (!optval) 2465141cc406Sopenharmony_ci { 2466141cc406Sopenharmony_ci DBG (1, "cis_drv_config: missing value for option bw\n"); 2467141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2468141cc406Sopenharmony_ci } 2469141cc406Sopenharmony_ci value = atoi(optval); 2470141cc406Sopenharmony_ci if (value < 0 || value > 255) 2471141cc406Sopenharmony_ci { 2472141cc406Sopenharmony_ci DBG (1, "cis_drv_config: value for option bw out of range: " 2473141cc406Sopenharmony_ci "%d < 0 or %d > 255\n", value, value); 2474141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2475141cc406Sopenharmony_ci } 2476141cc406Sopenharmony_ci cisdev->bw_limit = value; 2477141cc406Sopenharmony_ci } 2478141cc406Sopenharmony_ci else if (!strcmp(optname, "calibration_mode")) 2479141cc406Sopenharmony_ci { 2480141cc406Sopenharmony_ci if (optval) 2481141cc406Sopenharmony_ci { 2482141cc406Sopenharmony_ci DBG (1, "cis_drv_config: unexpected value for option calibration_mode\n"); 2483141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2484141cc406Sopenharmony_ci } 2485141cc406Sopenharmony_ci DBG (3, "cis_drv_config: using calibration mode\n"); 2486141cc406Sopenharmony_ci cisdev->calib_mode = SANE_TRUE; 2487141cc406Sopenharmony_ci } 2488141cc406Sopenharmony_ci else if (!strcmp(optname, "engine_delay")) 2489141cc406Sopenharmony_ci { 2490141cc406Sopenharmony_ci if (!optval) 2491141cc406Sopenharmony_ci { 2492141cc406Sopenharmony_ci DBG (1, "cis_drv_config: missing value for option engine_delay\n"); 2493141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2494141cc406Sopenharmony_ci } 2495141cc406Sopenharmony_ci value = atoi(optval); 2496141cc406Sopenharmony_ci if (value < 0 || value > 100) /* 100 ms is already pretty slow */ 2497141cc406Sopenharmony_ci { 2498141cc406Sopenharmony_ci DBG (1, "cis_drv_config: value for option engine_delay out of range: " 2499141cc406Sopenharmony_ci "%d < 0 or %d > 100\n", value, value); 2500141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2501141cc406Sopenharmony_ci } 2502141cc406Sopenharmony_ci cisdev->engine_delay = value; 2503141cc406Sopenharmony_ci } 2504141cc406Sopenharmony_ci else 2505141cc406Sopenharmony_ci { 2506141cc406Sopenharmony_ci DBG (1, "cis_drv_config: unknown options %s\n", optname); 2507141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 2508141cc406Sopenharmony_ci } 2509141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2510141cc406Sopenharmony_ci} 2511141cc406Sopenharmony_ci 2512141cc406Sopenharmony_ci/****************************************************************************** 2513141cc406Sopenharmony_ci* Close * 2514141cc406Sopenharmony_ci******************************************************************************/ 2515141cc406Sopenharmony_civoid cis_drv_close (SANE_Handle hndl) 2516141cc406Sopenharmony_ci{ 2517141cc406Sopenharmony_ci Mustek_pp_Handle *dev = hndl; 2518141cc406Sopenharmony_ci Mustek_PP_CIS_dev *cisdev = dev->priv; 2519141cc406Sopenharmony_ci DBG (3, "cis_close: resetting device.\n"); 2520141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_TRUE); 2521141cc406Sopenharmony_ci cis_reset_device (cisdev); 2522141cc406Sopenharmony_ci DBG (3, "cis_close: returning home.\n"); 2523141cc406Sopenharmony_ci cis_return_home (cisdev, SANE_TRUE); /* Don't wait */ 2524141cc406Sopenharmony_ci DBG (3, "cis_close: disabling fd.\n"); 2525141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_FALSE); 2526141cc406Sopenharmony_ci DBG (3, "cis_close: closing fd.\n"); 2527141cc406Sopenharmony_ci sanei_pa4s2_close (dev->fd); 2528141cc406Sopenharmony_ci DBG (3, "cis_close: done.\n"); 2529141cc406Sopenharmony_ci DBG (6, "cis_close: lamp_on: %d\n", (int)dev->lamp_on); 2530141cc406Sopenharmony_ci M1015_STOP_LL; 2531141cc406Sopenharmony_ci M1015_STOP_HL; 2532141cc406Sopenharmony_ci} 2533141cc406Sopenharmony_ci 2534141cc406Sopenharmony_ci/****************************************************************************** 2535141cc406Sopenharmony_ci* Start * 2536141cc406Sopenharmony_ci******************************************************************************/ 2537141cc406Sopenharmony_ciSANE_Status cis_drv_start (SANE_Handle hndl) 2538141cc406Sopenharmony_ci{ 2539141cc406Sopenharmony_ci Mustek_pp_Handle *dev = hndl; 2540141cc406Sopenharmony_ci Mustek_PP_CIS_dev *cisdev = dev->priv; 2541141cc406Sopenharmony_ci SANE_Int pixels = dev->params.pixels_per_line; 2542141cc406Sopenharmony_ci 2543141cc406Sopenharmony_ci if (!cisdev) 2544141cc406Sopenharmony_ci { 2545141cc406Sopenharmony_ci DBG (2, "cis_drv_start: not enough memory for device\n"); 2546141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2547141cc406Sopenharmony_ci } 2548141cc406Sopenharmony_ci 2549141cc406Sopenharmony_ci cisdev->CIS.exposeTime = 0xAA; 2550141cc406Sopenharmony_ci cisdev->CIS.setParameters = SANE_FALSE; 2551141cc406Sopenharmony_ci cisdev->CIS.use8KBank = SANE_TRUE; 2552141cc406Sopenharmony_ci cisdev->CIS.imagebytes = dev->bottomX - dev->topX; 2553141cc406Sopenharmony_ci cisdev->CIS.skipimagebytes = dev->topX; 2554141cc406Sopenharmony_ci 2555141cc406Sopenharmony_ci cisdev->CIS.res = dev->res; 2556141cc406Sopenharmony_ci 2557141cc406Sopenharmony_ci DBG (3, "cis_drv_start: %d dpi\n", dev->res); 2558141cc406Sopenharmony_ci 2559141cc406Sopenharmony_ci if (dev->res <= 50 && cisdev->model != MUSTEK_PP_CIS1200PLUS) 2560141cc406Sopenharmony_ci { 2561141cc406Sopenharmony_ci cisdev->CIS.hw_hres = 50; 2562141cc406Sopenharmony_ci } 2563141cc406Sopenharmony_ci else if (dev->res <= 75 && cisdev->model == MUSTEK_PP_CIS1200PLUS) 2564141cc406Sopenharmony_ci { 2565141cc406Sopenharmony_ci cisdev->CIS.hw_hres = 75; 2566141cc406Sopenharmony_ci } 2567141cc406Sopenharmony_ci else if (dev->res <= 100) 2568141cc406Sopenharmony_ci { 2569141cc406Sopenharmony_ci cisdev->CIS.hw_hres = 100; 2570141cc406Sopenharmony_ci } 2571141cc406Sopenharmony_ci else if (dev->res <= 200) 2572141cc406Sopenharmony_ci { 2573141cc406Sopenharmony_ci cisdev->CIS.hw_hres = 200; 2574141cc406Sopenharmony_ci } 2575141cc406Sopenharmony_ci else if (dev->res <= 300) 2576141cc406Sopenharmony_ci { 2577141cc406Sopenharmony_ci cisdev->CIS.hw_hres = 300; 2578141cc406Sopenharmony_ci } 2579141cc406Sopenharmony_ci else 2580141cc406Sopenharmony_ci { 2581141cc406Sopenharmony_ci if (cisdev->model == MUSTEK_PP_CIS600) 2582141cc406Sopenharmony_ci { 2583141cc406Sopenharmony_ci cisdev->CIS.hw_hres = 300; /* Limit for 600 CP */ 2584141cc406Sopenharmony_ci } 2585141cc406Sopenharmony_ci else if (dev->res <= 400) 2586141cc406Sopenharmony_ci { 2587141cc406Sopenharmony_ci cisdev->CIS.hw_hres = 400; 2588141cc406Sopenharmony_ci } 2589141cc406Sopenharmony_ci else 2590141cc406Sopenharmony_ci { 2591141cc406Sopenharmony_ci cisdev->CIS.hw_hres = 600; /* Limit for 1200 CP/CP+ */ 2592141cc406Sopenharmony_ci } 2593141cc406Sopenharmony_ci } 2594141cc406Sopenharmony_ci 2595141cc406Sopenharmony_ci if (cisdev->model == MUSTEK_PP_CIS600) 2596141cc406Sopenharmony_ci { 2597141cc406Sopenharmony_ci if (dev->res <= 150) 2598141cc406Sopenharmony_ci { 2599141cc406Sopenharmony_ci cisdev->CIS.hw_vres = 150; 2600141cc406Sopenharmony_ci } 2601141cc406Sopenharmony_ci else if (dev->res <= 300) 2602141cc406Sopenharmony_ci { 2603141cc406Sopenharmony_ci cisdev->CIS.hw_vres = 300; 2604141cc406Sopenharmony_ci } 2605141cc406Sopenharmony_ci else 2606141cc406Sopenharmony_ci { 2607141cc406Sopenharmony_ci cisdev->CIS.hw_vres = 600; 2608141cc406Sopenharmony_ci } 2609141cc406Sopenharmony_ci } 2610141cc406Sopenharmony_ci else 2611141cc406Sopenharmony_ci { 2612141cc406Sopenharmony_ci if (dev->res <= 300) 2613141cc406Sopenharmony_ci { 2614141cc406Sopenharmony_ci cisdev->CIS.hw_vres = 300; 2615141cc406Sopenharmony_ci } 2616141cc406Sopenharmony_ci else if (dev->res <= 600) 2617141cc406Sopenharmony_ci { 2618141cc406Sopenharmony_ci cisdev->CIS.hw_vres = 600; 2619141cc406Sopenharmony_ci } 2620141cc406Sopenharmony_ci else 2621141cc406Sopenharmony_ci { 2622141cc406Sopenharmony_ci cisdev->CIS.hw_vres = 1200; 2623141cc406Sopenharmony_ci } 2624141cc406Sopenharmony_ci } 2625141cc406Sopenharmony_ci 2626141cc406Sopenharmony_ci if (cisdev->model == MUSTEK_PP_CIS600 || 2627141cc406Sopenharmony_ci (cisdev->model == MUSTEK_PP_CIS1200 && dev->res <= 300)) 2628141cc406Sopenharmony_ci cisdev->CIS.cisRes = 300; 2629141cc406Sopenharmony_ci else 2630141cc406Sopenharmony_ci cisdev->CIS.cisRes = 600; 2631141cc406Sopenharmony_ci 2632141cc406Sopenharmony_ci /* Calibration only makes sense for hardware pixels, not for interpolated 2633141cc406Sopenharmony_ci pixels, so we limit the number of calibration pixels to the maximum 2634141cc406Sopenharmony_ci number of hardware pixels corresponding to the selected area */ 2635141cc406Sopenharmony_ci if (dev->res > cisdev->CIS.hw_hres) 2636141cc406Sopenharmony_ci cisdev->calib_pixels = (pixels * cisdev->CIS.hw_hres) / dev->res; 2637141cc406Sopenharmony_ci else 2638141cc406Sopenharmony_ci cisdev->calib_pixels = pixels; 2639141cc406Sopenharmony_ci 2640141cc406Sopenharmony_ci DBG (3, "cis_drv_start: hres: %d vres: %d cisres: %d\n", 2641141cc406Sopenharmony_ci cisdev->CIS.hw_hres, cisdev->CIS.hw_vres, cisdev->CIS.cisRes); 2642141cc406Sopenharmony_ci 2643141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_TRUE); 2644141cc406Sopenharmony_ci 2645141cc406Sopenharmony_ci cis_reset_device (cisdev); 2646141cc406Sopenharmony_ci cis_return_home (cisdev, SANE_TRUE); /* Don't wait here */ 2647141cc406Sopenharmony_ci 2648141cc406Sopenharmony_ci#ifdef M1015_TRACE_REGS 2649141cc406Sopenharmony_ci { 2650141cc406Sopenharmony_ci int i, j; 2651141cc406Sopenharmony_ci 2652141cc406Sopenharmony_ci /* 2653141cc406Sopenharmony_ci * Set all registers to -1 (uninitialized) 2654141cc406Sopenharmony_ci */ 2655141cc406Sopenharmony_ci for (i=0; i<4; ++i) 2656141cc406Sopenharmony_ci { 2657141cc406Sopenharmony_ci cisdev->CIS.regs.in_regs[i] = -1; 2658141cc406Sopenharmony_ci for (j=0; j<4; ++j) 2659141cc406Sopenharmony_ci { 2660141cc406Sopenharmony_ci cisdev->CIS.regs.out_regs[i][j] = -1; 2661141cc406Sopenharmony_ci } 2662141cc406Sopenharmony_ci } 2663141cc406Sopenharmony_ci 2664141cc406Sopenharmony_ci cisdev->CIS.regs.channel = -1; 2665141cc406Sopenharmony_ci /* These values have been read earlier. */ 2666141cc406Sopenharmony_ci cisdev->CIS.regs.in_regs[0] = 0xA5; 2667141cc406Sopenharmony_ci } 2668141cc406Sopenharmony_ci#endif 2669141cc406Sopenharmony_ci 2670141cc406Sopenharmony_ci cis_reset_device (cisdev); 2671141cc406Sopenharmony_ci cis_return_home (cisdev, SANE_TRUE); /* no wait */ 2672141cc406Sopenharmony_ci 2673141cc406Sopenharmony_ci /* Allocate memory for temporary color buffer */ 2674141cc406Sopenharmony_ci cisdev->tmpbuf = malloc (pixels); 2675141cc406Sopenharmony_ci if (cisdev->tmpbuf == NULL) 2676141cc406Sopenharmony_ci { 2677141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_FALSE); 2678141cc406Sopenharmony_ci DBG (2, "cis_drv_start: not enough memory for temporary buffer\n"); 2679141cc406Sopenharmony_ci free(cisdev); 2680141cc406Sopenharmony_ci dev->priv = NULL; 2681141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2682141cc406Sopenharmony_ci } 2683141cc406Sopenharmony_ci 2684141cc406Sopenharmony_ci /* Allocate memory for calibration; calibrating interpolated pixels 2685141cc406Sopenharmony_ci makes no sense */ 2686141cc406Sopenharmony_ci if (pixels > (dev->dev->maxhsize >> 1)) 2687141cc406Sopenharmony_ci pixels = (dev->dev->maxhsize >> 1); 2688141cc406Sopenharmony_ci 2689141cc406Sopenharmony_ci cisdev->calib_low[1] = malloc (pixels); 2690141cc406Sopenharmony_ci cisdev->calib_hi[1] = malloc (pixels); 2691141cc406Sopenharmony_ci 2692141cc406Sopenharmony_ci if (cisdev->calib_low[1] == NULL || cisdev->calib_hi[1] == NULL) 2693141cc406Sopenharmony_ci { 2694141cc406Sopenharmony_ci free (cisdev->calib_low[1]); cisdev->calib_low[1] = NULL; 2695141cc406Sopenharmony_ci free (cisdev->calib_hi[1]); cisdev->calib_hi[1] = NULL; 2696141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_FALSE); 2697141cc406Sopenharmony_ci DBG (2, "cis_drv_start: not enough memory for calibration buffer\n"); 2698141cc406Sopenharmony_ci free(cisdev->tmpbuf); cisdev->tmpbuf = NULL; 2699141cc406Sopenharmony_ci free(cisdev); dev->priv = NULL; 2700141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2701141cc406Sopenharmony_ci } 2702141cc406Sopenharmony_ci 2703141cc406Sopenharmony_ci cisdev->calib_low[0] = NULL; 2704141cc406Sopenharmony_ci cisdev->calib_low[2] = NULL; 2705141cc406Sopenharmony_ci cisdev->calib_hi[0] = NULL; 2706141cc406Sopenharmony_ci cisdev->calib_hi[2] = NULL; 2707141cc406Sopenharmony_ci if (dev->mode == MODE_COLOR) 2708141cc406Sopenharmony_ci { 2709141cc406Sopenharmony_ci cisdev->calib_low[0] = malloc (pixels); 2710141cc406Sopenharmony_ci cisdev->calib_low[2] = malloc (pixels); 2711141cc406Sopenharmony_ci cisdev->calib_hi[0] = malloc (pixels); 2712141cc406Sopenharmony_ci cisdev->calib_hi[2] = malloc (pixels); 2713141cc406Sopenharmony_ci 2714141cc406Sopenharmony_ci if ((cisdev->calib_low[0] == NULL) || (cisdev->calib_low[2] == NULL) || 2715141cc406Sopenharmony_ci (cisdev->calib_hi[0] == NULL) || (cisdev->calib_hi[2] == NULL)) 2716141cc406Sopenharmony_ci { 2717141cc406Sopenharmony_ci free (cisdev->calib_low[0]); cisdev->calib_low[0] = NULL; 2718141cc406Sopenharmony_ci free (cisdev->calib_low[1]); cisdev->calib_low[1] = NULL; 2719141cc406Sopenharmony_ci free (cisdev->calib_low[2]); cisdev->calib_low[2] = NULL; 2720141cc406Sopenharmony_ci free (cisdev->calib_hi[0]); cisdev->calib_hi[0] = NULL; 2721141cc406Sopenharmony_ci free (cisdev->calib_hi[1]); cisdev->calib_hi[1] = NULL; 2722141cc406Sopenharmony_ci free (cisdev->calib_hi[2]); cisdev->calib_hi[2] = NULL; 2723141cc406Sopenharmony_ci free(cisdev->tmpbuf); cisdev->tmpbuf = NULL; 2724141cc406Sopenharmony_ci free(cisdev); dev->priv = NULL; 2725141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_FALSE); 2726141cc406Sopenharmony_ci DBG (2, "cis_drv_start: not enough memory for color calib buffer\n"); 2727141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 2728141cc406Sopenharmony_ci } 2729141cc406Sopenharmony_ci } 2730141cc406Sopenharmony_ci 2731141cc406Sopenharmony_ci DBG (3, "cis_drv_start: executing calibration\n"); 2732141cc406Sopenharmony_ci 2733141cc406Sopenharmony_ci if (!cis_calibrate (cisdev)) 2734141cc406Sopenharmony_ci { 2735141cc406Sopenharmony_ci free (cisdev->calib_low[0]); cisdev->calib_low[0] = NULL; 2736141cc406Sopenharmony_ci free (cisdev->calib_low[1]); cisdev->calib_low[1] = NULL; 2737141cc406Sopenharmony_ci free (cisdev->calib_low[2]); cisdev->calib_low[2] = NULL; 2738141cc406Sopenharmony_ci free (cisdev->calib_hi[0]); cisdev->calib_hi[0] = NULL; 2739141cc406Sopenharmony_ci free (cisdev->calib_hi[1]); cisdev->calib_hi[1] = NULL; 2740141cc406Sopenharmony_ci free (cisdev->calib_hi[2]); cisdev->calib_hi[2] = NULL; 2741141cc406Sopenharmony_ci free(cisdev->tmpbuf); cisdev->tmpbuf = NULL; 2742141cc406Sopenharmony_ci free(cisdev); dev->priv = NULL; 2743141cc406Sopenharmony_ci return SANE_STATUS_CANCELLED; /* Most likely cause */ 2744141cc406Sopenharmony_ci } 2745141cc406Sopenharmony_ci 2746141cc406Sopenharmony_ci/* M1015_DISPLAY_REGS(dev, "after calibration"); */ 2747141cc406Sopenharmony_ci 2748141cc406Sopenharmony_ci cis_get_bank_count(cisdev); 2749141cc406Sopenharmony_ci 2750141cc406Sopenharmony_ci cis_move_motor (cisdev, dev->topY); /* Measured in max resolution */ 2751141cc406Sopenharmony_ci 2752141cc406Sopenharmony_ci /* It is vital to reinitialize the scanner right before we start the 2753141cc406Sopenharmony_ci real scanning. Otherwise the bank synchronization may have gotten lost 2754141cc406Sopenharmony_ci by the time we reach the top of the scan area */ 2755141cc406Sopenharmony_ci 2756141cc406Sopenharmony_ci cisdev->CIS.setParameters = SANE_TRUE; 2757141cc406Sopenharmony_ci cis_config_ccd(cisdev); 2758141cc406Sopenharmony_ci cis_wait_read_ready(cisdev); 2759141cc406Sopenharmony_ci 2760141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_FALSE); 2761141cc406Sopenharmony_ci 2762141cc406Sopenharmony_ci cisdev->CIS.line_step = 2763141cc406Sopenharmony_ci SANE_FIX ((float) cisdev->CIS.hw_vres / (float) cisdev->CIS.res); 2764141cc406Sopenharmony_ci 2765141cc406Sopenharmony_ci /* 2766141cc406Sopenharmony_ci * It is very important that line_diff is not initialized at zero ! 2767141cc406Sopenharmony_ci * If it is set to zero, the motor will keep on moving forever (or better, 2768141cc406Sopenharmony_ci * till the scanner breaks). 2769141cc406Sopenharmony_ci */ 2770141cc406Sopenharmony_ci cisdev->line_diff = cisdev->CIS.line_step; 2771141cc406Sopenharmony_ci cisdev->ccd_line = 0; 2772141cc406Sopenharmony_ci cisdev->line = 0; 2773141cc406Sopenharmony_ci cisdev->lines_left = dev->params.lines; 2774141cc406Sopenharmony_ci 2775141cc406Sopenharmony_ci dev->state = STATE_SCANNING; 2776141cc406Sopenharmony_ci 2777141cc406Sopenharmony_ci DBG (3, "cis_drv_start: device ready for scanning\n"); 2778141cc406Sopenharmony_ci 2779141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 2780141cc406Sopenharmony_ci} 2781141cc406Sopenharmony_ci 2782141cc406Sopenharmony_ci/****************************************************************************** 2783141cc406Sopenharmony_ci* Read * 2784141cc406Sopenharmony_ci******************************************************************************/ 2785141cc406Sopenharmony_civoid cis_drv_read (SANE_Handle hndl, SANE_Byte *buffer) 2786141cc406Sopenharmony_ci{ 2787141cc406Sopenharmony_ci Mustek_pp_Handle *dev = hndl; 2788141cc406Sopenharmony_ci Mustek_PP_CIS_dev *cisdev = dev->priv; 2789141cc406Sopenharmony_ci DBG(6, "cis_drv_read: Reading line\n"); 2790141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_TRUE); 2791141cc406Sopenharmony_ci switch (dev->mode) 2792141cc406Sopenharmony_ci { 2793141cc406Sopenharmony_ci case MODE_BW: 2794141cc406Sopenharmony_ci cis_get_lineart_line(cisdev, buffer); 2795141cc406Sopenharmony_ci break; 2796141cc406Sopenharmony_ci 2797141cc406Sopenharmony_ci case MODE_GRAYSCALE: 2798141cc406Sopenharmony_ci cis_get_grayscale_line(cisdev, buffer); 2799141cc406Sopenharmony_ci break; 2800141cc406Sopenharmony_ci 2801141cc406Sopenharmony_ci case MODE_COLOR: 2802141cc406Sopenharmony_ci cis_get_color_line(cisdev, buffer); 2803141cc406Sopenharmony_ci break; 2804141cc406Sopenharmony_ci } 2805141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_FALSE); 2806141cc406Sopenharmony_ci} 2807141cc406Sopenharmony_ci 2808141cc406Sopenharmony_ci/****************************************************************************** 2809141cc406Sopenharmony_ci* Stop * 2810141cc406Sopenharmony_ci******************************************************************************/ 2811141cc406Sopenharmony_civoid cis_drv_stop (SANE_Handle hndl) 2812141cc406Sopenharmony_ci{ 2813141cc406Sopenharmony_ci Mustek_pp_Handle *dev = hndl; 2814141cc406Sopenharmony_ci Mustek_PP_CIS_dev *cisdev = dev->priv; 2815141cc406Sopenharmony_ci 2816141cc406Sopenharmony_ci /* device is scanning: return lamp and free buffers */ 2817141cc406Sopenharmony_ci DBG (3, "cis_drv_stop: stopping current scan\n"); 2818141cc406Sopenharmony_ci dev->state = STATE_CANCELLED; 2819141cc406Sopenharmony_ci 2820141cc406Sopenharmony_ci DBG (9, "cis_drv_stop: enabling fd\n"); 2821141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_TRUE); 2822141cc406Sopenharmony_ci Mustek_PP_1015_write_reg(cisdev, MA1015W_MOTOR_CONTROL, 0); /* stop */ 2823141cc406Sopenharmony_ci DBG (9, "cis_drv_stop: resetting device (1)\n"); 2824141cc406Sopenharmony_ci cis_reset_device (cisdev); 2825141cc406Sopenharmony_ci DBG (9, "cis_drv_stop: returning home\n"); 2826141cc406Sopenharmony_ci cis_return_home (cisdev, SANE_TRUE); /* don't wait */ 2827141cc406Sopenharmony_ci DBG (9, "cis_drv_stop: resetting device (2)\n"); 2828141cc406Sopenharmony_ci cis_reset_device (cisdev); 2829141cc406Sopenharmony_ci DBG (9, "cis_drv_stop: disabling fd\n"); 2830141cc406Sopenharmony_ci sanei_pa4s2_enable (dev->fd, SANE_FALSE); 2831141cc406Sopenharmony_ci DBG (9, "cis_drv_stop: freeing buffers\n"); 2832141cc406Sopenharmony_ci 2833141cc406Sopenharmony_ci /* This is no good: canceling while the device is scanning and 2834141cc406Sopenharmony_ci freeing the data buffers can result in illegal memory accesses if 2835141cc406Sopenharmony_ci the device is still scanning in another thread. */ 2836141cc406Sopenharmony_ci free (cisdev->calib_low[1]); cisdev->calib_low[1] = NULL; 2837141cc406Sopenharmony_ci free (cisdev->calib_hi[1]); cisdev->calib_hi[1] = NULL; 2838141cc406Sopenharmony_ci free (cisdev->tmpbuf); cisdev->tmpbuf = NULL; 2839141cc406Sopenharmony_ci DBG (3, "cis_drv_stop: freed green and temporary buffers\n"); 2840141cc406Sopenharmony_ci 2841141cc406Sopenharmony_ci if (cisdev->CIS.mode == MODE_COLOR) 2842141cc406Sopenharmony_ci { 2843141cc406Sopenharmony_ci free (cisdev->calib_low[0]); cisdev->calib_low[0] = NULL; 2844141cc406Sopenharmony_ci free (cisdev->calib_low[2]); cisdev->calib_low[2] = NULL; 2845141cc406Sopenharmony_ci free (cisdev->calib_hi[0]); cisdev->calib_hi[0] = NULL; 2846141cc406Sopenharmony_ci free (cisdev->calib_hi[2]); cisdev->calib_hi[2] = NULL; 2847141cc406Sopenharmony_ci } 2848141cc406Sopenharmony_ci DBG (3, "cis_drv_stop: freed buffers\n"); 2849141cc406Sopenharmony_ci DBG (6, "cis_drv_stop: lamp_on: %d\n", (int)dev->lamp_on); 2850141cc406Sopenharmony_ci} 2851