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