1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 1999 Paul Mackerras
4141cc406Sopenharmony_ci   Copyright (C) 2000 Adrian Perez Jorge
5141cc406Sopenharmony_ci   Copyright (C) 2001 Frank Zago
6141cc406Sopenharmony_ci   Copyright (C) 2001 Marcio Teixeira
7141cc406Sopenharmony_ci   Parts copyright (C) 2006 Patrick Lessard
8141cc406Sopenharmony_ci
9141cc406Sopenharmony_ci   This file is part of the SANE package.
10141cc406Sopenharmony_ci
11141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
12141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
13141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
14141cc406Sopenharmony_ci   License, or (at your option) any later version.
15141cc406Sopenharmony_ci
16141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
17141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
18141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19141cc406Sopenharmony_ci   General Public License for more details.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
22141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
25141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
28141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
29141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
30141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
31141cc406Sopenharmony_ci   account of linking the SANE library code into it.
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
34141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
35141cc406Sopenharmony_ci   License.
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
38141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
39141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
42141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
43141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci   Defines a driver and API for accessing the UMAX Astra 1220U
46141cc406Sopenharmony_ci   USB scanner. Based on the original command line tool by Paul
47141cc406Sopenharmony_ci   Mackerras.
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci   The UMAX Astra 1220U scanner uses the PowerVision PV8630
50141cc406Sopenharmony_ci   Parallel Port to USB bridge. This chip is also used
51141cc406Sopenharmony_ci   by the HP4200C flatbed scanner. Adrian Perez Jorge wrote
52141cc406Sopenharmony_ci   a nice interface file for that chip and Frank Zago adapted
53141cc406Sopenharmony_ci   it to use the sanei_usb interface. Thanks, guys, for making
54141cc406Sopenharmony_ci   my life easier! :)
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci */
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_ci#include <string.h>
60141cc406Sopenharmony_ci#include <errno.h>
61141cc406Sopenharmony_ci#include <fcntl.h>
62141cc406Sopenharmony_ci#include <sys/types.h>
63141cc406Sopenharmony_ci#include <sys/stat.h>
64141cc406Sopenharmony_ci#include <sys/ioctl.h>
65141cc406Sopenharmony_ci#include <math.h>
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci/*
68141cc406Sopenharmony_ci * The backend performs test scans in order to calibrate
69141cc406Sopenharmony_ci * the CCD and to find the zero location. If you would like
70141cc406Sopenharmony_ci * to look at those scans, define DEBUG_CALIBRATION to have
71141cc406Sopenharmony_ci * the backend save "find_zero.pgm" and "calibration.pgm" to
72141cc406Sopenharmony_ci * disk.
73141cc406Sopenharmony_ci */
74141cc406Sopenharmony_ci/* #define DEBUG_CALIBRATION */
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci/*
77141cc406Sopenharmony_ci * Define DEBUG_BOUNDS to insert paranoid array bounds
78141cc406Sopenharmony_ci * overrun detection into the code.
79141cc406Sopenharmony_ci */
80141cc406Sopenharmony_ci/* #define DEBUG_BOUNDS */
81141cc406Sopenharmony_ci
82141cc406Sopenharmony_ci/* These values are empirically determined and are given
83141cc406Sopenharmony_ci * in 1/600 inch units. If UMAX_MAX_HEIGHT is too large,
84141cc406Sopenharmony_ci * the scanner may grind its gears. I assume there is a
85141cc406Sopenharmony_ci * physical limit to UMAX_MAX_WIDTH as well (based on the
86141cc406Sopenharmony_ci * sensor size) but I do not know what it is. The current
87141cc406Sopenharmony_ci * value can be increased beyond what it is now, but you
88141cc406Sopenharmony_ci * gain nothing in usable scan area (you only scan more
89141cc406Sopenharmony_ci * of the underside of the scanner's plastic lid).
90141cc406Sopenharmony_ci */
91141cc406Sopenharmony_ci
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ci#define UMAX_MAX_WIDTH    5400
94141cc406Sopenharmony_ci#define UMAX_MAX_HEIGHT   7040
95141cc406Sopenharmony_ci
96141cc406Sopenharmony_ci/* Buffer size. Specifies the size of the buffer that is
97141cc406Sopenharmony_ci * used to copy data from the scanner. The old command
98141cc406Sopenharmony_ci * line driver had this set at 0x80000 which is likely
99141cc406Sopenharmony_ci * the largest possible chunk of data that can be.
100141cc406Sopenharmony_ci * at once. This is probably most efficient, but using
101141cc406Sopenharmony_ci * a lower value for the SANE driver makes the driver
102141cc406Sopenharmony_ci * more responsive to interaction.
103141cc406Sopenharmony_ci */
104141cc406Sopenharmony_ci#define BUFFER_SIZE 0x80000
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci/* Constants that can be used with set_lamp_state to
107141cc406Sopenharmony_ci * control the state of the scanner's lamp
108141cc406Sopenharmony_ci */
109141cc406Sopenharmony_citypedef enum
110141cc406Sopenharmony_ci{
111141cc406Sopenharmony_ci  UMAX_LAMP_OFF = 0,
112141cc406Sopenharmony_ci  UMAX_LAMP_ON = 1
113141cc406Sopenharmony_ci}
114141cc406Sopenharmony_ciUMAX_Lamp_State;
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_ci/* Constants that can be used with move to control
117141cc406Sopenharmony_ci * the rate of scanner head movement
118141cc406Sopenharmony_ci */
119141cc406Sopenharmony_citypedef enum
120141cc406Sopenharmony_ci{
121141cc406Sopenharmony_ci  UMAX_NOT_FINE = 0,
122141cc406Sopenharmony_ci  UMAX_FINE = 1
123141cc406Sopenharmony_ci}
124141cc406Sopenharmony_ciUMAX_Speed;
125141cc406Sopenharmony_ci
126141cc406Sopenharmony_ci/* If anyone knows some descriptive names for these,
127141cc406Sopenharmony_ci * please update
128141cc406Sopenharmony_ci */
129141cc406Sopenharmony_citypedef enum
130141cc406Sopenharmony_ci{
131141cc406Sopenharmony_ci  CMD_0 = 0x00,
132141cc406Sopenharmony_ci  CMD_1 = 0x01,
133141cc406Sopenharmony_ci  CMD_2 = 0x02,
134141cc406Sopenharmony_ci  CMD_4 = 0x04,
135141cc406Sopenharmony_ci  CMD_8 = 0x08,
136141cc406Sopenharmony_ci  CMD_40 = 0x40,
137141cc406Sopenharmony_ci  CMD_WRITE = 0x80,
138141cc406Sopenharmony_ci  CMD_READ = 0xc0
139141cc406Sopenharmony_ci}
140141cc406Sopenharmony_ciUMAX_Cmd;
141141cc406Sopenharmony_ci
142141cc406Sopenharmony_ci/* Product IDs for Astra scanners
143141cc406Sopenharmony_ci */
144141cc406Sopenharmony_citypedef enum
145141cc406Sopenharmony_ci{
146141cc406Sopenharmony_ci  ASTRA_1220U = 0x0010,
147141cc406Sopenharmony_ci  ASTRA_2000U = 0x0030,
148141cc406Sopenharmony_ci  ASTRA_2100U = 0x0130
149141cc406Sopenharmony_ci}
150141cc406Sopenharmony_ciUMAX_Model;
151141cc406Sopenharmony_ci
152141cc406Sopenharmony_ci/* The bytes UMAX_SYNC1 and UMAX_SYNC2 serve as a
153141cc406Sopenharmony_ci * synchronization signal. Unintentional sync bytes
154141cc406Sopenharmony_ci * in the data stream are escaped with UMAX_ESCAPE
155141cc406Sopenharmony_ci * character
156141cc406Sopenharmony_ci */
157141cc406Sopenharmony_ci
158141cc406Sopenharmony_ci#define UMAX_SYNC1  0x55
159141cc406Sopenharmony_ci#define UMAX_SYNC2  0xaa
160141cc406Sopenharmony_ci#define UMAX_ESCAPE 0x1b
161141cc406Sopenharmony_ci
162141cc406Sopenharmony_ci/* Status bits. These bits are active low.
163141cc406Sopenharmony_ci * In umax_pp, UMAX_REVERSE_BIT is called
164141cc406Sopenharmony_ci * MOTOR_BIT.
165141cc406Sopenharmony_ci */
166141cc406Sopenharmony_ci
167141cc406Sopenharmony_ci#define UMAX_FORWARD_BIT       0x40
168141cc406Sopenharmony_ci#define UMAX_ERROR_BIT         0x20
169141cc406Sopenharmony_ci#define UMAX_MOTOR_OFF_BIT     0x08
170141cc406Sopenharmony_ci
171141cc406Sopenharmony_ci#define UMAX_OK                0x48        /* Used to be 0xC8 */
172141cc406Sopenharmony_ci#define UMAX_OK_WITH_MOTOR     0x40        /* Used to be 0xD0 */
173141cc406Sopenharmony_ci
174141cc406Sopenharmony_ci#define UMAX_STATUS_MASK       0x68
175141cc406Sopenharmony_ci
176141cc406Sopenharmony_ci/* This byte is used as a placeholder for bytes that are parameterized
177141cc406Sopenharmony_ci * in the opcode strings */
178141cc406Sopenharmony_ci
179141cc406Sopenharmony_ci#define XXXX 0x00
180141cc406Sopenharmony_ci
181141cc406Sopenharmony_ci/* This macro is used to check the return code of
182141cc406Sopenharmony_ci * functions
183141cc406Sopenharmony_ci */
184141cc406Sopenharmony_ci#define CHK(A) {if( (res = A) != SANE_STATUS_GOOD ) { \
185141cc406Sopenharmony_ci                 DBG( 1, "Failure on line of %s: %d\n", __FILE__, \
186141cc406Sopenharmony_ci                      __LINE__ ); return A; }}
187141cc406Sopenharmony_ci
188141cc406Sopenharmony_ci/* Macros that are used for array overrun detection
189141cc406Sopenharmony_ci * (when DEBUG_BOUNDS is defined)
190141cc406Sopenharmony_ci */
191141cc406Sopenharmony_ci#ifdef DEBUG_BOUNDS
192141cc406Sopenharmony_ci#define PAD 10
193141cc406Sopenharmony_ci#define PAD_ARRAY( A, len ) {int i; \
194141cc406Sopenharmony_ci                 for( i = 0; i < PAD; i++ ) {A[len+i]=0x55;}}
195141cc406Sopenharmony_ci
196141cc406Sopenharmony_ci#define CHK_ARRAY( A, len ) {int i;for( i = 0; i < PAD; i++ ) {\
197141cc406Sopenharmony_ci   if(A[len+i]!=0x55) { \
198141cc406Sopenharmony_ci     DBG( 1, "Array overrun detected on line %d\n", __LINE__ ); \
199141cc406Sopenharmony_ci   }}}
200141cc406Sopenharmony_ci#else
201141cc406Sopenharmony_ci#define PAD 0
202141cc406Sopenharmony_ci#define PAD_ARRAY( A, len )
203141cc406Sopenharmony_ci#define CHK_ARRAY( A, len )
204141cc406Sopenharmony_ci#endif
205141cc406Sopenharmony_ci
206141cc406Sopenharmony_ci
207141cc406Sopenharmony_ci/* This data structure contains data related
208141cc406Sopenharmony_ci * to the scanning process.
209141cc406Sopenharmony_ci */
210141cc406Sopenharmony_citypedef struct
211141cc406Sopenharmony_ci{
212141cc406Sopenharmony_ci  /* Constant data */
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci  int color;
215141cc406Sopenharmony_ci  int w;
216141cc406Sopenharmony_ci  int h;
217141cc406Sopenharmony_ci  int xo;
218141cc406Sopenharmony_ci  int yo;
219141cc406Sopenharmony_ci  int xdpi;                      /* Physical x dpi */
220141cc406Sopenharmony_ci  int ydpi;                      /* Physical y dpi */
221141cc406Sopenharmony_ci  int xsamp;
222141cc406Sopenharmony_ci  int ysamp;
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_ci  int xskip;
225141cc406Sopenharmony_ci  int yskip;
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_ci  int fd;                        /* Device file handle */
228141cc406Sopenharmony_ci  UMAX_Model model;
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_ci  /* Raw scan data buffer */
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_ci  unsigned char *p;
233141cc406Sopenharmony_ci  int bh;                        /* Size of buffer in lines    */
234141cc406Sopenharmony_ci  int hexp;                      /* Scan lines yet to be read  */
235141cc406Sopenharmony_ci
236141cc406Sopenharmony_ci  /* Decoding logic */
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci  int x, y, maxh;
239141cc406Sopenharmony_ci  int done;                      /* Boolean, all lines decoded */
240141cc406Sopenharmony_ci
241141cc406Sopenharmony_ci  /* Calibration data */
242141cc406Sopenharmony_ci
243141cc406Sopenharmony_ci  unsigned char caldata[16070 + PAD];
244141cc406Sopenharmony_ci
245141cc406Sopenharmony_ci  /* Scan head position */
246141cc406Sopenharmony_ci
247141cc406Sopenharmony_ci  int scanner_ypos;
248141cc406Sopenharmony_ci  int scanner_yorg;
249141cc406Sopenharmony_ci}
250141cc406Sopenharmony_ciUMAX_Handle;
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_citypedef unsigned char UMAX_Status_Byte;
253141cc406Sopenharmony_ci
254141cc406Sopenharmony_ci
255141cc406Sopenharmony_ci#if 0
256141cc406Sopenharmony_cistatic void
257141cc406Sopenharmony_ciunused_operations ()
258141cc406Sopenharmony_ci{
259141cc406Sopenharmony_ci  /* These operations are unused anywhere in the driver */
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci  unsigned char opb8[35] = {
262141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x04,
263141cc406Sopenharmony_ci    0x40, 0x01, 0x00, 0x00, 0x04, 0x00, 0x6e, 0x18, 0x10, 0x03,
264141cc406Sopenharmony_ci    0x06, 0x00, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x8b, 0x49, 0x4a,
265141cc406Sopenharmony_ci    0xd0, 0x68, 0xdf, 0x13, 0x1a
266141cc406Sopenharmony_ci  };
267141cc406Sopenharmony_ci
268141cc406Sopenharmony_ci  unsigned char opb9[35] = {
269141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x04,
270141cc406Sopenharmony_ci    0x40, 0x01, 0x00, 0x00, 0x04, 0x00, 0x6e, 0x41, 0x20, 0x24,
271141cc406Sopenharmony_ci    0x06, 0x00, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x8b, 0x49, 0x4a,
272141cc406Sopenharmony_ci    0xd0, 0x68, 0xdf, 0x13, 0x1a
273141cc406Sopenharmony_ci  };
274141cc406Sopenharmony_ci
275141cc406Sopenharmony_ci  unsigned char opb10[35] = {
276141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x04,
277141cc406Sopenharmony_ci    0x40, 0x01, 0x00, 0x00, 0x04, 0x00, 0x6e, 0x41, 0x60, 0x4f,
278141cc406Sopenharmony_ci    0x06, 0x00, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x8b, 0x49, 0x4a,
279141cc406Sopenharmony_ci    0xd0, 0x68, 0xdf, 0x93, 0x1a
280141cc406Sopenharmony_ci  };
281141cc406Sopenharmony_ci
282141cc406Sopenharmony_ci  unsigned char opc5[16] = {
283141cc406Sopenharmony_ci    0x05, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x2f, 0x2f, 0x00,
284141cc406Sopenharmony_ci    0x00, 0x30, 0x0c, 0xc3, 0xa4, 0x00
285141cc406Sopenharmony_ci  };
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_ci  unsigned char opc6[16] = {
288141cc406Sopenharmony_ci    0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x2f, 0x2f, 0x00,
289141cc406Sopenharmony_ci    0x88, 0x48, 0x0c, 0x83, 0xa4, 0x00
290141cc406Sopenharmony_ci  };
291141cc406Sopenharmony_ci
292141cc406Sopenharmony_ci  unsigned char opc7[16] = {
293141cc406Sopenharmony_ci    0x05, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x2f, 0x2f, 0x00,
294141cc406Sopenharmony_ci    0xec, 0x4e, 0x0c, 0xc3, 0xa4, 0x00
295141cc406Sopenharmony_ci  };
296141cc406Sopenharmony_ci
297141cc406Sopenharmony_ci  unsigned char opd2[8] = {
298141cc406Sopenharmony_ci    0x06, 0xf4, 0xff, 0x81, 0x3d, 0x00, 0x00, 0x30
299141cc406Sopenharmony_ci  };
300141cc406Sopenharmony_ci}
301141cc406Sopenharmony_ci#endif
302141cc406Sopenharmony_ci
303141cc406Sopenharmony_ci#if 0
304141cc406Sopenharmony_cistatic SANE_Status
305141cc406Sopenharmony_cicalib (UMAX_Handle * scan)
306141cc406Sopenharmony_ci{
307141cc406Sopenharmony_ci  unsigned char buf[65536];
308141cc406Sopenharmony_ci  opc5[11] = 0x30;
309141cc406Sopenharmony_ci  opd2[7]  = 0x30;
310141cc406Sopenharmony_ci  CHK (get_pixels (scan, opc5, opb8, opd2, ope, 24, 0, buff));
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci  opc5[11] = 0x40;
313141cc406Sopenharmony_ci  opd2[7]  = 0x40;
314141cc406Sopenharmony_ci  CHK (get_pixels (scan, opc5, opb8, opd2, ope, 24, 0, buff));
315141cc406Sopenharmony_ci
316141cc406Sopenharmony_ci  opd2[6] = 8;
317141cc406Sopenharmony_ci  opd2[7] = 0x30;
318141cc406Sopenharmony_ci  CHK (get_pixels (scan, opc6, opb9, opd2, ope, 0x200, 1, buff));
319141cc406Sopenharmony_ci
320141cc406Sopenharmony_ci  opc7[10] = 0xec;
321141cc406Sopenharmony_ci  opd2[6]  = 0xc;
322141cc406Sopenharmony_ci  opd2[7]  = 0x40;
323141cc406Sopenharmony_ci  CHK (get_pixels (scan, opc7, opb10, opd2, ope, 5300, 1, buff));
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_ci  opc7[10] = 0xed;
326141cc406Sopenharmony_ci  opd2[6]  = 0xd;
327141cc406Sopenharmony_ci  CHK (get_pixels (scan, opc7, opb10, opd2, ope, 5300, 0, buff));
328141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
329141cc406Sopenharmony_ci}
330141cc406Sopenharmony_ci#endif
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci
333141cc406Sopenharmony_ci/* This seems to configure the pv8630 chip somehow. I wish
334141cc406Sopenharmony_ci * all the magic numbers were defined as self-descriptive
335141cc406Sopenharmony_ci * constants somewhere. I made some guesses based on what
336141cc406Sopenharmony_ci * I found in "pv8630.c", but alas there wasn't enough in
337141cc406Sopenharmony_ci * there. If you know what this does, please let me know!
338141cc406Sopenharmony_ci */
339141cc406Sopenharmony_cistatic SANE_Status
340141cc406Sopenharmony_cixxxops (UMAX_Handle * scan)
341141cc406Sopenharmony_ci{
342141cc406Sopenharmony_ci  SANE_Status res;
343141cc406Sopenharmony_ci
344141cc406Sopenharmony_ci  DBG (9, "doing xxxops\n");
345141cc406Sopenharmony_ci
346141cc406Sopenharmony_ci  CHK (sanei_pv8630_write_byte (scan->fd, PV8630_RMODE, 0x02));
347141cc406Sopenharmony_ci
348141cc406Sopenharmony_ci  CHK (sanei_pv8630_write_byte (scan->fd, PV8630_UNKNOWN, 0x0E));
349141cc406Sopenharmony_ci  CHK (sanei_pv8630_write_byte (scan->fd, PV8630_RDATA, 0x40));
350141cc406Sopenharmony_ci  CHK (sanei_pv8630_write_byte (scan->fd, PV8630_UNKNOWN, 0x06));
351141cc406Sopenharmony_ci  CHK (sanei_pv8630_xpect_byte (scan->fd, PV8630_RSTATUS, 0x38, 0xFF));
352141cc406Sopenharmony_ci
353141cc406Sopenharmony_ci  CHK (sanei_pv8630_write_byte (scan->fd, PV8630_UNKNOWN, 0x07));
354141cc406Sopenharmony_ci  CHK (sanei_pv8630_xpect_byte (scan->fd, PV8630_RSTATUS, 0x38, 0xFF));
355141cc406Sopenharmony_ci
356141cc406Sopenharmony_ci  CHK (sanei_pv8630_write_byte (scan->fd, PV8630_UNKNOWN, 0x04));
357141cc406Sopenharmony_ci  CHK (sanei_pv8630_xpect_byte (scan->fd, PV8630_RSTATUS, 0xF8, 0xFF));
358141cc406Sopenharmony_ci
359141cc406Sopenharmony_ci  CHK (sanei_pv8630_write_byte (scan->fd, PV8630_UNKNOWN, 0x05));
360141cc406Sopenharmony_ci  CHK (sanei_pv8630_xpect_byte (scan->fd, PV8630_UNKNOWN, 0x05, 0xFF));
361141cc406Sopenharmony_ci
362141cc406Sopenharmony_ci  CHK (sanei_pv8630_write_byte (scan->fd, PV8630_UNKNOWN, 0x04));
363141cc406Sopenharmony_ci
364141cc406Sopenharmony_ci  CHK (sanei_pv8630_write_byte (scan->fd, PV8630_RMODE, 0x1E));
365141cc406Sopenharmony_ci
366141cc406Sopenharmony_ci  return res;
367141cc406Sopenharmony_ci}
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_ci/*
370141cc406Sopenharmony_ciApparently sends the two synchronization characters followed
371141cc406Sopenharmony_ciby the command length, followed by the command number
372141cc406Sopenharmony_ci*/
373141cc406Sopenharmony_cistatic SANE_Status
374141cc406Sopenharmony_ciusync (UMAX_Handle * scan, UMAX_Cmd cmd, int len)
375141cc406Sopenharmony_ci{
376141cc406Sopenharmony_ci  UMAX_Status_Byte s0, s4;
377141cc406Sopenharmony_ci  SANE_Status res;
378141cc406Sopenharmony_ci  unsigned char buf[4];
379141cc406Sopenharmony_ci  size_t nb;
380141cc406Sopenharmony_ci
381141cc406Sopenharmony_ci  DBG (80, "usync: len = %d, cmd = %d\n", len, cmd);
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci  buf[0] = UMAX_SYNC1;
384141cc406Sopenharmony_ci  buf[1] = UMAX_SYNC2;
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_ci  nb = 2;
387141cc406Sopenharmony_ci  CHK (sanei_pv8630_flush_buffer (scan->fd));
388141cc406Sopenharmony_ci  CHK (sanei_pv8630_prep_bulkwrite (scan->fd, nb));
389141cc406Sopenharmony_ci  CHK (sanei_pv8630_bulkwrite (scan->fd, buf, &nb));
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci  CHK (sanei_pv8630_wait_byte
392141cc406Sopenharmony_ci       (scan->fd, PV8630_RSTATUS, UMAX_OK, UMAX_STATUS_MASK, 20));
393141cc406Sopenharmony_ci
394141cc406Sopenharmony_ci  buf[0] = len >> 16;
395141cc406Sopenharmony_ci  buf[1] = len >> 8;
396141cc406Sopenharmony_ci  buf[2] = len;
397141cc406Sopenharmony_ci  buf[3] = cmd;
398141cc406Sopenharmony_ci
399141cc406Sopenharmony_ci  nb = 4;
400141cc406Sopenharmony_ci  CHK (sanei_pv8630_flush_buffer (scan->fd));
401141cc406Sopenharmony_ci  CHK (sanei_pv8630_prep_bulkwrite (scan->fd, nb));
402141cc406Sopenharmony_ci  CHK (sanei_pv8630_bulkwrite (scan->fd, buf, &nb));
403141cc406Sopenharmony_ci
404141cc406Sopenharmony_ci  CHK (sanei_pv8630_read_byte (scan->fd, PV8630_RDATA, &s0));
405141cc406Sopenharmony_ci  CHK (sanei_pv8630_read_byte (scan->fd, PV8630_RSTATUS, &s4));
406141cc406Sopenharmony_ci
407141cc406Sopenharmony_ci  DBG (90, "usync: s0 = %#x s4 = %#x\n", s0, s4);
408141cc406Sopenharmony_ci
409141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
410141cc406Sopenharmony_ci}
411141cc406Sopenharmony_ci
412141cc406Sopenharmony_ci/*
413141cc406Sopenharmony_ciThis function escapes any synchronization sequence that may be
414141cc406Sopenharmony_ciin data, storing the result in buf. In the worst case where
415141cc406Sopenharmony_cievery character gets escaped buf must be at least twice as
416141cc406Sopenharmony_cilarge as dlen.
417141cc406Sopenharmony_ci*/
418141cc406Sopenharmony_cistatic int
419141cc406Sopenharmony_cibescape (const unsigned char *data, int dlen, unsigned char *buf, int blen)
420141cc406Sopenharmony_ci{
421141cc406Sopenharmony_ci  const unsigned char *p;
422141cc406Sopenharmony_ci  unsigned char *q;
423141cc406Sopenharmony_ci  int i, c;
424141cc406Sopenharmony_ci  i = blen;   /* Eliminate compiler warning about unused param */
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci  p = data;
427141cc406Sopenharmony_ci  q = buf;
428141cc406Sopenharmony_ci  for (i = 0; i < dlen; ++i)
429141cc406Sopenharmony_ci    {
430141cc406Sopenharmony_ci      c = *p++;
431141cc406Sopenharmony_ci      if (c == UMAX_ESCAPE
432141cc406Sopenharmony_ci          || (c == UMAX_SYNC2 && i > 0 && p[-2] == UMAX_SYNC1))
433141cc406Sopenharmony_ci        *q++ = UMAX_ESCAPE;
434141cc406Sopenharmony_ci      *q++ = c;
435141cc406Sopenharmony_ci    }
436141cc406Sopenharmony_ci  return q - buf;
437141cc406Sopenharmony_ci}
438141cc406Sopenharmony_ci
439141cc406Sopenharmony_ci
440141cc406Sopenharmony_ci
441141cc406Sopenharmony_ci/* Write */
442141cc406Sopenharmony_ci
443141cc406Sopenharmony_cistatic SANE_Status
444141cc406Sopenharmony_cicwrite (UMAX_Handle * scan, UMAX_Cmd cmd, size_t len, const unsigned char *data,
445141cc406Sopenharmony_ci        UMAX_Status_Byte * s)
446141cc406Sopenharmony_ci{
447141cc406Sopenharmony_ci  SANE_Status res;
448141cc406Sopenharmony_ci  UMAX_Status_Byte s0, s4;
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ci  static unsigned char *escaped = NULL;
451141cc406Sopenharmony_ci  static size_t escaped_size = 0;
452141cc406Sopenharmony_ci
453141cc406Sopenharmony_ci  DBG (80, "cwrite: cmd = %d, len = %lu\n", cmd, (u_long) len);
454141cc406Sopenharmony_ci
455141cc406Sopenharmony_ci  CHK (usync (scan, cmd | CMD_WRITE, len));
456141cc406Sopenharmony_ci
457141cc406Sopenharmony_ci  if (len <= 0)
458141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
459141cc406Sopenharmony_ci
460141cc406Sopenharmony_ci  if (escaped_size < len * 2)
461141cc406Sopenharmony_ci    {
462141cc406Sopenharmony_ci      escaped_size = len * 2;
463141cc406Sopenharmony_ci      if (escaped)
464141cc406Sopenharmony_ci        free (escaped);
465141cc406Sopenharmony_ci      escaped = malloc (escaped_size);
466141cc406Sopenharmony_ci      if (escaped == NULL)
467141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
468141cc406Sopenharmony_ci    }
469141cc406Sopenharmony_ci
470141cc406Sopenharmony_ci  len = bescape (data, len, escaped, len * 2);
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci  CHK (sanei_pv8630_wait_byte
473141cc406Sopenharmony_ci       (scan->fd, PV8630_RSTATUS, UMAX_OK, UMAX_STATUS_MASK, 20));
474141cc406Sopenharmony_ci
475141cc406Sopenharmony_ci  CHK (sanei_pv8630_flush_buffer (scan->fd));
476141cc406Sopenharmony_ci  CHK (sanei_pv8630_prep_bulkwrite (scan->fd, len));
477141cc406Sopenharmony_ci  CHK (sanei_pv8630_bulkwrite (scan->fd, escaped, &len));
478141cc406Sopenharmony_ci
479141cc406Sopenharmony_ci  CHK (sanei_pv8630_read_byte (scan->fd, PV8630_RSTATUS, &s4));
480141cc406Sopenharmony_ci  CHK (sanei_pv8630_read_byte (scan->fd, PV8630_RDATA, &s0));
481141cc406Sopenharmony_ci
482141cc406Sopenharmony_ci  DBG (90, "cwrite: s0 = %#x s4 = %#x\n", s0, s4);
483141cc406Sopenharmony_ci
484141cc406Sopenharmony_ci  if (s)
485141cc406Sopenharmony_ci    *s = s0;
486141cc406Sopenharmony_ci
487141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
488141cc406Sopenharmony_ci}
489141cc406Sopenharmony_ci
490141cc406Sopenharmony_ci/* Read */
491141cc406Sopenharmony_ci
492141cc406Sopenharmony_cistatic SANE_Status
493141cc406Sopenharmony_cicread (UMAX_Handle * scan, UMAX_Cmd cmd, size_t len, unsigned char *data,
494141cc406Sopenharmony_ci       UMAX_Status_Byte * s)
495141cc406Sopenharmony_ci{
496141cc406Sopenharmony_ci  SANE_Status res;
497141cc406Sopenharmony_ci  UMAX_Status_Byte s0, s4;
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_ci  DBG (80, "cread: cmd = %d, len = %lu\n", cmd, (u_long) len);
500141cc406Sopenharmony_ci
501141cc406Sopenharmony_ci  CHK (usync (scan, cmd | CMD_READ, len));
502141cc406Sopenharmony_ci
503141cc406Sopenharmony_ci  if (len > 0)
504141cc406Sopenharmony_ci    {
505141cc406Sopenharmony_ci      CHK (sanei_pv8630_wait_byte
506141cc406Sopenharmony_ci           (scan->fd, PV8630_RSTATUS, UMAX_OK_WITH_MOTOR, UMAX_STATUS_MASK,
507141cc406Sopenharmony_ci            2000));
508141cc406Sopenharmony_ci
509141cc406Sopenharmony_ci      while (len > 0)
510141cc406Sopenharmony_ci        {
511141cc406Sopenharmony_ci          size_t req, n;
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci          req = n = (len > 0xf000) ? 0xf000 : len;
514141cc406Sopenharmony_ci          CHK (sanei_pv8630_prep_bulkread (scan->fd, n));
515141cc406Sopenharmony_ci          CHK (sanei_pv8630_bulkread (scan->fd, data, &n));
516141cc406Sopenharmony_ci          if (n < req)
517141cc406Sopenharmony_ci            {
518141cc406Sopenharmony_ci              DBG (1, "qread: Expecting to read %lu, only got %lu\n", (u_long) req, (u_long) n);
519141cc406Sopenharmony_ci              return SANE_STATUS_IO_ERROR;
520141cc406Sopenharmony_ci            }
521141cc406Sopenharmony_ci          data += n;
522141cc406Sopenharmony_ci          len -= n;
523141cc406Sopenharmony_ci        }
524141cc406Sopenharmony_ci    }
525141cc406Sopenharmony_ci
526141cc406Sopenharmony_ci  CHK (sanei_pv8630_read_byte (scan->fd, PV8630_RSTATUS, &s4));
527141cc406Sopenharmony_ci  CHK (sanei_pv8630_read_byte (scan->fd, PV8630_RDATA, &s0));
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci  DBG (90, "cwrite: s0 = %#x s4 = %#x\n", s0, s4);
530141cc406Sopenharmony_ci
531141cc406Sopenharmony_ci  if (s)
532141cc406Sopenharmony_ci    *s = s0;
533141cc406Sopenharmony_ci
534141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
535141cc406Sopenharmony_ci}
536141cc406Sopenharmony_ci
537141cc406Sopenharmony_ci
538141cc406Sopenharmony_ci
539141cc406Sopenharmony_ci/* Seems to be like cwrite, with a verification option */
540141cc406Sopenharmony_ci
541141cc406Sopenharmony_cistatic SANE_Status
542141cc406Sopenharmony_cicwritev (UMAX_Handle * scan, UMAX_Cmd cmd, size_t len, const unsigned char *data,
543141cc406Sopenharmony_ci         UMAX_Status_Byte * s)
544141cc406Sopenharmony_ci{
545141cc406Sopenharmony_ci  SANE_Status res;
546141cc406Sopenharmony_ci  unsigned char buf[16384];
547141cc406Sopenharmony_ci
548141cc406Sopenharmony_ci  /* Write out the opcode */
549141cc406Sopenharmony_ci
550141cc406Sopenharmony_ci  CHK (cwrite (scan, cmd, len, data, s));
551141cc406Sopenharmony_ci  if (len <= 0)
552141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
553141cc406Sopenharmony_ci
554141cc406Sopenharmony_ci  /* Read the opcode back */
555141cc406Sopenharmony_ci
556141cc406Sopenharmony_ci  CHK (cread (scan, cmd, len, buf, NULL));
557141cc406Sopenharmony_ci  if (bcmp (buf, data, len))
558141cc406Sopenharmony_ci    {
559141cc406Sopenharmony_ci      DBG (1, "cwritev: verification failed\n");
560141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
561141cc406Sopenharmony_ci    }
562141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
563141cc406Sopenharmony_ci}
564141cc406Sopenharmony_ci
565141cc406Sopenharmony_ci
566141cc406Sopenharmony_ci/* Send command */
567141cc406Sopenharmony_ci
568141cc406Sopenharmony_cistatic SANE_Status
569141cc406Sopenharmony_cicsend (UMAX_Handle * scan, UMAX_Cmd cmd)
570141cc406Sopenharmony_ci{
571141cc406Sopenharmony_ci  DBG (80, "csend: cmd = %d\n", cmd);
572141cc406Sopenharmony_ci
573141cc406Sopenharmony_ci  return usync (scan, cmd, 0);
574141cc406Sopenharmony_ci}
575141cc406Sopenharmony_ci
576141cc406Sopenharmony_ci/* Lamp control */
577141cc406Sopenharmony_ci
578141cc406Sopenharmony_cistatic SANE_Status
579141cc406Sopenharmony_cicwritev_opc1_lamp_ctrl (UMAX_Handle * scan, UMAX_Lamp_State state)
580141cc406Sopenharmony_ci{
581141cc406Sopenharmony_ci  unsigned char opc1[16] = {
582141cc406Sopenharmony_ci    0x01, 0x00, 0x01, 0x70, 0x00, 0x00, 0x60, 0x2f, 0x13, 0x05,
583141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x80, 0xf0, 0x00
584141cc406Sopenharmony_ci  };
585141cc406Sopenharmony_ci
586141cc406Sopenharmony_ci  DBG (9, "cwritev_opc1: set lamp state = %s\n",
587141cc406Sopenharmony_ci       (state == UMAX_LAMP_OFF) ? "off" : "on");
588141cc406Sopenharmony_ci  opc1[14] = (state == UMAX_LAMP_OFF) ? 0x90 : 0xf0;
589141cc406Sopenharmony_ci  return cwritev (scan, CMD_2, 16, opc1, NULL);
590141cc406Sopenharmony_ci}
591141cc406Sopenharmony_ci
592141cc406Sopenharmony_ci
593141cc406Sopenharmony_ci/* Restore Head 1220U */
594141cc406Sopenharmony_ci
595141cc406Sopenharmony_cistatic SANE_Status
596141cc406Sopenharmony_cicwritev_opb3_restore (UMAX_Handle * scan)
597141cc406Sopenharmony_ci{
598141cc406Sopenharmony_ci  unsigned char opb3[35] = {
599141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x03,
600141cc406Sopenharmony_ci    0xc1, 0x80, 0x00, 0x00, 0x04, 0x00, 0x16, 0x80, 0x15, 0x78,
601141cc406Sopenharmony_ci    0x03, 0x03, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x8b, 0x49, 0x4a,
602141cc406Sopenharmony_ci    0xd0, 0x68, 0xdf, 0x1b, 0x1a,
603141cc406Sopenharmony_ci  };
604141cc406Sopenharmony_ci
605141cc406Sopenharmony_ci  SANE_Status res;
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci  DBG (9, "cwritev_opb3_restore:\n");
608141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_8, 35, opb3, NULL));
609141cc406Sopenharmony_ci  CHK (csend (scan, CMD_40));
610141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
611141cc406Sopenharmony_ci}
612141cc406Sopenharmony_ci
613141cc406Sopenharmony_ci
614141cc406Sopenharmony_ci/* Restore Head 2100U */
615141cc406Sopenharmony_ci
616141cc406Sopenharmony_cistatic SANE_Status
617141cc406Sopenharmony_cicwritev_opb3_restore_2100U (UMAX_Handle * scan)
618141cc406Sopenharmony_ci{
619141cc406Sopenharmony_ci  unsigned char opb3[36] = {
620141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x03,
621141cc406Sopenharmony_ci    0xc1, 0x80, 0x00, 0x00, 0x04, 0x00, 0x16, 0x80, 0x15, 0x78,
622141cc406Sopenharmony_ci    0x03, 0x03, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x8b, 0x49, 0x2a,
623141cc406Sopenharmony_ci    0xe9, 0x68, 0xdf, 0x0b, 0x1a, 0x00
624141cc406Sopenharmony_ci  };
625141cc406Sopenharmony_ci
626141cc406Sopenharmony_ci  SANE_Status res;
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_ci  DBG (9, "cwritev_opb3_restore:\n");
629141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_8, 36, opb3, NULL));
630141cc406Sopenharmony_ci  CHK (csend (scan, CMD_40));
631141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
632141cc406Sopenharmony_ci}
633141cc406Sopenharmony_ci
634141cc406Sopenharmony_ci
635141cc406Sopenharmony_ci/* Initialize and turn lamp on 1220U */
636141cc406Sopenharmony_ci
637141cc406Sopenharmony_ci/*
638141cc406Sopenharmony_ciThis function seems to perform various things. First, it loads a default
639141cc406Sopenharmony_cigamma information (which is used for the calibration scan), returns the
640141cc406Sopenharmony_cihead to the park position, and turns the lamp on. This function used to
641141cc406Sopenharmony_cibe split up into two parts, umaxinit and umaxinit2.
642141cc406Sopenharmony_ci*/
643141cc406Sopenharmony_ci
644141cc406Sopenharmony_cistatic SANE_Status
645141cc406Sopenharmony_ciumaxinit (UMAX_Handle * scan)
646141cc406Sopenharmony_ci{
647141cc406Sopenharmony_ci  unsigned char opb[34] = {
648141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x03,
649141cc406Sopenharmony_ci    0xc1, 0x80, 0x60, 0x20, 0x00, 0x00, 0x16, 0x41, 0xe0, 0xac,
650141cc406Sopenharmony_ci    0x03, 0x03, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x00, 0x00, 0x00,
651141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0xf0
652141cc406Sopenharmony_ci  };
653141cc406Sopenharmony_ci  unsigned char opb1[35] = {
654141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x03,
655141cc406Sopenharmony_ci    0xc1, 0x80, 0x00, 0x20, 0x02, 0x00, 0x16, 0x41, 0xe0, 0xac,
656141cc406Sopenharmony_ci    0x03, 0x03, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x00, 0x00, 0x00,
657141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x10, 0x1a
658141cc406Sopenharmony_ci  };
659141cc406Sopenharmony_ci  unsigned char opb2[35] = {
660141cc406Sopenharmony_ci    0x00, 0x00, 0x06, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x03,
661141cc406Sopenharmony_ci    0xc1, 0x80, 0x00, 0x20, 0x02, 0x00, 0x16, 0x41, 0xe0, 0xac,
662141cc406Sopenharmony_ci    0x03, 0x03, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x00, 0x00, 0x00,
663141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x10, 0x1a
664141cc406Sopenharmony_ci  };
665141cc406Sopenharmony_ci  unsigned char opb4[35] = {
666141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x03,
667141cc406Sopenharmony_ci    0xc1, 0x80, 0x60, 0x20, 0x00, 0x00, 0x16, 0x41, 0xe0, 0xac,
668141cc406Sopenharmony_ci    0x03, 0x03, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x8b, 0x49, 0x4a,
669141cc406Sopenharmony_ci    0xd0, 0x68, 0xdf, 0xf3, 0x1b
670141cc406Sopenharmony_ci  };
671141cc406Sopenharmony_ci  unsigned char opbx[35];
672141cc406Sopenharmony_ci  unsigned char opc[16] = {
673141cc406Sopenharmony_ci    0x02, 0x80, 0x00, 0x70, 0x00, 0x00, 0x60, 0x2f, 0x2f, 0x07,
674141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x80, 0xf0, 0x00
675141cc406Sopenharmony_ci  };
676141cc406Sopenharmony_ci  unsigned char opcx[16];
677141cc406Sopenharmony_ci  unsigned char opd[8] = {
678141cc406Sopenharmony_ci    0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa
679141cc406Sopenharmony_ci  };
680141cc406Sopenharmony_ci
681141cc406Sopenharmony_ci  SANE_Status res;
682141cc406Sopenharmony_ci  UMAX_Status_Byte s;
683141cc406Sopenharmony_ci  unsigned char ramp[800];
684141cc406Sopenharmony_ci  int i;
685141cc406Sopenharmony_ci  unsigned char *p;
686141cc406Sopenharmony_ci
687141cc406Sopenharmony_ci  DBG (3, "umaxinit called\n");
688141cc406Sopenharmony_ci
689141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
690141cc406Sopenharmony_ci  CHK (xxxops (scan));
691141cc406Sopenharmony_ci
692141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_8, 34, opb, &s));
693141cc406Sopenharmony_ci  CHK (cread (scan, CMD_8, 35, opbx, &s));
694141cc406Sopenharmony_ci
695141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_8, 35, opb1, &s));
696141cc406Sopenharmony_ci
697141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
698141cc406Sopenharmony_ci
699141cc406Sopenharmony_ci  DBG (4, "umaxinit: checkpoint 2:\n");
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci  /* The following code appears to send three 256 entry, 8-bit gamma tables
702141cc406Sopenharmony_ci   * to the scanner
703141cc406Sopenharmony_ci   */
704141cc406Sopenharmony_ci  p = ramp;
705141cc406Sopenharmony_ci  *p++ = 0;
706141cc406Sopenharmony_ci  *p++ = 0;
707141cc406Sopenharmony_ci  *p++ = 0;
708141cc406Sopenharmony_ci  for (i = 0; i < 256; ++i)
709141cc406Sopenharmony_ci    *p++ = i;
710141cc406Sopenharmony_ci  for (i = 0; i < 256; ++i)
711141cc406Sopenharmony_ci    *p++ = i;
712141cc406Sopenharmony_ci  for (i = 0; i < 256; ++i)
713141cc406Sopenharmony_ci    *p++ = i;
714141cc406Sopenharmony_ci  *p++ = 0xaa;
715141cc406Sopenharmony_ci  *p++ = 0xaa;
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci  res = cwritev (scan, CMD_4, p - ramp, ramp, &s);
718141cc406Sopenharmony_ci  if (res != SANE_STATUS_GOOD)
719141cc406Sopenharmony_ci    {
720141cc406Sopenharmony_ci      DBG (4, "umaxinit: Writing ramp 1 failed (is this a 2000U?)\n");
721141cc406Sopenharmony_ci    }
722141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_8, 35, opb1, &s));
723141cc406Sopenharmony_ci
724141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
725141cc406Sopenharmony_ci
726141cc406Sopenharmony_ci  DBG (4, "umaxinit: checkpoint 3:\n");
727141cc406Sopenharmony_ci
728141cc406Sopenharmony_ci  /* The following code appears to send a 256 entry, 16-bit gamma table
729141cc406Sopenharmony_ci   * to the scanner
730141cc406Sopenharmony_ci   */
731141cc406Sopenharmony_ci  p = ramp;
732141cc406Sopenharmony_ci  for (i = 0; i < 256; ++i)
733141cc406Sopenharmony_ci    {
734141cc406Sopenharmony_ci      *p++ = i;
735141cc406Sopenharmony_ci      *p++ = 0;
736141cc406Sopenharmony_ci    }
737141cc406Sopenharmony_ci
738141cc406Sopenharmony_ci  res = cwrite (scan, CMD_4, p - ramp, ramp, &s);
739141cc406Sopenharmony_ci  if (res != SANE_STATUS_GOOD)
740141cc406Sopenharmony_ci    {
741141cc406Sopenharmony_ci      DBG (4, "umaxinit: Writing ramp 2 failed (is this a 2000U?)\n");
742141cc406Sopenharmony_ci    }
743141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_8, 35, opb2, &s));
744141cc406Sopenharmony_ci
745141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
746141cc406Sopenharmony_ci
747141cc406Sopenharmony_ci  DBG (4, "umaxinit: checkpoint 4:\n");
748141cc406Sopenharmony_ci
749141cc406Sopenharmony_ci  /* The following code appears to send a 256 entry, 16-bit gamma table
750141cc406Sopenharmony_ci   * to the scanner.
751141cc406Sopenharmony_ci   */
752141cc406Sopenharmony_ci  p = ramp;
753141cc406Sopenharmony_ci  for (i = 0; i < 256; ++i)
754141cc406Sopenharmony_ci    {
755141cc406Sopenharmony_ci      *p++ = i;
756141cc406Sopenharmony_ci      *p++ = 4;
757141cc406Sopenharmony_ci    }
758141cc406Sopenharmony_ci
759141cc406Sopenharmony_ci  res = cwritev (scan, CMD_4, p - ramp, ramp, &s);
760141cc406Sopenharmony_ci  if (res != SANE_STATUS_GOOD)
761141cc406Sopenharmony_ci    {
762141cc406Sopenharmony_ci      DBG (4, "umaxinit: Writing ramp 3 failed (is this a 2000U?)\n");
763141cc406Sopenharmony_ci    }
764141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_8, 35, opb1, &s));
765141cc406Sopenharmony_ci
766141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_2, 16, opc, NULL));
767141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_1, 8, opd, NULL));
768141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
769141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
770141cc406Sopenharmony_ci
771141cc406Sopenharmony_ci  DBG (4, "umaxinit: checkpoint 5: s = %#x\n", s);
772141cc406Sopenharmony_ci
773141cc406Sopenharmony_ci  if ((s & 0x40) == 0)
774141cc406Sopenharmony_ci    {
775141cc406Sopenharmony_ci      DBG (4, "umaxinit: turning on lamp and restoring\n");
776141cc406Sopenharmony_ci      CHK (cwritev_opc1_lamp_ctrl (scan, UMAX_LAMP_ON));
777141cc406Sopenharmony_ci      CHK (cwritev_opb3_restore (scan));
778141cc406Sopenharmony_ci
779141cc406Sopenharmony_ci      for (i = 0; i < 60; ++i)
780141cc406Sopenharmony_ci        {
781141cc406Sopenharmony_ci          CHK (cread (scan, CMD_2, 0, NULL, &s));
782141cc406Sopenharmony_ci          DBG (4, "umaxinit: s = %#x\n", s);
783141cc406Sopenharmony_ci          if ((s & 0x40) != 0)
784141cc406Sopenharmony_ci            break;
785141cc406Sopenharmony_ci          DBG (4, "umaxinit: sleeping\n");
786141cc406Sopenharmony_ci          usleep (500000);
787141cc406Sopenharmony_ci        }
788141cc406Sopenharmony_ci    }
789141cc406Sopenharmony_ci
790141cc406Sopenharmony_ci  DBG (4, "umaxinit: checkpoint 6\n");
791141cc406Sopenharmony_ci
792141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
793141cc406Sopenharmony_ci
794141cc406Sopenharmony_ci  /* The following stuff used to be in umaxinit2() */
795141cc406Sopenharmony_ci
796141cc406Sopenharmony_ci  DBG (4, "umaxinit: checkpoint 7\n");
797141cc406Sopenharmony_ci
798141cc406Sopenharmony_ci  CHK (xxxops (scan));
799141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
800141cc406Sopenharmony_ci  CHK (xxxops (scan));
801141cc406Sopenharmony_ci
802141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_8, 34, opb4, &s));
803141cc406Sopenharmony_ci  CHK (cread (scan, CMD_8, 35, opbx, &s));
804141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 16, opcx, &s));
805141cc406Sopenharmony_ci
806141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_2, 16, opc, NULL));
807141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_1, 8, opd, NULL));
808141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
809141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
810141cc406Sopenharmony_ci
811141cc406Sopenharmony_ci  DBG (4, "umaxinit: checkpoint 8: s = %d\n", s);
812141cc406Sopenharmony_ci
813141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
814141cc406Sopenharmony_ci}
815141cc406Sopenharmony_ci
816141cc406Sopenharmony_ci/* Initialize and turn lamp on 2100U */
817141cc406Sopenharmony_ci
818141cc406Sopenharmony_cistatic SANE_Status
819141cc406Sopenharmony_ciumaxinit_2100U (UMAX_Handle * scan)
820141cc406Sopenharmony_ci{
821141cc406Sopenharmony_ci
822141cc406Sopenharmony_ci  unsigned char opx[36];
823141cc406Sopenharmony_ci  unsigned char opy[16];
824141cc406Sopenharmony_ci
825141cc406Sopenharmony_ci
826141cc406Sopenharmony_ci  SANE_Status res;
827141cc406Sopenharmony_ci  UMAX_Status_Byte s;
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci  DBG (3, "umaxinit called\n");
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci  CHK (xxxops (scan));
832141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
833141cc406Sopenharmony_ci
834141cc406Sopenharmony_ci  /* Turn lamp on */
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ci  cwritev_opc1_lamp_ctrl (scan, UMAX_LAMP_ON);
837141cc406Sopenharmony_ci
838141cc406Sopenharmony_ci  CHK (cread (scan, CMD_8, 36, opx, &s));
839141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 16, opy, &s));
840141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
841141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
842141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
843141cc406Sopenharmony_ci
844141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
845141cc406Sopenharmony_ci}
846141cc406Sopenharmony_ci
847141cc406Sopenharmony_ci
848141cc406Sopenharmony_ci/* Move head 1220U */
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_cistatic SANE_Status
851141cc406Sopenharmony_cimove (UMAX_Handle * scan, int distance, UMAX_Speed fine)
852141cc406Sopenharmony_ci{
853141cc406Sopenharmony_ci  unsigned char opc4[16] = {
854141cc406Sopenharmony_ci    0x01, XXXX, XXXX, XXXX, 0x00, 0x00, 0x60, 0x2f, XXXX, XXXX,
855141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x80, XXXX, 0x00
856141cc406Sopenharmony_ci  };
857141cc406Sopenharmony_ci  unsigned char opb5[35] = {
858141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x04,
859141cc406Sopenharmony_ci    0x40, 0x01, 0x00, 0x00, 0x04, 0x00, 0x6e, 0xf6, 0x79, 0xbf,
860141cc406Sopenharmony_ci    0x06, 0x00, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x8b, 0x49, 0x4a,
861141cc406Sopenharmony_ci    0xd0, 0x68, 0xdf, 0x13, 0x1a
862141cc406Sopenharmony_ci  };
863141cc406Sopenharmony_ci  unsigned char opb7[35] = {
864141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
865141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x6e, 0xf6, 0x79, 0xbf,
866141cc406Sopenharmony_ci    0x01, 0x00, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x8b, 0x49, 0x4a,
867141cc406Sopenharmony_ci    0xd0, 0x68, 0xdf, 0x13, 0x1a
868141cc406Sopenharmony_ci  };
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_ci  unsigned char ope[8] = {
871141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
872141cc406Sopenharmony_ci  };
873141cc406Sopenharmony_ci
874141cc406Sopenharmony_ci  unsigned char ope2[3] = {
875141cc406Sopenharmony_ci    0x00, 0xff, 0x8f
876141cc406Sopenharmony_ci  };
877141cc406Sopenharmony_ci  unsigned char buf[512 + PAD];
878141cc406Sopenharmony_ci
879141cc406Sopenharmony_ci  SANE_Status res;
880141cc406Sopenharmony_ci  UMAX_Status_Byte s;
881141cc406Sopenharmony_ci
882141cc406Sopenharmony_ci  SANE_Bool rev = distance < 0;
883141cc406Sopenharmony_ci  int skip = (rev ? -distance : distance) - 1;
884141cc406Sopenharmony_ci
885141cc406Sopenharmony_ci  DBG (9, "move: distance = %d, scanner_ypos = %d\n", distance,
886141cc406Sopenharmony_ci       scan->scanner_ypos);
887141cc406Sopenharmony_ci
888141cc406Sopenharmony_ci  PAD_ARRAY (buf, 512);
889141cc406Sopenharmony_ci
890141cc406Sopenharmony_ci  if (distance == 0)
891141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
892141cc406Sopenharmony_ci
893141cc406Sopenharmony_ci  opc4[1] = skip << 6;
894141cc406Sopenharmony_ci  opc4[2] = skip >> 2;
895141cc406Sopenharmony_ci  opc4[3] = (rev ? 0x20 : 0x70) + ((skip >> 10) & 0xf);
896141cc406Sopenharmony_ci  opc4[9] = rev ? 0x01 : 0x05;
897141cc406Sopenharmony_ci
898141cc406Sopenharmony_ci  if (fine == UMAX_FINE)
899141cc406Sopenharmony_ci    {
900141cc406Sopenharmony_ci      opc4[8]  = 0x2f;
901141cc406Sopenharmony_ci      opc4[14] = 0xa4;
902141cc406Sopenharmony_ci    }
903141cc406Sopenharmony_ci  else
904141cc406Sopenharmony_ci    {
905141cc406Sopenharmony_ci      opc4[8]  = 0x17;
906141cc406Sopenharmony_ci      opc4[14] = 0xac;
907141cc406Sopenharmony_ci    }
908141cc406Sopenharmony_ci
909141cc406Sopenharmony_ci  scan->scanner_ypos +=
910141cc406Sopenharmony_ci    (fine == UMAX_FINE ? distance : 2 * distance + (rev ? -1 : 1));
911141cc406Sopenharmony_ci  scan->scanner_ypos = (scan->scanner_ypos + (rev ? 0 : 3)) & ~3;
912141cc406Sopenharmony_ci
913141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_2, 16, opc4, &s));
914141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_8, 35, rev ? opb7 : opb5, &s));
915141cc406Sopenharmony_ci
916141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
917141cc406Sopenharmony_ci  DBG (10, "move: checkpoint 1: s = %d\n", s);
918141cc406Sopenharmony_ci
919141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
920141cc406Sopenharmony_ci  if (rev)
921141cc406Sopenharmony_ci    CHK (cwrite (scan, CMD_4, 3, ope2, &s))
922141cc406Sopenharmony_ci  else
923141cc406Sopenharmony_ci    CHK (cwrite (scan, CMD_4, 8, ope, &s));
924141cc406Sopenharmony_ci
925141cc406Sopenharmony_ci
926141cc406Sopenharmony_ci  CHK (csend (scan, CMD_40));
927141cc406Sopenharmony_ci
928141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
929141cc406Sopenharmony_ci
930141cc406Sopenharmony_ci  DBG (10, "move: checkpoint 2: s = %d\n", s);
931141cc406Sopenharmony_ci
932141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
933141cc406Sopenharmony_ci  DBG (10, "move: checkpoint 3: s = %d\n", s);
934141cc406Sopenharmony_ci
935141cc406Sopenharmony_ci  CHK (cread (scan, CMD_4, 512, buf, &s));
936141cc406Sopenharmony_ci
937141cc406Sopenharmony_ci  CHK_ARRAY (buf, 512);
938141cc406Sopenharmony_ci
939141cc406Sopenharmony_ci  return res;
940141cc406Sopenharmony_ci}
941141cc406Sopenharmony_ci
942141cc406Sopenharmony_ci
943141cc406Sopenharmony_ci
944141cc406Sopenharmony_ci/* Move head 2100U */
945141cc406Sopenharmony_ci
946141cc406Sopenharmony_cistatic SANE_Status
947141cc406Sopenharmony_cimove_2100U (UMAX_Handle * scan, int distance, UMAX_Speed fine)
948141cc406Sopenharmony_ci{
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci
951141cc406Sopenharmony_ci  unsigned char opc4[16] = {
952141cc406Sopenharmony_ci    0x01, XXXX, XXXX, XXXX, 0x00, 0x00, 0x60, 0x2f, XXXX, XXXX,
953141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x80, XXXX, 0x00
954141cc406Sopenharmony_ci  };
955141cc406Sopenharmony_ci  unsigned char opb5[36] = {
956141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x04,
957141cc406Sopenharmony_ci    0x40, 0x01, 0x00, 0x00, 0x04, 0x00, 0x6e, 0xf6, 0x79, 0xbf,
958141cc406Sopenharmony_ci    0x06, 0x00, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x8b, 0x49, 0x2a,
959141cc406Sopenharmony_ci    0xe9, 0x68, 0xdf, 0x03, 0x1a, 0x00
960141cc406Sopenharmony_ci  };
961141cc406Sopenharmony_ci  unsigned char opb7[36] = {
962141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
963141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x6e, 0xf6, 0x79, 0xbf,
964141cc406Sopenharmony_ci    0x01, 0x00, 0x00, 0x00, 0x46, 0xa0, 0x00, 0x8b, 0x49, 0x2a,
965141cc406Sopenharmony_ci    0xe9, 0x68, 0xdf, 0x03, 0x1a, 0x00
966141cc406Sopenharmony_ci  };
967141cc406Sopenharmony_ci  unsigned char ope[8] = {
968141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
969141cc406Sopenharmony_ci  };
970141cc406Sopenharmony_ci  unsigned char ope2[3] = {
971141cc406Sopenharmony_ci    0x00, 0xff, 0xff
972141cc406Sopenharmony_ci  };
973141cc406Sopenharmony_ci  unsigned char buf[512];
974141cc406Sopenharmony_ci
975141cc406Sopenharmony_ci
976141cc406Sopenharmony_ci  SANE_Status res;
977141cc406Sopenharmony_ci  UMAX_Status_Byte s;
978141cc406Sopenharmony_ci
979141cc406Sopenharmony_ci  SANE_Bool rev = distance < 0;
980141cc406Sopenharmony_ci  int skip = (rev ? -distance : distance) - 1;
981141cc406Sopenharmony_ci
982141cc406Sopenharmony_ci  DBG (9, "move: distance = %d, scanner_ypos = %d\n", distance,
983141cc406Sopenharmony_ci       scan->scanner_ypos);
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci  PAD_ARRAY (buf, 512);
986141cc406Sopenharmony_ci
987141cc406Sopenharmony_ci  if (distance == 0)
988141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
989141cc406Sopenharmony_ci
990141cc406Sopenharmony_ci  opc4[1] = skip << 6;
991141cc406Sopenharmony_ci  opc4[2] = skip >> 2;
992141cc406Sopenharmony_ci  opc4[3] = (rev ? 0x20 : 0x70) + ((skip >> 10) & 0x0f);
993141cc406Sopenharmony_ci  opc4[9] = rev ? 0x01 : 0x05;
994141cc406Sopenharmony_ci
995141cc406Sopenharmony_ci  if (fine == UMAX_FINE)
996141cc406Sopenharmony_ci    {
997141cc406Sopenharmony_ci      opc4[8]  = 0x2b;
998141cc406Sopenharmony_ci      opc4[14] = 0xa4;
999141cc406Sopenharmony_ci    }
1000141cc406Sopenharmony_ci  else
1001141cc406Sopenharmony_ci    {
1002141cc406Sopenharmony_ci      opc4[8]  = 0x15;
1003141cc406Sopenharmony_ci      opc4[14] = 0xac;
1004141cc406Sopenharmony_ci    }
1005141cc406Sopenharmony_ci
1006141cc406Sopenharmony_ci  scan->scanner_ypos +=
1007141cc406Sopenharmony_ci    (fine == UMAX_FINE ? distance : 2 * distance + (rev ? -1 : 1));
1008141cc406Sopenharmony_ci  scan->scanner_ypos = (scan->scanner_ypos + (rev ? 0 : 3)) & ~3;
1009141cc406Sopenharmony_ci
1010141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_2, 16, opc4, &s));
1011141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_8, 36, rev ? opb7 : opb5, &s));
1012141cc406Sopenharmony_ci
1013141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1014141cc406Sopenharmony_ci  DBG (10, "move: checkpoint 1: s = %d\n", s);
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
1017141cc406Sopenharmony_ci
1018141cc406Sopenharmony_ci  if (rev)
1019141cc406Sopenharmony_ci    CHK (cwrite (scan, CMD_4, 3, ope2, &s))
1020141cc406Sopenharmony_ci  else
1021141cc406Sopenharmony_ci    CHK (cwrite (scan, CMD_4, 8, ope, &s));
1022141cc406Sopenharmony_ci
1023141cc406Sopenharmony_ci  CHK (csend (scan, CMD_40));
1024141cc406Sopenharmony_ci
1025141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1026141cc406Sopenharmony_ci
1027141cc406Sopenharmony_ci  DBG (10, "move: checkpoint 2: s = %d\n", s);
1028141cc406Sopenharmony_ci
1029141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1030141cc406Sopenharmony_ci  DBG (10, "move: checkpoint 3: s = %d\n", s);
1031141cc406Sopenharmony_ci
1032141cc406Sopenharmony_ci  CHK (cread (scan, CMD_4, 512, buf, &s));
1033141cc406Sopenharmony_ci
1034141cc406Sopenharmony_ci  CHK_ARRAY (buf, 512);
1035141cc406Sopenharmony_ci
1036141cc406Sopenharmony_ci  return res;
1037141cc406Sopenharmony_ci}
1038141cc406Sopenharmony_ci
1039141cc406Sopenharmony_ci
1040141cc406Sopenharmony_ci/* Get pixel image 1220U */
1041141cc406Sopenharmony_ci
1042141cc406Sopenharmony_cistatic SANE_Status
1043141cc406Sopenharmony_ciget_pixels (UMAX_Handle * scan, unsigned char *op2, unsigned char *op8,
1044141cc406Sopenharmony_ci            unsigned char *op1, unsigned char *op4, int len, int zpos,
1045141cc406Sopenharmony_ci            unsigned char *buf)
1046141cc406Sopenharmony_ci{
1047141cc406Sopenharmony_ci  SANE_Status res;
1048141cc406Sopenharmony_ci  UMAX_Status_Byte s;
1049141cc406Sopenharmony_ci
1050141cc406Sopenharmony_ci  DBG (9, "get_pixels: len = %d, zpos = %d\n", len, zpos);
1051141cc406Sopenharmony_ci
1052141cc406Sopenharmony_ci  if (zpos == 0)
1053141cc406Sopenharmony_ci    CHK (csend (scan, CMD_0));
1054141cc406Sopenharmony_ci
1055141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_2, 16, op2, &s));
1056141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_8, 35, op8, &s));
1057141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_1, 8, op1, &s));
1058141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1059141cc406Sopenharmony_ci
1060141cc406Sopenharmony_ci  if (zpos == 1)
1061141cc406Sopenharmony_ci    CHK (csend (scan, CMD_0));
1062141cc406Sopenharmony_ci
1063141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_4, 8, op4, &s));
1064141cc406Sopenharmony_ci  CHK (csend (scan, CMD_40));
1065141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1066141cc406Sopenharmony_ci
1067141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1068141cc406Sopenharmony_ci
1069141cc406Sopenharmony_ci  CHK (cread (scan, CMD_4, len, buf, &s));
1070141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1071141cc406Sopenharmony_ci}
1072141cc406Sopenharmony_ci
1073141cc406Sopenharmony_ci
1074141cc406Sopenharmony_ci/* Get pixel image 2100U */
1075141cc406Sopenharmony_ci
1076141cc406Sopenharmony_cistatic SANE_Status
1077141cc406Sopenharmony_ciget_pixels_2100U (UMAX_Handle * scan, unsigned char *op2, unsigned char *op8,
1078141cc406Sopenharmony_ci            unsigned char *op1, unsigned char *op4, int len, int zpos,
1079141cc406Sopenharmony_ci            unsigned char *buf)
1080141cc406Sopenharmony_ci{
1081141cc406Sopenharmony_ci  SANE_Status res;
1082141cc406Sopenharmony_ci  UMAX_Status_Byte s;
1083141cc406Sopenharmony_ci
1084141cc406Sopenharmony_ci  DBG (9, "get_pixels: len = %d, zpos = %d\n", len, zpos);
1085141cc406Sopenharmony_ci
1086141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_2, 16, op2, &s));
1087141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_8, 36, op8, &s));
1088141cc406Sopenharmony_ci
1089141cc406Sopenharmony_ci  if (zpos == 1)
1090141cc406Sopenharmony_ci    CHK (cwritev (scan, CMD_1, 8, op1, &s))
1091141cc406Sopenharmony_ci  else
1092141cc406Sopenharmony_ci    CHK (cwrite (scan, CMD_1, 8, op1, &s));
1093141cc406Sopenharmony_ci
1094141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1095141cc406Sopenharmony_ci
1096141cc406Sopenharmony_ci  if (zpos == 1)
1097141cc406Sopenharmony_ci    CHK (csend (scan, CMD_0));
1098141cc406Sopenharmony_ci
1099141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_4, 8, op4, &s));
1100141cc406Sopenharmony_ci  CHK (csend (scan, CMD_40));
1101141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1102141cc406Sopenharmony_ci
1103141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1104141cc406Sopenharmony_ci
1105141cc406Sopenharmony_ci  CHK (cread (scan, CMD_4, len, buf, &s));
1106141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1107141cc406Sopenharmony_ci}
1108141cc406Sopenharmony_ci
1109141cc406Sopenharmony_ci
1110141cc406Sopenharmony_ci/* This function locates the black stripe under scanner lid */
1111141cc406Sopenharmony_ci
1112141cc406Sopenharmony_cistatic int
1113141cc406Sopenharmony_cilocate_black_stripe (unsigned char *img, int w, int h)
1114141cc406Sopenharmony_ci{
1115141cc406Sopenharmony_ci  int epos, ecnt, x, y;
1116141cc406Sopenharmony_ci  unsigned char *p;
1117141cc406Sopenharmony_ci
1118141cc406Sopenharmony_ci  epos = 0;
1119141cc406Sopenharmony_ci  ecnt = 0;
1120141cc406Sopenharmony_ci  p = img;
1121141cc406Sopenharmony_ci  for (x = 0; x < w; ++x, ++p)
1122141cc406Sopenharmony_ci    {
1123141cc406Sopenharmony_ci      int d, dmax = 0, dpos = 0;
1124141cc406Sopenharmony_ci      unsigned char *q = img + x;
1125141cc406Sopenharmony_ci      for (y = 1; y < h; ++y, q += w)
1126141cc406Sopenharmony_ci        {
1127141cc406Sopenharmony_ci          d = q[0] - q[w];
1128141cc406Sopenharmony_ci          if (d > dmax)
1129141cc406Sopenharmony_ci            {
1130141cc406Sopenharmony_ci              dmax = d;
1131141cc406Sopenharmony_ci              dpos = y;
1132141cc406Sopenharmony_ci            }
1133141cc406Sopenharmony_ci        }
1134141cc406Sopenharmony_ci      if (dmax > 0)
1135141cc406Sopenharmony_ci        {
1136141cc406Sopenharmony_ci          epos += dpos;
1137141cc406Sopenharmony_ci          ++ecnt;
1138141cc406Sopenharmony_ci        }
1139141cc406Sopenharmony_ci    }
1140141cc406Sopenharmony_ci  if (ecnt == 0)
1141141cc406Sopenharmony_ci    epos = 70;
1142141cc406Sopenharmony_ci  else
1143141cc406Sopenharmony_ci    epos = (epos + ecnt / 2) / ecnt;
1144141cc406Sopenharmony_ci  return epos;
1145141cc406Sopenharmony_ci}
1146141cc406Sopenharmony_ci
1147141cc406Sopenharmony_ci
1148141cc406Sopenharmony_ci/* To find the lowest head position 1220U */
1149141cc406Sopenharmony_ci
1150141cc406Sopenharmony_cistatic SANE_Status
1151141cc406Sopenharmony_cifind_zero (UMAX_Handle * scan)
1152141cc406Sopenharmony_ci{
1153141cc406Sopenharmony_ci  unsigned char opc3[16] = {
1154141cc406Sopenharmony_ci    0xb4, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x2f, 0x2f, 0x05,
1155141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x80, 0xa4, 0x00
1156141cc406Sopenharmony_ci  };
1157141cc406Sopenharmony_ci  unsigned char ope1[8] = {
1158141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0xaa, 0xcc, 0xee, 0x80, 0xff
1159141cc406Sopenharmony_ci  };
1160141cc406Sopenharmony_ci  unsigned char opb6[35] = {
1161141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x04,
1162141cc406Sopenharmony_ci    0x40, 0x01, 0x00, 0x00, 0x04, 0x00, 0x6e, 0xfb, 0xc4, 0xe5,
1163141cc406Sopenharmony_ci    0x06, 0x00, 0x00, 0x60, 0x4d, 0xa0, 0x00, 0x8b, 0x49, 0x4a,
1164141cc406Sopenharmony_ci    0xd0, 0x68, 0xdf, 0x13, 0x1a
1165141cc406Sopenharmony_ci  };
1166141cc406Sopenharmony_ci  unsigned char opd1[8] = {
1167141cc406Sopenharmony_ci    0x06, 0xf4, 0xff, 0x81, 0x3d, 0x00, 0x08, 0x00
1168141cc406Sopenharmony_ci  };
1169141cc406Sopenharmony_ci
1170141cc406Sopenharmony_ci  SANE_Status res;
1171141cc406Sopenharmony_ci  int s;
1172141cc406Sopenharmony_ci  unsigned char *img;
1173141cc406Sopenharmony_ci
1174141cc406Sopenharmony_ci  DBG (9, "find_zero:\n");
1175141cc406Sopenharmony_ci
1176141cc406Sopenharmony_ci  img = malloc (54000);
1177141cc406Sopenharmony_ci  if (img == 0)
1178141cc406Sopenharmony_ci    {
1179141cc406Sopenharmony_ci      DBG (1, "out of memory (need 54000)\n");
1180141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1181141cc406Sopenharmony_ci    }
1182141cc406Sopenharmony_ci
1183141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
1184141cc406Sopenharmony_ci  CHK (get_pixels (scan, opc3, opb6, opd1, ope1, 54000, 1, img));
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci#ifdef DEBUG_CALIBRATION
1187141cc406Sopenharmony_ci  {
1188141cc406Sopenharmony_ci    int w = 300, h = 180;
1189141cc406Sopenharmony_ci    FILE *f2 = fopen ("find_zero.pgm", "wb");
1190141cc406Sopenharmony_ci    fprintf (f2, "P5\n%d %d\n255\n", w, h);
1191141cc406Sopenharmony_ci    fwrite (img, 1, w * h, f2);
1192141cc406Sopenharmony_ci    fclose (f2);
1193141cc406Sopenharmony_ci  }
1194141cc406Sopenharmony_ci#endif
1195141cc406Sopenharmony_ci
1196141cc406Sopenharmony_ci  s = locate_black_stripe (img, 300, 180);
1197141cc406Sopenharmony_ci  scan->scanner_yorg = scan->scanner_ypos + s + 64;
1198141cc406Sopenharmony_ci  scan->scanner_ypos += 180 + 3;
1199141cc406Sopenharmony_ci  scan->scanner_ypos &= ~3;
1200141cc406Sopenharmony_ci
1201141cc406Sopenharmony_ci  free (img);
1202141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1203141cc406Sopenharmony_ci}
1204141cc406Sopenharmony_ci
1205141cc406Sopenharmony_ci
1206141cc406Sopenharmony_ci/* To find the lowest head position 2100U */
1207141cc406Sopenharmony_ci
1208141cc406Sopenharmony_cistatic SANE_Status
1209141cc406Sopenharmony_cifind_zero_2100U (UMAX_Handle * scan)
1210141cc406Sopenharmony_ci{
1211141cc406Sopenharmony_ci  unsigned char opc3[16] = {
1212141cc406Sopenharmony_ci    0xb4, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x2f, 0x2b, 0x05,
1213141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x80, 0xa4, 0x00
1214141cc406Sopenharmony_ci  };
1215141cc406Sopenharmony_ci  unsigned char ope1[8] = {
1216141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0xaa, 0xcc, 0xee, 0x80, 0xff
1217141cc406Sopenharmony_ci  };
1218141cc406Sopenharmony_ci  unsigned char opb6[36] = {
1219141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x04,
1220141cc406Sopenharmony_ci    0x40, 0x01, 0x00, 0x00, 0x04, 0x00, 0x6e, 0xfb, 0xc4, 0xe5,
1221141cc406Sopenharmony_ci    0x06, 0x00, 0x00, 0x60, 0x4d, 0xa0, 0x00, 0x8b, 0x49, 0x2a,
1222141cc406Sopenharmony_ci    0xe9, 0x68, 0xdf, 0x03, 0x1a, 0x00
1223141cc406Sopenharmony_ci  };
1224141cc406Sopenharmony_ci  unsigned char opd1[8] = {
1225141cc406Sopenharmony_ci    0x06, 0xf4, 0xff, 0x81, 0x1b, 0x00, 0x08, 0x00
1226141cc406Sopenharmony_ci  };
1227141cc406Sopenharmony_ci
1228141cc406Sopenharmony_ci  SANE_Status res;
1229141cc406Sopenharmony_ci  int s;
1230141cc406Sopenharmony_ci  unsigned char *img;
1231141cc406Sopenharmony_ci
1232141cc406Sopenharmony_ci  DBG (9, "find_zero:\n");
1233141cc406Sopenharmony_ci
1234141cc406Sopenharmony_ci  img = malloc (54000);
1235141cc406Sopenharmony_ci  if (img == 0)
1236141cc406Sopenharmony_ci    {
1237141cc406Sopenharmony_ci      DBG (1, "out of memory (need 54000)\n");
1238141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1239141cc406Sopenharmony_ci    }
1240141cc406Sopenharmony_ci
1241141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
1242141cc406Sopenharmony_ci  CHK (get_pixels_2100U (scan, opc3, opb6, opd1, ope1, 54000, 1, img));
1243141cc406Sopenharmony_ci
1244141cc406Sopenharmony_ci#ifdef DEBUG_CALIBRATION
1245141cc406Sopenharmony_ci  {
1246141cc406Sopenharmony_ci    int w = 300, h = 180;
1247141cc406Sopenharmony_ci    FILE *f2 = fopen ("find_zero.pgm", "wb");
1248141cc406Sopenharmony_ci    fprintf (f2, "P5\n%d %d\n255\n", w, h);
1249141cc406Sopenharmony_ci    fwrite (img, 1, w * h, f2);
1250141cc406Sopenharmony_ci    fclose (f2);
1251141cc406Sopenharmony_ci  }
1252141cc406Sopenharmony_ci#endif
1253141cc406Sopenharmony_ci
1254141cc406Sopenharmony_ci  s = locate_black_stripe (img, 300, 180);
1255141cc406Sopenharmony_ci  scan->scanner_yorg = scan->scanner_ypos + s + 64;
1256141cc406Sopenharmony_ci  scan->scanner_ypos += 180 + 3;
1257141cc406Sopenharmony_ci  scan->scanner_ypos &= ~3;
1258141cc406Sopenharmony_ci
1259141cc406Sopenharmony_ci  free (img);
1260141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1261141cc406Sopenharmony_ci}
1262141cc406Sopenharmony_ci
1263141cc406Sopenharmony_ci
1264141cc406Sopenharmony_ci/* Calibration 1220U */
1265141cc406Sopenharmony_ci
1266141cc406Sopenharmony_ci/*
1267141cc406Sopenharmony_ciFormat of caldata:
1268141cc406Sopenharmony_ci
1269141cc406Sopenharmony_ci   5100 bytes of CCD calibration values
1270141cc406Sopenharmony_ci   5100 bytes of CCD calibration values
1271141cc406Sopenharmony_ci   5100 bytes of CCD calibration values
1272141cc406Sopenharmony_ci   256 bytes of gamma data for blue
1273141cc406Sopenharmony_ci   256 bytes of gamma data for green
1274141cc406Sopenharmony_ci   256 bytes of gamma data for red
1275141cc406Sopenharmony_ci   2 bytes of extra information
1276141cc406Sopenharmony_ci
1277141cc406Sopenharmony_ci*/
1278141cc406Sopenharmony_cistatic SANE_Status
1279141cc406Sopenharmony_ciget_caldata (UMAX_Handle * scan, int color)
1280141cc406Sopenharmony_ci{
1281141cc406Sopenharmony_ci  unsigned char opc9[16] = {
1282141cc406Sopenharmony_ci    XXXX, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x00, 0x17, 0x05,
1283141cc406Sopenharmony_ci    0xec, 0x4e, 0x0c, XXXX, 0xac
1284141cc406Sopenharmony_ci  };
1285141cc406Sopenharmony_ci  unsigned char opb11[35] = {
1286141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x04,
1287141cc406Sopenharmony_ci    0x40, 0x01, 0x00, 0x00, 0x04, 0x00, 0x6e, 0xad, 0xa0, 0x49,
1288141cc406Sopenharmony_ci    0x06, 0x00, 0x00, XXXX, XXXX, 0xa0, 0x00, 0x8b, 0x49, 0x4a,
1289141cc406Sopenharmony_ci    0xd0, 0x68, 0xdf, 0x93, 0x1b
1290141cc406Sopenharmony_ci  };
1291141cc406Sopenharmony_ci
1292141cc406Sopenharmony_ci  unsigned char ope[8] = {
1293141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
1294141cc406Sopenharmony_ci  };
1295141cc406Sopenharmony_ci
1296141cc406Sopenharmony_ci  unsigned char opd4[8] = {
1297141cc406Sopenharmony_ci    0x06, 0xf4, 0xff, 0x81, 0x3d, 0x00, XXXX, XXXX
1298141cc406Sopenharmony_ci  };
1299141cc406Sopenharmony_ci  SANE_Status res;
1300141cc406Sopenharmony_ci
1301141cc406Sopenharmony_ci  unsigned char *p;
1302141cc406Sopenharmony_ci  int h  = 66;
1303141cc406Sopenharmony_ci  int w  = color ? 3 * 5100 : 5100;
1304141cc406Sopenharmony_ci  int x0 = color ? 0 : 5100;
1305141cc406Sopenharmony_ci  int l  = w * h;
1306141cc406Sopenharmony_ci  int i, x, y;
1307141cc406Sopenharmony_ci
1308141cc406Sopenharmony_ci  PAD_ARRAY (scan->caldata, 16070);
1309141cc406Sopenharmony_ci
1310141cc406Sopenharmony_ci  DBG (9, "get_caldata: color = %d\n", color);
1311141cc406Sopenharmony_ci
1312141cc406Sopenharmony_ci  p = malloc (l);
1313141cc406Sopenharmony_ci  if (p == 0)
1314141cc406Sopenharmony_ci    {
1315141cc406Sopenharmony_ci      DBG (1, "out of memory (need %d)\n", l);
1316141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1317141cc406Sopenharmony_ci    }
1318141cc406Sopenharmony_ci  memset (scan->caldata, 0, 3 * 5100);
1319141cc406Sopenharmony_ci
1320141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
1321141cc406Sopenharmony_ci  opc9[0] = h + 4;
1322141cc406Sopenharmony_ci  if (color)
1323141cc406Sopenharmony_ci    {
1324141cc406Sopenharmony_ci      opc9[13]  = 0x03;
1325141cc406Sopenharmony_ci      opb11[23] = 0xc4;
1326141cc406Sopenharmony_ci      opb11[24] = 0x5c;
1327141cc406Sopenharmony_ci      opd4[6]   = 0x08;
1328141cc406Sopenharmony_ci      opd4[7]   = 0x00;
1329141cc406Sopenharmony_ci    }
1330141cc406Sopenharmony_ci  else
1331141cc406Sopenharmony_ci    {
1332141cc406Sopenharmony_ci      opc9[13]  = 0xc3;
1333141cc406Sopenharmony_ci      opb11[23] = 0xec;
1334141cc406Sopenharmony_ci      opb11[24] = 0x54;
1335141cc406Sopenharmony_ci      opd4[6]   = 0x0c;
1336141cc406Sopenharmony_ci      opd4[7]   = 0x40;
1337141cc406Sopenharmony_ci    }
1338141cc406Sopenharmony_ci
1339141cc406Sopenharmony_ci  /* Do a test scan of the calibration strip (which is located
1340141cc406Sopenharmony_ci   * under the scanner's lid */
1341141cc406Sopenharmony_ci
1342141cc406Sopenharmony_ci  CHK (get_pixels (scan, opc9, opb11, opd4, ope, l, 0, p));
1343141cc406Sopenharmony_ci
1344141cc406Sopenharmony_ci#ifdef DEBUG_CALIBRATION
1345141cc406Sopenharmony_ci  {
1346141cc406Sopenharmony_ci    FILE *f2 = fopen ("calibration.pgm", "wb");
1347141cc406Sopenharmony_ci    fprintf (f2, "P5\n%d %d\n255\n", w, h);
1348141cc406Sopenharmony_ci    fwrite (p, 1, w * h, f2);
1349141cc406Sopenharmony_ci    fclose (f2);
1350141cc406Sopenharmony_ci  }
1351141cc406Sopenharmony_ci#endif
1352141cc406Sopenharmony_ci
1353141cc406Sopenharmony_ci  scan->scanner_ypos += (h + 4) * 2 + 3;
1354141cc406Sopenharmony_ci  scan->scanner_ypos &= ~3;
1355141cc406Sopenharmony_ci
1356141cc406Sopenharmony_ci  /* The following loop computes the gain for each of the CCD pixel
1357141cc406Sopenharmony_ci   * elements.
1358141cc406Sopenharmony_ci   */
1359141cc406Sopenharmony_ci  for (x = 0; x < w; ++x)
1360141cc406Sopenharmony_ci    {
1361141cc406Sopenharmony_ci      int t = 0, gn;
1362141cc406Sopenharmony_ci      double av, gain;
1363141cc406Sopenharmony_ci
1364141cc406Sopenharmony_ci      for (y = 0; y < h; ++y)
1365141cc406Sopenharmony_ci        t += p[x + y * w];
1366141cc406Sopenharmony_ci      av = (double) t / h;
1367141cc406Sopenharmony_ci      gain = 250 / av;
1368141cc406Sopenharmony_ci      gn = (int) ((gain - 0.984) * 102.547 + 0.5);
1369141cc406Sopenharmony_ci      if (gn < 0)
1370141cc406Sopenharmony_ci        gn = 0;
1371141cc406Sopenharmony_ci      else if (gn > 255)
1372141cc406Sopenharmony_ci        gn = 255;
1373141cc406Sopenharmony_ci      scan->caldata[x + x0] = gn;
1374141cc406Sopenharmony_ci    }
1375141cc406Sopenharmony_ci
1376141cc406Sopenharmony_ci  /* Gamma table for blue */
1377141cc406Sopenharmony_ci
1378141cc406Sopenharmony_ci  for (i = 0; i < 256; ++i)
1379141cc406Sopenharmony_ci    scan->caldata[i + 3 * 5100 + 0] = i;
1380141cc406Sopenharmony_ci
1381141cc406Sopenharmony_ci  /* Gamma table for green */
1382141cc406Sopenharmony_ci
1383141cc406Sopenharmony_ci  for (i = 0; i < 256; ++i)
1384141cc406Sopenharmony_ci    scan->caldata[i + 3 * 5100 + 256] = i;
1385141cc406Sopenharmony_ci
1386141cc406Sopenharmony_ci  /* Gamma table for red */
1387141cc406Sopenharmony_ci
1388141cc406Sopenharmony_ci  for (i = 0; i < 256; ++i)
1389141cc406Sopenharmony_ci    scan->caldata[i + 3 * 5100 + 512] = i;
1390141cc406Sopenharmony_ci
1391141cc406Sopenharmony_ci  free (p);
1392141cc406Sopenharmony_ci
1393141cc406Sopenharmony_ci  CHK_ARRAY (scan->caldata, 16070);
1394141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1395141cc406Sopenharmony_ci}
1396141cc406Sopenharmony_ci
1397141cc406Sopenharmony_ci/* Calibration 2100U */
1398141cc406Sopenharmony_ci
1399141cc406Sopenharmony_ci/*
1400141cc406Sopenharmony_ciFormat of caldata:
1401141cc406Sopenharmony_ci
1402141cc406Sopenharmony_ci   5100 bytes of CCD calibration values
1403141cc406Sopenharmony_ci   5100 bytes of CCD calibration values
1404141cc406Sopenharmony_ci   5100 bytes of CCD calibration values
1405141cc406Sopenharmony_ci   256 bytes of gamma data for blue
1406141cc406Sopenharmony_ci   256 bytes of gamma data for green
1407141cc406Sopenharmony_ci   256 bytes of gamma data for red
1408141cc406Sopenharmony_ci   2 bytes of extra information
1409141cc406Sopenharmony_ci
1410141cc406Sopenharmony_ci*/
1411141cc406Sopenharmony_cistatic SANE_Status
1412141cc406Sopenharmony_ciget_caldata_2100U (UMAX_Handle * scan, int color)
1413141cc406Sopenharmony_ci{
1414141cc406Sopenharmony_ci  unsigned char opc9[16] = {
1415141cc406Sopenharmony_ci    XXXX, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x00, 0x15, 0x05,
1416141cc406Sopenharmony_ci    XXXX, XXXX, XXXX, XXXX, 0xac, 0x00
1417141cc406Sopenharmony_ci  };
1418141cc406Sopenharmony_ci  unsigned char opb11[36] = {
1419141cc406Sopenharmony_ci    0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x04,
1420141cc406Sopenharmony_ci    0x40, 0x01, 0x00, 0x00, 0x04, 0x00, 0x6e, XXXX, XXXX, 0x46,
1421141cc406Sopenharmony_ci    0x06, 0x00, 0x00, XXXX, XXXX, 0xa0, 0x00, 0x8b, 0x49, 0x2a,
1422141cc406Sopenharmony_ci    0xe9, 0x68, 0xdf, 0x83, XXXX, 0x00
1423141cc406Sopenharmony_ci  };
1424141cc406Sopenharmony_ci  unsigned char opd4[8] = {
1425141cc406Sopenharmony_ci    0x06, 0xf4, 0xff, 0x81, 0x1b, 0x00, XXXX, XXXX
1426141cc406Sopenharmony_ci  };
1427141cc406Sopenharmony_ci  unsigned char ope[8] = {
1428141cc406Sopenharmony_ci    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
1429141cc406Sopenharmony_ci  };
1430141cc406Sopenharmony_ci
1431141cc406Sopenharmony_ci
1432141cc406Sopenharmony_ci/* default gamma translation table */
1433141cc406Sopenharmony_ci  unsigned char ggamma[256] = {
1434141cc406Sopenharmony_ci    0x00, 0x06, 0x0A, 0x0D, 0x10, 0x12, 0x14, 0x17, 0x19, 0x1B, 0x1D,
1435141cc406Sopenharmony_ci    0x1F, 0x21, 0x23, 0x24, 0x26, 0x28, 0x2A, 0x2B, 0x2D, 0x2E, 0x30,
1436141cc406Sopenharmony_ci    0x31, 0x33, 0x34, 0x36, 0x37, 0x39, 0x3A, 0x3B, 0x3D, 0x3E, 0x40,
1437141cc406Sopenharmony_ci    0x41, 0x42, 0x43, 0x45, 0x46, 0x47, 0x49, 0x4A, 0x4B, 0x4C, 0x4D,
1438141cc406Sopenharmony_ci    0x4F, 0x50, 0x51, 0x52, 0x53, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A,
1439141cc406Sopenharmony_ci    0x5B, 0x5C, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
1440141cc406Sopenharmony_ci    0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
1441141cc406Sopenharmony_ci    0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
1442141cc406Sopenharmony_ci    0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x86,
1443141cc406Sopenharmony_ci    0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x90,
1444141cc406Sopenharmony_ci    0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x97, 0x98, 0x99, 0x9A,
1445141cc406Sopenharmony_ci    0x9B, 0x9C, 0x9D, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA2, 0xA3,
1446141cc406Sopenharmony_ci    0xA4, 0xA5, 0xA6, 0xA7, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAC,
1447141cc406Sopenharmony_ci    0xAD, 0xAE, 0xAF, 0xB0, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB4, 0xB5,
1448141cc406Sopenharmony_ci    0xB6, 0xB7, 0xB8, 0xB8, 0xB9, 0xBA, 0xBB, 0xBB, 0xBC, 0xBD, 0xBE,
1449141cc406Sopenharmony_ci    0xBF, 0xBF, 0xC0, 0xC1, 0xC2, 0xC2, 0xC3, 0xC4, 0xC5, 0xC5, 0xC6,
1450141cc406Sopenharmony_ci    0xC7, 0xC8, 0xC8, 0xC9, 0xCA, 0xCB, 0xCB, 0xCC, 0xCD, 0xCE, 0xCE,
1451141cc406Sopenharmony_ci    0xCF, 0xD0, 0xD1, 0xD1, 0xD2, 0xD3, 0xD4, 0xD4, 0xD5, 0xD6, 0xD6,
1452141cc406Sopenharmony_ci    0xD7, 0xD8, 0xD9, 0xD9, 0xDA, 0xDB, 0xDC, 0xDC, 0xDD, 0xDE, 0xDE,
1453141cc406Sopenharmony_ci    0xDF, 0xE0, 0xE1, 0xE1, 0xE2, 0xE3, 0xE3, 0xE4, 0xE5, 0xE6, 0xE6,
1454141cc406Sopenharmony_ci    0xE7, 0xE8, 0xE8, 0xE9, 0xEA, 0xEA, 0xEB, 0xEC, 0xEC, 0xED, 0xEE,
1455141cc406Sopenharmony_ci    0xEF, 0xEF, 0xF0, 0xF1, 0xF1, 0xF2, 0xF3, 0xF3, 0xF4, 0xF5, 0xF5,
1456141cc406Sopenharmony_ci    0xF6, 0xF7, 0xF7, 0xF8, 0xF9, 0xF9, 0xFA, 0xFB, 0xFB, 0xFC, 0xFD,
1457141cc406Sopenharmony_ci    0xFE, 0xFE, 0xFF
1458141cc406Sopenharmony_ci  };
1459141cc406Sopenharmony_ci
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci  SANE_Status res;
1462141cc406Sopenharmony_ci
1463141cc406Sopenharmony_ci  unsigned char *p;
1464141cc406Sopenharmony_ci  int h  = 66;
1465141cc406Sopenharmony_ci  int w  = color ? 3 * 5100 : 5100;
1466141cc406Sopenharmony_ci  int x0 = color ? 0 : 5100;
1467141cc406Sopenharmony_ci  int l  = w * h;
1468141cc406Sopenharmony_ci  int i, x, y;
1469141cc406Sopenharmony_ci  int t, gn;
1470141cc406Sopenharmony_ci  double av, pct;
1471141cc406Sopenharmony_ci
1472141cc406Sopenharmony_ci  PAD_ARRAY (scan->caldata, 16070);
1473141cc406Sopenharmony_ci
1474141cc406Sopenharmony_ci  DBG (9, "get_caldata: color = %d\n", color);
1475141cc406Sopenharmony_ci
1476141cc406Sopenharmony_ci  p = malloc (l);
1477141cc406Sopenharmony_ci  if (p == 0)
1478141cc406Sopenharmony_ci    {
1479141cc406Sopenharmony_ci      DBG (1, "out of memory (need %d)\n", l);
1480141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1481141cc406Sopenharmony_ci    }
1482141cc406Sopenharmony_ci  memset (scan->caldata, 0, 3 * 5100);
1483141cc406Sopenharmony_ci
1484141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
1485141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci  opc9[0] = h + 4;
1488141cc406Sopenharmony_ci
1489141cc406Sopenharmony_ci  if (color)
1490141cc406Sopenharmony_ci    {
1491141cc406Sopenharmony_ci      opc9[10]  = 0xb6;
1492141cc406Sopenharmony_ci      opc9[11]  = 0x3b;
1493141cc406Sopenharmony_ci      opc9[12]  = 0x0c;
1494141cc406Sopenharmony_ci      opc9[13]  = 0x03;
1495141cc406Sopenharmony_ci      opb11[17] = 0x7e;
1496141cc406Sopenharmony_ci      opb11[18] = 0xb0;
1497141cc406Sopenharmony_ci      opb11[23] = 0xc4;
1498141cc406Sopenharmony_ci      opb11[24] = 0x5c;
1499141cc406Sopenharmony_ci      opb11[34] = 0x1b;
1500141cc406Sopenharmony_ci      opd4[6]   = 0x0f;
1501141cc406Sopenharmony_ci      opd4[7]   = 0x40;
1502141cc406Sopenharmony_ci    }
1503141cc406Sopenharmony_ci  else
1504141cc406Sopenharmony_ci    {
1505141cc406Sopenharmony_ci      opc9[10]  = 0xa6;
1506141cc406Sopenharmony_ci      opc9[11]  = 0x2a;
1507141cc406Sopenharmony_ci      opc9[12]  = 0x08;
1508141cc406Sopenharmony_ci      opc9[13]  = 0xc2;
1509141cc406Sopenharmony_ci      opb11[17] = 0x7f;
1510141cc406Sopenharmony_ci      opb11[18] = 0xc0;
1511141cc406Sopenharmony_ci      opb11[23] = 0xec;
1512141cc406Sopenharmony_ci      opb11[24] = 0x54;
1513141cc406Sopenharmony_ci      opb11[34] = 0x1a;
1514141cc406Sopenharmony_ci      opd4[6]   = 0x06;
1515141cc406Sopenharmony_ci      opd4[7]   = 0x20;
1516141cc406Sopenharmony_ci    }
1517141cc406Sopenharmony_ci
1518141cc406Sopenharmony_ci  /* Do a test scan of the calibration strip (which is located
1519141cc406Sopenharmony_ci   * under the scanner's lid */
1520141cc406Sopenharmony_ci  CHK (get_pixels_2100U (scan, opc9, opb11, opd4, ope, l, 0, p));
1521141cc406Sopenharmony_ci
1522141cc406Sopenharmony_ci#ifdef DEBUG_CALIBRATION
1523141cc406Sopenharmony_ci  {
1524141cc406Sopenharmony_ci    FILE *f2 = fopen ("calibration.pgm", "wb");
1525141cc406Sopenharmony_ci    fprintf (f2, "P5\n%d %d\n255\n", w, h);
1526141cc406Sopenharmony_ci    fwrite (p, 1, w * h, f2);
1527141cc406Sopenharmony_ci    fclose (f2);
1528141cc406Sopenharmony_ci  }
1529141cc406Sopenharmony_ci#endif
1530141cc406Sopenharmony_ci
1531141cc406Sopenharmony_ci  scan->scanner_ypos += (h + 4) * 2 + 3;
1532141cc406Sopenharmony_ci  scan->scanner_ypos &= ~3;
1533141cc406Sopenharmony_ci
1534141cc406Sopenharmony_ci  /* The following loop computes the gain for each of the CCD pixel
1535141cc406Sopenharmony_ci   * elements.
1536141cc406Sopenharmony_ci   */
1537141cc406Sopenharmony_ci  for (x = 0; x < w; x++)
1538141cc406Sopenharmony_ci    {
1539141cc406Sopenharmony_ci      t = 0;
1540141cc406Sopenharmony_ci      for (y = 0; y < h; y++)
1541141cc406Sopenharmony_ci        t += p[x + y * w];
1542141cc406Sopenharmony_ci      av = (double) t / h;
1543141cc406Sopenharmony_ci      pct = 100.0 - (av * 100.0) / 250;
1544141cc406Sopenharmony_ci      gn = (int) (pct / 0.57);
1545141cc406Sopenharmony_ci
1546141cc406Sopenharmony_ci      pct = gn;
1547141cc406Sopenharmony_ci      av = exp((-pct)/50)*2.5+0.9;
1548141cc406Sopenharmony_ci      gn = gn * av;
1549141cc406Sopenharmony_ci
1550141cc406Sopenharmony_ci
1551141cc406Sopenharmony_ci      if (gn < 0)
1552141cc406Sopenharmony_ci        gn = 0;
1553141cc406Sopenharmony_ci      else if (gn > 127)
1554141cc406Sopenharmony_ci        gn = 127;
1555141cc406Sopenharmony_ci      scan->caldata[x + x0] = gn;
1556141cc406Sopenharmony_ci    }
1557141cc406Sopenharmony_ci
1558141cc406Sopenharmony_ci  /* Gamma table for blue */
1559141cc406Sopenharmony_ci
1560141cc406Sopenharmony_ci  for (i = 0; i < 256; i++)
1561141cc406Sopenharmony_ci    scan->caldata[i + 3 * 5100 + 0] = ggamma[i];
1562141cc406Sopenharmony_ci
1563141cc406Sopenharmony_ci  /* Gamma table for green */
1564141cc406Sopenharmony_ci
1565141cc406Sopenharmony_ci  for (i = 0; i < 256; i++)
1566141cc406Sopenharmony_ci    scan->caldata[i + 3 * 5100 + 256] = ggamma[i];
1567141cc406Sopenharmony_ci
1568141cc406Sopenharmony_ci  /* Gamma table for red */
1569141cc406Sopenharmony_ci
1570141cc406Sopenharmony_ci  for (i = 0; i < 256; i++)
1571141cc406Sopenharmony_ci    scan->caldata[i + 3 * 5100 + 512] = ggamma[i];
1572141cc406Sopenharmony_ci
1573141cc406Sopenharmony_ci  free (p);
1574141cc406Sopenharmony_ci
1575141cc406Sopenharmony_ci  CHK_ARRAY (scan->caldata, 16070);
1576141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1577141cc406Sopenharmony_ci}
1578141cc406Sopenharmony_ci
1579141cc406Sopenharmony_ci
1580141cc406Sopenharmony_ci
1581141cc406Sopenharmony_ci/* Sends scan user parameters from frontend 1220U */
1582141cc406Sopenharmony_ci
1583141cc406Sopenharmony_cistatic SANE_Status
1584141cc406Sopenharmony_cisend_scan_parameters (UMAX_Handle * scan)
1585141cc406Sopenharmony_ci{
1586141cc406Sopenharmony_ci  SANE_Status res;
1587141cc406Sopenharmony_ci  UMAX_Status_Byte s;
1588141cc406Sopenharmony_ci
1589141cc406Sopenharmony_ci  /* Appears to correspond to opscan in umax_pp_low.c */
1590141cc406Sopenharmony_ci  unsigned char opbgo[35] = {
1591141cc406Sopenharmony_ci    0x00, 0x00, 0xb0, 0x4f, 0xd8, 0xe7, 0xfa, 0x10, 0xef, 0xc4,
1592141cc406Sopenharmony_ci    0x3c, 0x71, 0x0f, 0x00, 0x04, 0x00, 0x6e, XXXX, XXXX, XXXX,
1593141cc406Sopenharmony_ci    0xc4, 0x7e, 0x00, XXXX, XXXX, 0xa0, 0x0a, 0x8b, 0x49, 0x4a,
1594141cc406Sopenharmony_ci    0xd0, 0x68, 0xdf, XXXX, 0x1a
1595141cc406Sopenharmony_ci  };
1596141cc406Sopenharmony_ci
1597141cc406Sopenharmony_ci  /* Appears to correspond to opsc53 in umax_pp_low.c */
1598141cc406Sopenharmony_ci  unsigned char opcgo[16] = {
1599141cc406Sopenharmony_ci    XXXX, XXXX, XXXX, XXXX, 0xec, 0x03, XXXX, XXXX, XXXX, XXXX,
1600141cc406Sopenharmony_ci    0xec, 0x4e, XXXX, XXXX, XXXX
1601141cc406Sopenharmony_ci  };
1602141cc406Sopenharmony_ci
1603141cc406Sopenharmony_ci  /* Appears to correspond to opsc04 in umax_pp_low.c */
1604141cc406Sopenharmony_ci  unsigned char opdgo[8] = {
1605141cc406Sopenharmony_ci    0x06, 0xf4, 0xff, 0x81, 0x3d, 0x00, XXXX, XXXX
1606141cc406Sopenharmony_ci  };
1607141cc406Sopenharmony_ci
1608141cc406Sopenharmony_ci  unsigned char subsamp[9] = {
1609141cc406Sopenharmony_ci    0xff, 0xff, 0xaa, 0xaa, 0x88, 0x88, 0x88, 0x88, 0x80
1610141cc406Sopenharmony_ci  };
1611141cc406Sopenharmony_ci
1612141cc406Sopenharmony_ci  const int xend =
1613141cc406Sopenharmony_ci    scan->xskip + scan->w * scan->xsamp + (scan->xsamp + 1) / 2;
1614141cc406Sopenharmony_ci  const int ytot = scan->hexp * scan->ysamp + 12;
1615141cc406Sopenharmony_ci
1616141cc406Sopenharmony_ci  opbgo[17] = scan->xskip % 256;
1617141cc406Sopenharmony_ci  opbgo[18] = ((scan->xskip >> 8) & 0xf) + (xend << 4);
1618141cc406Sopenharmony_ci  opbgo[19] = xend >> 4;
1619141cc406Sopenharmony_ci  opbgo[33] = 0x33 + ((xend & 0x1000) >> 5) + ((scan->xskip & 0x1000) >> 6);
1620141cc406Sopenharmony_ci
1621141cc406Sopenharmony_ci  /* bytes per line */
1622141cc406Sopenharmony_ci
1623141cc406Sopenharmony_ci  opbgo[23] = scan->color ? 0xc6 : 0x77;
1624141cc406Sopenharmony_ci  opbgo[24] = scan->color ? 0x5b : 0x4a;
1625141cc406Sopenharmony_ci
1626141cc406Sopenharmony_ci  /* Scan height */
1627141cc406Sopenharmony_ci
1628141cc406Sopenharmony_ci  opcgo[0] = ytot;
1629141cc406Sopenharmony_ci  opcgo[1] = ((ytot >> 8) & 0x3f) + (scan->yskip << 6);
1630141cc406Sopenharmony_ci  opcgo[2] = scan->yskip >> 2;
1631141cc406Sopenharmony_ci  opcgo[3] = 0x50 + ((scan->yskip >> 10) & 0xf);
1632141cc406Sopenharmony_ci
1633141cc406Sopenharmony_ci  /* This is what used to be here:
1634141cc406Sopenharmony_ci
1635141cc406Sopenharmony_ci     opcgo[6] = bh == h? 0: 0x60;       // a guess
1636141cc406Sopenharmony_ci
1637141cc406Sopenharmony_ci     I replaced it with what umax_pp_low.c uses, since it
1638141cc406Sopenharmony_ci     made more sense
1639141cc406Sopenharmony_ci   */
1640141cc406Sopenharmony_ci  opcgo[6]  = (scan->ydpi <= 300) ? 0x00 : 0x60;
1641141cc406Sopenharmony_ci  opcgo[8]  = (scan->ydpi <= 300) ? 0x17 : 0x2F;
1642141cc406Sopenharmony_ci  opcgo[9]  = (scan->ydpi >= 300) ? 0x05 : 0x07;
1643141cc406Sopenharmony_ci  opcgo[14] = (scan->ydpi == 600) ? 0xa4 : 0xac;
1644141cc406Sopenharmony_ci
1645141cc406Sopenharmony_ci  opcgo[7]  = scan->color ? 0x2F : 0x40;
1646141cc406Sopenharmony_ci  opcgo[12] = scan->color ? 0x10 : 0x0C;
1647141cc406Sopenharmony_ci  opcgo[13] = scan->color ? 0x04 : 0xc3;
1648141cc406Sopenharmony_ci
1649141cc406Sopenharmony_ci  opdgo[6]  = scan->color ? 0x88 : 0x8c;
1650141cc406Sopenharmony_ci  opdgo[7]  = scan->color ? 0x00 : 0x40;
1651141cc406Sopenharmony_ci
1652141cc406Sopenharmony_ci  DBG (3, "send_scan_parameters: xskip = %d, yskip = %d\n", scan->xskip,
1653141cc406Sopenharmony_ci       scan->yskip);
1654141cc406Sopenharmony_ci
1655141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
1656141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
1657141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_2, 16, opcgo, &s));
1658141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_8, 35, opbgo, &s));
1659141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_1, 8, opdgo, &s));
1660141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1661141cc406Sopenharmony_ci  DBG (4, "send_scan_parameters: checkpoint 1: s = %d\n", s);
1662141cc406Sopenharmony_ci
1663141cc406Sopenharmony_ci  /* Loads the new calibration data (that was computed by get_caldata) into the
1664141cc406Sopenharmony_ci     scanner */
1665141cc406Sopenharmony_ci
1666141cc406Sopenharmony_ci  scan->caldata[16068] = subsamp[scan->xsamp];
1667141cc406Sopenharmony_ci  scan->caldata[16069] = subsamp[scan->ysamp];
1668141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_4, 16070, scan->caldata, &s));
1669141cc406Sopenharmony_ci
1670141cc406Sopenharmony_ci  CHK (csend (scan, CMD_40));
1671141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1672141cc406Sopenharmony_ci
1673141cc406Sopenharmony_ci  DBG (4, "send_scan_parameters: checkpoint 2: s = %d\n", s);
1674141cc406Sopenharmony_ci
1675141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1676141cc406Sopenharmony_ci}
1677141cc406Sopenharmony_ci
1678141cc406Sopenharmony_ci/* Sends scan user parameters from frontend 2100U */
1679141cc406Sopenharmony_ci
1680141cc406Sopenharmony_cistatic SANE_Status
1681141cc406Sopenharmony_cisend_scan_parameters_2100U (UMAX_Handle * scan)
1682141cc406Sopenharmony_ci{
1683141cc406Sopenharmony_ci  SANE_Status res;
1684141cc406Sopenharmony_ci  UMAX_Status_Byte s;
1685141cc406Sopenharmony_ci  int bpl;
1686141cc406Sopenharmony_ci
1687141cc406Sopenharmony_ci  /* Appears to correspond to opscan in umax_pp_low.c */
1688141cc406Sopenharmony_ci  unsigned char opbgo[36] = {
1689141cc406Sopenharmony_ci    0x00, 0x00, 0xb0, 0x4f, 0xd8, 0xe7, 0xfa, 0x10, 0xef, 0xc4,
1690141cc406Sopenharmony_ci    0x3c, 0x71, 0x0f, 0x00, 0x04, 0x00, 0x6e, XXXX, XXXX, XXXX,
1691141cc406Sopenharmony_ci    0xc4, 0x7e, 0x00, XXXX, XXXX, 0xa0, 0x0a, 0x8b, 0x49, 0x2a,
1692141cc406Sopenharmony_ci    0xe9, 0x68, 0xdf, XXXX, 0x1a, 0x00
1693141cc406Sopenharmony_ci  };
1694141cc406Sopenharmony_ci
1695141cc406Sopenharmony_ci  /* Appears to correspond to opsc53 in umax_pp_low.c */
1696141cc406Sopenharmony_ci  unsigned char opcgo[16] = {
1697141cc406Sopenharmony_ci    XXXX, XXXX, XXXX, XXXX, 0xec, 0x03, 0x60, XXXX, XXXX, XXXX,
1698141cc406Sopenharmony_ci    XXXX, XXXX, XXXX, XXXX, XXXX, 0x00
1699141cc406Sopenharmony_ci  };
1700141cc406Sopenharmony_ci
1701141cc406Sopenharmony_ci  /* Appears to correspond to opsc04 in umax_pp_low.c */
1702141cc406Sopenharmony_ci  unsigned char opdgo[8] = {
1703141cc406Sopenharmony_ci    0x06, 0xf4, 0xff, 0x81, 0x1b, 0x00, XXXX, XXXX
1704141cc406Sopenharmony_ci  };
1705141cc406Sopenharmony_ci
1706141cc406Sopenharmony_ci  unsigned char subsamp[9] = {
1707141cc406Sopenharmony_ci    0xff, 0xff, 0xaa, 0xaa, 0x88, 0x88, 0x88, 0x88, 0x80
1708141cc406Sopenharmony_ci  };
1709141cc406Sopenharmony_ci
1710141cc406Sopenharmony_ci  const int xend =
1711141cc406Sopenharmony_ci    scan->xskip + scan->w * scan->xsamp + (scan->xsamp + 1) / 2;
1712141cc406Sopenharmony_ci  const int ytot = scan->hexp * scan->ysamp + 12;
1713141cc406Sopenharmony_ci
1714141cc406Sopenharmony_ci  opbgo[17] = scan->xskip % 256;
1715141cc406Sopenharmony_ci  opbgo[18] = ((scan->xskip >> 8) & 0x0f) + (xend << 4);
1716141cc406Sopenharmony_ci  opbgo[19] = xend >> 4;
1717141cc406Sopenharmony_ci  opbgo[33] = 0x23 + ((xend & 0x1000) >> 5) + ((scan->xskip & 0x1000) >> 6);
1718141cc406Sopenharmony_ci
1719141cc406Sopenharmony_ci  /* bytes per line */
1720141cc406Sopenharmony_ci
1721141cc406Sopenharmony_ci  bpl = (scan->color ? 3 : 1) * scan->w * scan->xdpi;
1722141cc406Sopenharmony_ci  opbgo[23] = bpl % 256;
1723141cc406Sopenharmony_ci  opbgo[24] = 0x41 + ((bpl / 256) & 0x1f);
1724141cc406Sopenharmony_ci
1725141cc406Sopenharmony_ci  /* Scan height */
1726141cc406Sopenharmony_ci
1727141cc406Sopenharmony_ci  opcgo[0] = ytot;
1728141cc406Sopenharmony_ci  opcgo[1] = ((ytot >> 8) & 0x3f) + (scan->yskip << 6);
1729141cc406Sopenharmony_ci  opcgo[2] = (scan->yskip >> 2);
1730141cc406Sopenharmony_ci  opcgo[3] = 0x50 + ((scan->yskip >> 10) & 0x0f);
1731141cc406Sopenharmony_ci
1732141cc406Sopenharmony_ci
1733141cc406Sopenharmony_ci  opcgo[6]  = (scan->ydpi <= 300) ? 0x00 : 0x60;
1734141cc406Sopenharmony_ci  opcgo[8]  = (scan->ydpi <= 300) ? 0x17 : 0x2F;
1735141cc406Sopenharmony_ci  opcgo[9]  = (scan->ydpi >= 300) ? 0x05 : 0x07;
1736141cc406Sopenharmony_ci  opcgo[14] = (scan->ydpi == 600) ? 0xa4 : 0xac;
1737141cc406Sopenharmony_ci
1738141cc406Sopenharmony_ci
1739141cc406Sopenharmony_ci  opcgo[7]  = scan->color ? 0x2f : 0x40;
1740141cc406Sopenharmony_ci  opcgo[10] = scan->color ? 0xb6 : 0xa6;
1741141cc406Sopenharmony_ci  opcgo[11] = scan->color ? 0x3b : 0x2a;
1742141cc406Sopenharmony_ci  opcgo[12] = scan->color ? 0x0c : 0x08;
1743141cc406Sopenharmony_ci  opcgo[13] = scan->color ? 0x03 : 0xc2;
1744141cc406Sopenharmony_ci
1745141cc406Sopenharmony_ci  opdgo[6]  = scan->color ? 0x8f : 0x86;
1746141cc406Sopenharmony_ci  opdgo[7]  = scan->color ? 0x40 : 0x20;
1747141cc406Sopenharmony_ci
1748141cc406Sopenharmony_ci  DBG (3, "send_scan_parameters: xskip = %d, yskip = %d\n", scan->xskip,
1749141cc406Sopenharmony_ci       scan->yskip);
1750141cc406Sopenharmony_ci
1751141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
1752141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
1753141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_2, 16, opcgo, &s));
1754141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_8, 36, opbgo, &s));
1755141cc406Sopenharmony_ci  CHK (cwritev (scan, CMD_1, 8, opdgo, &s));
1756141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1757141cc406Sopenharmony_ci  DBG (4, "send_scan_parameters: checkpoint 1: s = %d\n", s);
1758141cc406Sopenharmony_ci
1759141cc406Sopenharmony_ci  /* Loads the new calibration data (that was computed by get_caldata) into the
1760141cc406Sopenharmony_ci     scanner */
1761141cc406Sopenharmony_ci
1762141cc406Sopenharmony_ci  scan->caldata[16068] = subsamp[scan->xsamp];
1763141cc406Sopenharmony_ci  scan->caldata[16069] = subsamp[scan->ysamp];
1764141cc406Sopenharmony_ci  CHK (cwrite (scan, CMD_4, 16070, scan->caldata, &s));
1765141cc406Sopenharmony_ci
1766141cc406Sopenharmony_ci  CHK (csend (scan, CMD_40));
1767141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1768141cc406Sopenharmony_ci
1769141cc406Sopenharmony_ci  DBG (4, "send_scan_parameters: checkpoint 2: s = %d\n", s);
1770141cc406Sopenharmony_ci
1771141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1772141cc406Sopenharmony_ci}
1773141cc406Sopenharmony_ci
1774141cc406Sopenharmony_ci/* Read raw data */
1775141cc406Sopenharmony_ci
1776141cc406Sopenharmony_cistatic SANE_Status
1777141cc406Sopenharmony_ciread_raw_data (UMAX_Handle * scan, unsigned char *data, int len)
1778141cc406Sopenharmony_ci{
1779141cc406Sopenharmony_ci  SANE_Status res;
1780141cc406Sopenharmony_ci  UMAX_Status_Byte s;
1781141cc406Sopenharmony_ci
1782141cc406Sopenharmony_ci  CHK (cread (scan, CMD_2, 0, NULL, &s));
1783141cc406Sopenharmony_ci  CHK (cread (scan, CMD_4, len, data, &s));
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1786141cc406Sopenharmony_ci}
1787141cc406Sopenharmony_ci
1788141cc406Sopenharmony_ci/* Read raw strip color */
1789141cc406Sopenharmony_ci
1790141cc406Sopenharmony_cistatic SANE_Status
1791141cc406Sopenharmony_ciread_raw_strip_color (UMAX_Handle * scan)
1792141cc406Sopenharmony_ci{
1793141cc406Sopenharmony_ci  /**
1794141cc406Sopenharmony_ci     yres = 75   => ydpi = 150 => ysamp = 2 => yoff_scale = 8
1795141cc406Sopenharmony_ci     yres = 150  => ydpi = 150 => ysamp = 1 => yoff_scale = 4
1796141cc406Sopenharmony_ci     yres = 300  => ydpi = 300 => ysamp = 1 => yoff_scale = 2
1797141cc406Sopenharmony_ci     yres = 600  => ydpi = 600 => ysamp = 1 => yoff_scale = 1
1798141cc406Sopenharmony_ci  */
1799141cc406Sopenharmony_ci
1800141cc406Sopenharmony_ci  const int yoff_scale = 600 * scan->ysamp / scan->ydpi;
1801141cc406Sopenharmony_ci  const int linelen = 3 * scan->w;
1802141cc406Sopenharmony_ci
1803141cc406Sopenharmony_ci  /*
1804141cc406Sopenharmony_ci     yoff_scale = 8  =>  roff = 5  * w,  goff = 1  * w,  boff = 0 * w, hextra = 1
1805141cc406Sopenharmony_ci     yoff_scale = 4  =>  roff = 8  * w,  goff = 4  * w,  boff = 0 * w, hextra = 2
1806141cc406Sopenharmony_ci     yoff_scale = 2  =>  roff = 14 * w,  goff = 7  * w,  boff = 0 * w, hextra = 4
1807141cc406Sopenharmony_ci     yoff_scale = 1  =>  roff = 26 * w,  goff = 13 * w,  boff = 0 * w, hextra = 8
1808141cc406Sopenharmony_ci   */
1809141cc406Sopenharmony_ci
1810141cc406Sopenharmony_ci  const int hextra = 8 / yoff_scale;
1811141cc406Sopenharmony_ci
1812141cc406Sopenharmony_ci  SANE_Status res;
1813141cc406Sopenharmony_ci  int lines_to_read = scan->hexp;
1814141cc406Sopenharmony_ci
1815141cc406Sopenharmony_ci  DBG (9, "read_raw_strip_color: hexp = %d, bh = %d\n", scan->hexp, scan->bh);
1816141cc406Sopenharmony_ci
1817141cc406Sopenharmony_ci  if (scan->maxh == -1)
1818141cc406Sopenharmony_ci    {
1819141cc406Sopenharmony_ci      DBG (10, "read_raw_strip_color: filling buffer for the first time\n");
1820141cc406Sopenharmony_ci      if (lines_to_read > scan->bh)
1821141cc406Sopenharmony_ci        lines_to_read = scan->bh;
1822141cc406Sopenharmony_ci
1823141cc406Sopenharmony_ci      CHK (read_raw_data (scan, scan->p, lines_to_read * linelen));
1824141cc406Sopenharmony_ci      scan->maxh = lines_to_read - hextra;
1825141cc406Sopenharmony_ci    }
1826141cc406Sopenharmony_ci  else
1827141cc406Sopenharmony_ci    {
1828141cc406Sopenharmony_ci      DBG (10, "read_raw_strip_color: reading new rows into buffer\n");
1829141cc406Sopenharmony_ci      memmove (scan->p, scan->p + (scan->bh - hextra) * linelen,
1830141cc406Sopenharmony_ci               hextra * linelen);
1831141cc406Sopenharmony_ci
1832141cc406Sopenharmony_ci      if (lines_to_read > (scan->bh - hextra))
1833141cc406Sopenharmony_ci        lines_to_read = scan->bh - hextra;
1834141cc406Sopenharmony_ci
1835141cc406Sopenharmony_ci      CHK (read_raw_data
1836141cc406Sopenharmony_ci           (scan, scan->p + hextra * linelen, lines_to_read * linelen));
1837141cc406Sopenharmony_ci      scan->maxh = lines_to_read;
1838141cc406Sopenharmony_ci    }
1839141cc406Sopenharmony_ci
1840141cc406Sopenharmony_ci  scan->hexp -= lines_to_read;
1841141cc406Sopenharmony_ci  scan->x = 0;
1842141cc406Sopenharmony_ci  scan->y = 0;
1843141cc406Sopenharmony_ci
1844141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1845141cc406Sopenharmony_ci}
1846141cc406Sopenharmony_ci
1847141cc406Sopenharmony_ci/* Read raw strip grey */
1848141cc406Sopenharmony_ci
1849141cc406Sopenharmony_cistatic SANE_Status
1850141cc406Sopenharmony_ciread_raw_strip_gray (UMAX_Handle * scan)
1851141cc406Sopenharmony_ci{
1852141cc406Sopenharmony_ci  const int linelen = scan->w;
1853141cc406Sopenharmony_ci
1854141cc406Sopenharmony_ci  SANE_Status res;
1855141cc406Sopenharmony_ci
1856141cc406Sopenharmony_ci  int lines_to_read = scan->bh;
1857141cc406Sopenharmony_ci
1858141cc406Sopenharmony_ci  DBG (9, "read_raw_strip_gray: hexp = %d\n", scan->hexp);
1859141cc406Sopenharmony_ci
1860141cc406Sopenharmony_ci  if (lines_to_read > scan->hexp)
1861141cc406Sopenharmony_ci    lines_to_read = scan->hexp;
1862141cc406Sopenharmony_ci  scan->hexp -= lines_to_read;
1863141cc406Sopenharmony_ci
1864141cc406Sopenharmony_ci  CHK (read_raw_data (scan, scan->p, lines_to_read * linelen));
1865141cc406Sopenharmony_ci
1866141cc406Sopenharmony_ci  scan->maxh = lines_to_read;
1867141cc406Sopenharmony_ci  scan->x = 0;
1868141cc406Sopenharmony_ci  scan->y = 0;
1869141cc406Sopenharmony_ci
1870141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1871141cc406Sopenharmony_ci}
1872141cc406Sopenharmony_ci
1873141cc406Sopenharmony_ci
1874141cc406Sopenharmony_ci/* Read raw strip */
1875141cc406Sopenharmony_ci
1876141cc406Sopenharmony_cistatic SANE_Status
1877141cc406Sopenharmony_ciread_raw_strip (UMAX_Handle * scan)
1878141cc406Sopenharmony_ci{
1879141cc406Sopenharmony_ci  if (scan->color)
1880141cc406Sopenharmony_ci      return read_raw_strip_color (scan);
1881141cc406Sopenharmony_ci  else
1882141cc406Sopenharmony_ci      return read_raw_strip_gray (scan);
1883141cc406Sopenharmony_ci}
1884141cc406Sopenharmony_ci
1885141cc406Sopenharmony_ci/* Set scan user pamaters Frontend */
1886141cc406Sopenharmony_ci
1887141cc406Sopenharmony_cistatic SANE_Status
1888141cc406Sopenharmony_ciUMAX_set_scan_parameters (UMAX_Handle * scan,
1889141cc406Sopenharmony_ci                          const int color,
1890141cc406Sopenharmony_ci                          const int xo,
1891141cc406Sopenharmony_ci                          const int yo,
1892141cc406Sopenharmony_ci                          const int w,
1893141cc406Sopenharmony_ci                          const int h, const int xres, const int yres)
1894141cc406Sopenharmony_ci{
1895141cc406Sopenharmony_ci
1896141cc406Sopenharmony_ci  /* Validate the input parameters */
1897141cc406Sopenharmony_ci
1898141cc406Sopenharmony_ci  int left = xo;
1899141cc406Sopenharmony_ci  int top = yo;
1900141cc406Sopenharmony_ci  int right = xo + w * 600 / xres;
1901141cc406Sopenharmony_ci  int bottom = yo + h * 600 / yres;
1902141cc406Sopenharmony_ci
1903141cc406Sopenharmony_ci  DBG (2, "UMAX_set_scan_parameters:\n");
1904141cc406Sopenharmony_ci  DBG (2, "color = %d             \n", color);
1905141cc406Sopenharmony_ci  DBG (2, "xo    = %d, yo     = %d\n", xo, yo);
1906141cc406Sopenharmony_ci  DBG (2, "w     = %d, h      = %d\n", w, h);
1907141cc406Sopenharmony_ci  DBG (2, "xres  = %d, yres   = %d\n", xres, yres);
1908141cc406Sopenharmony_ci  DBG (2, "left  = %d, top    = %d\n", left, top);
1909141cc406Sopenharmony_ci  DBG (2, "right = %d, bottom = %d\n", right, bottom);
1910141cc406Sopenharmony_ci
1911141cc406Sopenharmony_ci  if ((left < 0) || (right > UMAX_MAX_WIDTH))
1912141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1913141cc406Sopenharmony_ci
1914141cc406Sopenharmony_ci  if ((top < 0) || (bottom > UMAX_MAX_HEIGHT))
1915141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1916141cc406Sopenharmony_ci
1917141cc406Sopenharmony_ci  if (((right - left) < 10) || ((bottom - top) < 10))
1918141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1919141cc406Sopenharmony_ci
1920141cc406Sopenharmony_ci  if ((xres != 75) && (xres != 150) && (xres != 300) && (xres != 600))
1921141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1922141cc406Sopenharmony_ci
1923141cc406Sopenharmony_ci  if ((yres != 75) && (yres != 150) && (yres != 300) && (yres != 600))
1924141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
1925141cc406Sopenharmony_ci
1926141cc406Sopenharmony_ci  /* If we get this far, begin initializing the data
1927141cc406Sopenharmony_ci     structure
1928141cc406Sopenharmony_ci   */
1929141cc406Sopenharmony_ci
1930141cc406Sopenharmony_ci  scan->color = color;
1931141cc406Sopenharmony_ci  scan->w = w;
1932141cc406Sopenharmony_ci  scan->h = h;
1933141cc406Sopenharmony_ci  scan->xo = xo;
1934141cc406Sopenharmony_ci  scan->yo = yo;
1935141cc406Sopenharmony_ci
1936141cc406Sopenharmony_ci  /*
1937141cc406Sopenharmony_ci     The scanner has a fixed X resolution of 600 dpi, but
1938141cc406Sopenharmony_ci     supports three choices for the Y resolution. We must
1939141cc406Sopenharmony_ci     choose an appropriate physical resolution and the
1940141cc406Sopenharmony_ci     corresponding sampling value.
1941141cc406Sopenharmony_ci
1942141cc406Sopenharmony_ci     It is not clear to me why the choice depends on
1943141cc406Sopenharmony_ci     whether we are scanning in color or not, but the
1944141cc406Sopenharmony_ci     original code did this and I didn't want to mess
1945141cc406Sopenharmony_ci     with it.
1946141cc406Sopenharmony_ci
1947141cc406Sopenharmony_ci     Physical X resolution choice:
1948141cc406Sopenharmony_ci     xres = 75   =>  xdpi = 600  (xsamp = 8)
1949141cc406Sopenharmony_ci     xres = 150  =>  xdpi = 600  (xsamp = 4)
1950141cc406Sopenharmony_ci     xres = 300  =>  xdpi = 600  (xsamp = 2)
1951141cc406Sopenharmony_ci     xres = 600  =>  xdpi = 600  (xsamp = 1)
1952141cc406Sopenharmony_ci
1953141cc406Sopenharmony_ci     Physical Y resolution choice (if color):
1954141cc406Sopenharmony_ci     yres = 75    =>  ydpi = 150  (ysamp = 2)
1955141cc406Sopenharmony_ci     yres = 150   =>  ydpi = 150  (ysamp = 1)
1956141cc406Sopenharmony_ci     yres = 300   =>  ydpi = 300  (ysamp = 1)
1957141cc406Sopenharmony_ci     yres = 600   =>  ydpi = 600  (ysamp = 1)
1958141cc406Sopenharmony_ci
1959141cc406Sopenharmony_ci     Physical Y resolution choice (if not color):
1960141cc406Sopenharmony_ci     yres = 75    =>  ydpi = 300  (ysamp = 4)
1961141cc406Sopenharmony_ci     yres = 150   =>  ydpi = 300  (ysamp = 2)
1962141cc406Sopenharmony_ci     yres = 300   =>  ydpi = 300  (ysamp = 1)
1963141cc406Sopenharmony_ci     yres = 600   =>  ydpi = 600  (ysamp = 1)
1964141cc406Sopenharmony_ci   */
1965141cc406Sopenharmony_ci
1966141cc406Sopenharmony_ci  scan->xdpi = 600;
1967141cc406Sopenharmony_ci  if (yres <= 150 && color)
1968141cc406Sopenharmony_ci    scan->ydpi = 150;
1969141cc406Sopenharmony_ci  else if (yres > 300)
1970141cc406Sopenharmony_ci    scan->ydpi = 600;
1971141cc406Sopenharmony_ci  else
1972141cc406Sopenharmony_ci    scan->ydpi = 300;
1973141cc406Sopenharmony_ci
1974141cc406Sopenharmony_ci  scan->xsamp = scan->xdpi / xres;
1975141cc406Sopenharmony_ci  scan->ysamp = scan->ydpi / yres;
1976141cc406Sopenharmony_ci
1977141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1978141cc406Sopenharmony_ci}
1979141cc406Sopenharmony_ci
1980141cc406Sopenharmony_ci/* Start actual scan 1220U */
1981141cc406Sopenharmony_ci
1982141cc406Sopenharmony_cistatic SANE_Status
1983141cc406Sopenharmony_ciUMAX_start_scan (UMAX_Handle * scan)
1984141cc406Sopenharmony_ci{
1985141cc406Sopenharmony_ci  SANE_Status res;
1986141cc406Sopenharmony_ci  int linelen;
1987141cc406Sopenharmony_ci  int yd;
1988141cc406Sopenharmony_ci
1989141cc406Sopenharmony_ci  DBG (3, "UMAX_start_scan called\n");
1990141cc406Sopenharmony_ci
1991141cc406Sopenharmony_ci  if (scan->color)
1992141cc406Sopenharmony_ci    {
1993141cc406Sopenharmony_ci      const int yoff_scale = 600 * scan->ysamp / scan->ydpi;
1994141cc406Sopenharmony_ci      const int hextra = 8 / yoff_scale;
1995141cc406Sopenharmony_ci
1996141cc406Sopenharmony_ci      linelen = 3 * scan->w;
1997141cc406Sopenharmony_ci      scan->hexp = scan->h + hextra;
1998141cc406Sopenharmony_ci    }
1999141cc406Sopenharmony_ci  else
2000141cc406Sopenharmony_ci    {
2001141cc406Sopenharmony_ci      linelen = scan->w;
2002141cc406Sopenharmony_ci      scan->hexp = scan->h;
2003141cc406Sopenharmony_ci    }
2004141cc406Sopenharmony_ci
2005141cc406Sopenharmony_ci  scan->bh = BUFFER_SIZE / linelen;
2006141cc406Sopenharmony_ci
2007141cc406Sopenharmony_ci  scan->p = malloc (scan->bh * linelen);
2008141cc406Sopenharmony_ci  if (scan->p == 0)
2009141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2010141cc406Sopenharmony_ci
2011141cc406Sopenharmony_ci  DBG (4, "UMAX_start_scan: bh = %d, linelen = %d\n", scan->bh, linelen);
2012141cc406Sopenharmony_ci
2013141cc406Sopenharmony_ci  scan->maxh = -1;
2014141cc406Sopenharmony_ci  scan->done = 0;
2015141cc406Sopenharmony_ci
2016141cc406Sopenharmony_ci  /* Initialize the scanner and position the scan head */
2017141cc406Sopenharmony_ci
2018141cc406Sopenharmony_ci  CHK (umaxinit (scan));
2019141cc406Sopenharmony_ci
2020141cc406Sopenharmony_ci  /* This scans in the black and white calibration strip that
2021141cc406Sopenharmony_ci   * is located under the scanner's lid. The scan of that strip
2022141cc406Sopenharmony_ci   * is used to pick correct values for the CCD calibration
2023141cc406Sopenharmony_ci   * values
2024141cc406Sopenharmony_ci   */
2025141cc406Sopenharmony_ci
2026141cc406Sopenharmony_ci  scan->scanner_ypos = 0;
2027141cc406Sopenharmony_ci  CHK (move (scan, 196, UMAX_NOT_FINE));
2028141cc406Sopenharmony_ci  CHK (find_zero (scan));
2029141cc406Sopenharmony_ci  CHK (move (scan, scan->scanner_yorg - 232 - scan->scanner_ypos, UMAX_FINE));
2030141cc406Sopenharmony_ci  CHK (get_caldata (scan, scan->color));
2031141cc406Sopenharmony_ci
2032141cc406Sopenharmony_ci  /* This moves the head back to the starting position */
2033141cc406Sopenharmony_ci
2034141cc406Sopenharmony_ci  yd = scan->scanner_yorg + scan->yo - scan->scanner_ypos;
2035141cc406Sopenharmony_ci  if (yd < 0)
2036141cc406Sopenharmony_ci    CHK (move (scan, yd, UMAX_FINE));
2037141cc406Sopenharmony_ci  if (yd > 300)
2038141cc406Sopenharmony_ci    CHK (move (scan, (yd - 20) / 2, UMAX_NOT_FINE));
2039141cc406Sopenharmony_ci  yd = scan->scanner_yorg + scan->yo - scan->scanner_ypos;
2040141cc406Sopenharmony_ci
2041141cc406Sopenharmony_ci  scan->yskip = yd / (600 / scan->ydpi);
2042141cc406Sopenharmony_ci  scan->xskip = scan->xo / (600 / scan->xdpi);
2043141cc406Sopenharmony_ci
2044141cc406Sopenharmony_ci  /* Read in the first chunk of raw data */
2045141cc406Sopenharmony_ci
2046141cc406Sopenharmony_ci  CHK (send_scan_parameters (scan));
2047141cc406Sopenharmony_ci  CHK (read_raw_strip (scan));
2048141cc406Sopenharmony_ci
2049141cc406Sopenharmony_ci  DBG (4, "UMAX_start_scan successful\n");
2050141cc406Sopenharmony_ci
2051141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2052141cc406Sopenharmony_ci}
2053141cc406Sopenharmony_ci
2054141cc406Sopenharmony_ci
2055141cc406Sopenharmony_ci/* Start actual scan 2100U */
2056141cc406Sopenharmony_ci
2057141cc406Sopenharmony_cistatic SANE_Status
2058141cc406Sopenharmony_ciUMAX_start_scan_2100U (UMAX_Handle * scan)
2059141cc406Sopenharmony_ci{
2060141cc406Sopenharmony_ci  SANE_Status res;
2061141cc406Sopenharmony_ci  int linelen;
2062141cc406Sopenharmony_ci  int yd;
2063141cc406Sopenharmony_ci
2064141cc406Sopenharmony_ci  DBG (3, "UMAX_start_scan called\n");
2065141cc406Sopenharmony_ci
2066141cc406Sopenharmony_ci  if (scan->color)
2067141cc406Sopenharmony_ci    {
2068141cc406Sopenharmony_ci      const int yoff_scale = 600 * scan->ysamp / scan->ydpi;
2069141cc406Sopenharmony_ci      const int hextra = 8 / yoff_scale;
2070141cc406Sopenharmony_ci
2071141cc406Sopenharmony_ci      linelen = 3 * scan->w;
2072141cc406Sopenharmony_ci      scan->hexp = scan->h + hextra;
2073141cc406Sopenharmony_ci    }
2074141cc406Sopenharmony_ci  else
2075141cc406Sopenharmony_ci    {
2076141cc406Sopenharmony_ci      linelen = scan->w;
2077141cc406Sopenharmony_ci      scan->hexp = scan->h;
2078141cc406Sopenharmony_ci    }
2079141cc406Sopenharmony_ci
2080141cc406Sopenharmony_ci  scan->bh = BUFFER_SIZE / linelen;
2081141cc406Sopenharmony_ci
2082141cc406Sopenharmony_ci  scan->p = malloc (scan->bh * linelen);
2083141cc406Sopenharmony_ci  if (scan->p == 0)
2084141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
2085141cc406Sopenharmony_ci
2086141cc406Sopenharmony_ci  DBG (4, "UMAX_start_scan: bh = %d, linelen = %d\n", scan->bh, linelen);
2087141cc406Sopenharmony_ci
2088141cc406Sopenharmony_ci  scan->maxh = -1;
2089141cc406Sopenharmony_ci  scan->done = 0;
2090141cc406Sopenharmony_ci
2091141cc406Sopenharmony_ci  /* Initialize the scanner and position the scan head */
2092141cc406Sopenharmony_ci
2093141cc406Sopenharmony_ci  CHK (umaxinit_2100U (scan));
2094141cc406Sopenharmony_ci
2095141cc406Sopenharmony_ci  /* This scans in the black and white calibration strip that
2096141cc406Sopenharmony_ci   * is located under the scanner's lid. The scan of that strip
2097141cc406Sopenharmony_ci   * is used to pick correct values for the CCD calibration
2098141cc406Sopenharmony_ci   * values
2099141cc406Sopenharmony_ci   */
2100141cc406Sopenharmony_ci
2101141cc406Sopenharmony_ci  scan->scanner_ypos = 0;
2102141cc406Sopenharmony_ci  CHK (move_2100U (scan, 196, UMAX_NOT_FINE));
2103141cc406Sopenharmony_ci  CHK (find_zero_2100U (scan));
2104141cc406Sopenharmony_ci  CHK (move_2100U (scan, scan->scanner_yorg - 232 - scan->scanner_ypos, UMAX_FINE));
2105141cc406Sopenharmony_ci  CHK (get_caldata_2100U (scan, scan->color));
2106141cc406Sopenharmony_ci
2107141cc406Sopenharmony_ci  /* This moves the head back to the starting position */
2108141cc406Sopenharmony_ci
2109141cc406Sopenharmony_ci  yd = scan->scanner_yorg + scan->yo - scan->scanner_ypos;
2110141cc406Sopenharmony_ci  if (yd < 0)
2111141cc406Sopenharmony_ci    CHK (move_2100U (scan, yd, UMAX_FINE));
2112141cc406Sopenharmony_ci  if (yd > 300)
2113141cc406Sopenharmony_ci    CHK (move_2100U (scan, (yd - 20) / 2, UMAX_NOT_FINE));
2114141cc406Sopenharmony_ci  yd = scan->scanner_yorg + scan->yo - scan->scanner_ypos;
2115141cc406Sopenharmony_ci
2116141cc406Sopenharmony_ci  scan->yskip = yd / (600 / scan->ydpi);
2117141cc406Sopenharmony_ci  scan->xskip = scan->xo / (600 / scan->xdpi);
2118141cc406Sopenharmony_ci
2119141cc406Sopenharmony_ci  /* Read in the first chunk of raw data */
2120141cc406Sopenharmony_ci
2121141cc406Sopenharmony_ci  CHK (send_scan_parameters_2100U (scan));
2122141cc406Sopenharmony_ci  CHK (read_raw_strip (scan));
2123141cc406Sopenharmony_ci
2124141cc406Sopenharmony_ci  DBG (4, "UMAX_start_scan successful\n");
2125141cc406Sopenharmony_ci
2126141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2127141cc406Sopenharmony_ci}
2128141cc406Sopenharmony_ci
2129141cc406Sopenharmony_ci/* Set lamp state */
2130141cc406Sopenharmony_ci
2131141cc406Sopenharmony_cistatic SANE_Status
2132141cc406Sopenharmony_ciUMAX_set_lamp_state (UMAX_Handle * scan, UMAX_Lamp_State state)
2133141cc406Sopenharmony_ci{
2134141cc406Sopenharmony_ci  SANE_Status res;
2135141cc406Sopenharmony_ci
2136141cc406Sopenharmony_ci  DBG (3, "UMAX_set_lamp_state: state = %d\n", (int) state);
2137141cc406Sopenharmony_ci
2138141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
2139141cc406Sopenharmony_ci  CHK (cwritev_opc1_lamp_ctrl (scan, state));
2140141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2141141cc406Sopenharmony_ci}
2142141cc406Sopenharmony_ci
2143141cc406Sopenharmony_ci/* Park head 1220U */
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_cistatic SANE_Status
2146141cc406Sopenharmony_ciUMAX_park_head (UMAX_Handle * scan)
2147141cc406Sopenharmony_ci{
2148141cc406Sopenharmony_ci  SANE_Status res;
2149141cc406Sopenharmony_ci  UMAX_Status_Byte s;
2150141cc406Sopenharmony_ci  int i;
2151141cc406Sopenharmony_ci
2152141cc406Sopenharmony_ci  DBG (3, "UMAX_park_head called\n");
2153141cc406Sopenharmony_ci
2154141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
2155141cc406Sopenharmony_ci  /* WARNING: Must call cwritev_opc1_lamp_ctrl before cwritev_opb3_restore,
2156141cc406Sopenharmony_ci   * otherwise the head moves the wrong way and makes ugly grinding noises. */
2157141cc406Sopenharmony_ci
2158141cc406Sopenharmony_ci  CHK (cwritev_opc1_lamp_ctrl (scan, UMAX_LAMP_ON));
2159141cc406Sopenharmony_ci  CHK (cwritev_opb3_restore (scan));
2160141cc406Sopenharmony_ci
2161141cc406Sopenharmony_ci  for (i = 0; i < 60; ++i)
2162141cc406Sopenharmony_ci    {
2163141cc406Sopenharmony_ci      CHK (cread (scan, CMD_2, 0, NULL, &s));
2164141cc406Sopenharmony_ci      DBG (4, "UMAX_park_head: s = %#x\n", s);
2165141cc406Sopenharmony_ci      if ((s & 0x40) != 0)
2166141cc406Sopenharmony_ci        break;
2167141cc406Sopenharmony_ci      DBG (4, "UMAX_park_head: sleeping\n");
2168141cc406Sopenharmony_ci      usleep (500000);
2169141cc406Sopenharmony_ci    }
2170141cc406Sopenharmony_ci
2171141cc406Sopenharmony_ci  scan->scanner_ypos = 0;
2172141cc406Sopenharmony_ci
2173141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2174141cc406Sopenharmony_ci}
2175141cc406Sopenharmony_ci
2176141cc406Sopenharmony_ci
2177141cc406Sopenharmony_ci/* Park head 2100U */
2178141cc406Sopenharmony_ci
2179141cc406Sopenharmony_cistatic SANE_Status
2180141cc406Sopenharmony_ciUMAX_park_head_2100U (UMAX_Handle * scan)
2181141cc406Sopenharmony_ci{
2182141cc406Sopenharmony_ci  SANE_Status res;
2183141cc406Sopenharmony_ci  UMAX_Status_Byte s;
2184141cc406Sopenharmony_ci  int i;
2185141cc406Sopenharmony_ci
2186141cc406Sopenharmony_ci  DBG (3, "UMAX_park_head called\n");
2187141cc406Sopenharmony_ci
2188141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0));
2189141cc406Sopenharmony_ci  /* WARNING: Must call cwritev_opc1_lamp_ctrl before cwritev_opb3_restore,
2190141cc406Sopenharmony_ci   * otherwise the head moves the wrong way and makes ugly grinding noises. */
2191141cc406Sopenharmony_ci
2192141cc406Sopenharmony_ci  CHK (cwritev_opc1_lamp_ctrl (scan, UMAX_LAMP_ON));
2193141cc406Sopenharmony_ci  CHK (cwritev_opb3_restore_2100U (scan));
2194141cc406Sopenharmony_ci
2195141cc406Sopenharmony_ci  for (i = 0; i < 60; ++i)
2196141cc406Sopenharmony_ci    {
2197141cc406Sopenharmony_ci      CHK (cread (scan, CMD_2, 0, NULL, &s));
2198141cc406Sopenharmony_ci      DBG (4, "UMAX_park_head: s = %#x\n", s);
2199141cc406Sopenharmony_ci      if ((s & 0x40) != 0)
2200141cc406Sopenharmony_ci        break;
2201141cc406Sopenharmony_ci      DBG (4, "UMAX_park_head: sleeping\n");
2202141cc406Sopenharmony_ci      usleep (500000);
2203141cc406Sopenharmony_ci    }
2204141cc406Sopenharmony_ci
2205141cc406Sopenharmony_ci  /* CHK (csend (scan, CMD_0));
2206141cc406Sopenharmony_ci  CHK (csend (scan, CMD_0)); */
2207141cc406Sopenharmony_ci
2208141cc406Sopenharmony_ci  scan->scanner_ypos = 0;
2209141cc406Sopenharmony_ci
2210141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2211141cc406Sopenharmony_ci}
2212141cc406Sopenharmony_ci
2213141cc406Sopenharmony_ci
2214141cc406Sopenharmony_ci/* Finish scan */
2215141cc406Sopenharmony_ci
2216141cc406Sopenharmony_cistatic SANE_Status
2217141cc406Sopenharmony_ciUMAX_finish_scan (UMAX_Handle * scan)
2218141cc406Sopenharmony_ci{
2219141cc406Sopenharmony_ci  DBG (3, "UMAX_finish_scan:\n");
2220141cc406Sopenharmony_ci
2221141cc406Sopenharmony_ci  if (scan->p)
2222141cc406Sopenharmony_ci    free (scan->p);
2223141cc406Sopenharmony_ci  scan->p = NULL;
2224141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2225141cc406Sopenharmony_ci}
2226141cc406Sopenharmony_ci
2227141cc406Sopenharmony_ci
2228141cc406Sopenharmony_ci/* RGB decoding for a color scan */
2229141cc406Sopenharmony_ci
2230141cc406Sopenharmony_cistatic SANE_Status
2231141cc406Sopenharmony_ciUMAX_get_rgb (UMAX_Handle * scan, unsigned char *rgb)
2232141cc406Sopenharmony_ci{
2233141cc406Sopenharmony_ci
2234141cc406Sopenharmony_ci  if (scan->color)
2235141cc406Sopenharmony_ci    {
2236141cc406Sopenharmony_ci      const int linelen = 3 * scan->w;
2237141cc406Sopenharmony_ci      const int yoff_scale = 600 * scan->ysamp / scan->ydpi;
2238141cc406Sopenharmony_ci      const int roff = (8 / yoff_scale * 3 + 2) * scan->w;
2239141cc406Sopenharmony_ci      const int goff = (4 / yoff_scale * 3 + 1) * scan->w;
2240141cc406Sopenharmony_ci      const int boff = 0;
2241141cc406Sopenharmony_ci
2242141cc406Sopenharmony_ci      unsigned char *base = scan->p + (scan->y * linelen) + scan->x;
2243141cc406Sopenharmony_ci
2244141cc406Sopenharmony_ci      rgb[0] = base[roff];
2245141cc406Sopenharmony_ci      rgb[1] = base[goff];
2246141cc406Sopenharmony_ci      rgb[2] = base[boff];
2247141cc406Sopenharmony_ci    }
2248141cc406Sopenharmony_ci  else
2249141cc406Sopenharmony_ci    {
2250141cc406Sopenharmony_ci      const int linelen = scan->w;
2251141cc406Sopenharmony_ci      unsigned char *base = scan->p + (scan->y * linelen) + (scan->x);
2252141cc406Sopenharmony_ci
2253141cc406Sopenharmony_ci      rgb[0] = base[0];
2254141cc406Sopenharmony_ci      rgb[1] = base[0];
2255141cc406Sopenharmony_ci      rgb[2] = base[0];
2256141cc406Sopenharmony_ci    }
2257141cc406Sopenharmony_ci
2258141cc406Sopenharmony_ci  if (!(((scan->x + 1) == scan->w) && ((scan->y + 1) == scan->maxh)))
2259141cc406Sopenharmony_ci    {
2260141cc406Sopenharmony_ci      ++scan->x;
2261141cc406Sopenharmony_ci      if (scan->x == scan->w)
2262141cc406Sopenharmony_ci        {
2263141cc406Sopenharmony_ci          ++scan->y;
2264141cc406Sopenharmony_ci          scan->x = 0;
2265141cc406Sopenharmony_ci        }
2266141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2267141cc406Sopenharmony_ci    }
2268141cc406Sopenharmony_ci
2269141cc406Sopenharmony_ci  if (scan->hexp <= 0)
2270141cc406Sopenharmony_ci    {
2271141cc406Sopenharmony_ci      DBG (4, "UMAX_get_rgb: setting done flag\n");
2272141cc406Sopenharmony_ci      scan->done = 1;
2273141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2274141cc406Sopenharmony_ci    }
2275141cc406Sopenharmony_ci
2276141cc406Sopenharmony_ci  return read_raw_strip (scan);
2277141cc406Sopenharmony_ci}
2278141cc406Sopenharmony_ci
2279141cc406Sopenharmony_ci/* Close device */
2280141cc406Sopenharmony_ci
2281141cc406Sopenharmony_cistatic SANE_Status
2282141cc406Sopenharmony_ciUMAX_close_device (UMAX_Handle * scan)
2283141cc406Sopenharmony_ci{
2284141cc406Sopenharmony_ci  DBG (3, "UMAX_close_device:\n");
2285141cc406Sopenharmony_ci  sanei_usb_close (scan->fd);
2286141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2287141cc406Sopenharmony_ci}
2288141cc406Sopenharmony_ci
2289141cc406Sopenharmony_ci/* Open device */
2290141cc406Sopenharmony_ci
2291141cc406Sopenharmony_cistatic SANE_Status
2292141cc406Sopenharmony_ciUMAX_open_device (UMAX_Handle * scan, const char *dev)
2293141cc406Sopenharmony_ci{
2294141cc406Sopenharmony_ci  SANE_Word vendor;
2295141cc406Sopenharmony_ci  SANE_Word product;
2296141cc406Sopenharmony_ci  SANE_Status res;
2297141cc406Sopenharmony_ci
2298141cc406Sopenharmony_ci  DBG (3, "UMAX_open_device: `%s'\n", dev);
2299141cc406Sopenharmony_ci
2300141cc406Sopenharmony_ci  res = sanei_usb_open (dev, &scan->fd);
2301141cc406Sopenharmony_ci  if (res != SANE_STATUS_GOOD)
2302141cc406Sopenharmony_ci    {
2303141cc406Sopenharmony_ci      DBG (1, "UMAX_open_device: couldn't open device `%s': %s\n", dev,
2304141cc406Sopenharmony_ci           sane_strstatus (res));
2305141cc406Sopenharmony_ci      return res;
2306141cc406Sopenharmony_ci    }
2307141cc406Sopenharmony_ci
2308141cc406Sopenharmony_ci#ifndef NO_AUTODETECT
2309141cc406Sopenharmony_ci  /* We have opened the device. Check that it is a USB scanner. */
2310141cc406Sopenharmony_ci  if (sanei_usb_get_vendor_product (scan->fd, &vendor, &product) !=
2311141cc406Sopenharmony_ci      SANE_STATUS_GOOD)
2312141cc406Sopenharmony_ci    {
2313141cc406Sopenharmony_ci      DBG (1, "UMAX_open_device: sanei_usb_get_vendor_product failed\n");
2314141cc406Sopenharmony_ci      /* This is not a USB scanner, or SANE or the OS doesn't support it. */
2315141cc406Sopenharmony_ci      sanei_usb_close (scan->fd);
2316141cc406Sopenharmony_ci      scan->fd = -1;
2317141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
2318141cc406Sopenharmony_ci    }
2319141cc406Sopenharmony_ci
2320141cc406Sopenharmony_ci  /* Make sure we have a UMAX scanner */
2321141cc406Sopenharmony_ci  if (vendor != 0x1606)
2322141cc406Sopenharmony_ci    {
2323141cc406Sopenharmony_ci      DBG (1, "UMAX_open_device: incorrect vendor\n");
2324141cc406Sopenharmony_ci      sanei_usb_close (scan->fd);
2325141cc406Sopenharmony_ci      scan->fd = -1;
2326141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
2327141cc406Sopenharmony_ci    }
2328141cc406Sopenharmony_ci
2329141cc406Sopenharmony_ci  /* Now check whether it is a scanner we know about */
2330141cc406Sopenharmony_ci  switch (product)
2331141cc406Sopenharmony_ci    {
2332141cc406Sopenharmony_ci    case ASTRA_2000U:
2333141cc406Sopenharmony_ci      /* The UMAX Astra 2000U is only partially supported by
2334141cc406Sopenharmony_ci         this driver. Expect severe color problems! :)
2335141cc406Sopenharmony_ci       */
2336141cc406Sopenharmony_ci      DBG (1,
2337141cc406Sopenharmony_ci           "UMAX_open_device: Scanner is a 2000U. Expect color problems :)\n");
2338141cc406Sopenharmony_ci      scan->model = ASTRA_2000U;
2339141cc406Sopenharmony_ci      break;
2340141cc406Sopenharmony_ci     case ASTRA_2100U:
2341141cc406Sopenharmony_ci       scan->model = ASTRA_2100U;
2342141cc406Sopenharmony_ci      break;
2343141cc406Sopenharmony_ci    case ASTRA_1220U:
2344141cc406Sopenharmony_ci       scan->model = ASTRA_1220U;
2345141cc406Sopenharmony_ci      break;
2346141cc406Sopenharmony_ci    default:
2347141cc406Sopenharmony_ci      DBG (1, "UMAX_open_device: unknown product number\n");
2348141cc406Sopenharmony_ci      sanei_usb_close (scan->fd);
2349141cc406Sopenharmony_ci      scan->fd = -1;
2350141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
2351141cc406Sopenharmony_ci    }
2352141cc406Sopenharmony_ci#endif
2353141cc406Sopenharmony_ci
2354141cc406Sopenharmony_ci  res = csend (scan, CMD_0);
2355141cc406Sopenharmony_ci  if (res != SANE_STATUS_GOOD)
2356141cc406Sopenharmony_ci    UMAX_close_device (scan);
2357141cc406Sopenharmony_ci  CHK (res);
2358141cc406Sopenharmony_ci
2359141cc406Sopenharmony_ci  res = xxxops (scan);
2360141cc406Sopenharmony_ci  if (res != SANE_STATUS_GOOD)
2361141cc406Sopenharmony_ci    UMAX_close_device (scan);
2362141cc406Sopenharmony_ci  CHK (res);
2363141cc406Sopenharmony_ci
2364141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2365141cc406Sopenharmony_ci}
2366141cc406Sopenharmony_ci
2367141cc406Sopenharmony_ci/* Get scanner model name */
2368141cc406Sopenharmony_ci
2369141cc406Sopenharmony_cistatic const char *
2370141cc406Sopenharmony_ciUMAX_get_device_name (UMAX_Handle * scan)
2371141cc406Sopenharmony_ci{
2372141cc406Sopenharmony_ci  switch (scan->model)
2373141cc406Sopenharmony_ci    {
2374141cc406Sopenharmony_ci    case ASTRA_1220U:
2375141cc406Sopenharmony_ci      return "Astra 1220U";
2376141cc406Sopenharmony_ci    case ASTRA_2000U:
2377141cc406Sopenharmony_ci      return "Astra 2000U";
2378141cc406Sopenharmony_ci    case ASTRA_2100U:
2379141cc406Sopenharmony_ci      return "Astra 2100U";
2380141cc406Sopenharmony_ci    }
2381141cc406Sopenharmony_ci  return "Unknown";
2382141cc406Sopenharmony_ci}
2383141cc406Sopenharmony_ci
2384141cc406Sopenharmony_ci/* End */
2385