1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   pie.c
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   Copyright (C) 2000 Simon Munton, based on the umax backend by Oliver Rauch
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This file is part of the SANE package.
8141cc406Sopenharmony_ci
9141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
10141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
11141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
12141cc406Sopenharmony_ci   License, or (at your option) any later version.
13141cc406Sopenharmony_ci
14141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
15141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
16141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17141cc406Sopenharmony_ci   General Public License for more details.
18141cc406Sopenharmony_ci
19141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
20141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
23141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
24141cc406Sopenharmony_ci
25141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
26141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
27141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
28141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
29141cc406Sopenharmony_ci   account of linking the SANE library code into it.
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
32141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
33141cc406Sopenharmony_ci   License.
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
36141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
37141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
38141cc406Sopenharmony_ci
39141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
40141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
41141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.  */
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci/*
44141cc406Sopenharmony_ci * 22-2-2003 set devlist to NULL in sane_exit()
45141cc406Sopenharmony_ci *           set first_dev to NULL in sane_exit()
46141cc406Sopenharmony_ci *           eliminated num_devices
47141cc406Sopenharmony_ci *
48141cc406Sopenharmony_ci * 23-7-2002 added TL_X > BR_X, TL_Y > BR_Y check in sane_start
49141cc406Sopenharmony_ci *
50141cc406Sopenharmony_ci * 17-9-2001 changed ADLIB to AdLib as the comparison is case sensitive and
51141cc406Sopenharmony_ci * 	     the scanner returns AdLib
52141cc406Sopenharmony_ci *
53141cc406Sopenharmony_ci * 7-5-2001 removed removal of '\n' after sanei_config_read()
54141cc406Sopenharmony_ci *	    free devlist allocated in sane_get_devices() on sane_exit()
55141cc406Sopenharmony_ci *
56141cc406Sopenharmony_ci * 2-3-2001 improved the reordering of RGB data in pie_reader_process()
57141cc406Sopenharmony_ci *
58141cc406Sopenharmony_ci * 11-11-2000 eliminated some warnings about signed/unsigned comparisons
59141cc406Sopenharmony_ci *            removed #undef NDEBUG and C++ style comments
60141cc406Sopenharmony_ci *
61141cc406Sopenharmony_ci * 1-10-2000 force gamma table to one to one mapping if lineart or halftone selected
62141cc406Sopenharmony_ci *
63141cc406Sopenharmony_ci * 30-9-2000 added ADLIB devices to scanner_str[]
64141cc406Sopenharmony_ci *
65141cc406Sopenharmony_ci * 29-9-2000 wasn't setting 'background is halftone bit' (BGHT) in halftone mode
66141cc406Sopenharmony_ci *
67141cc406Sopenharmony_ci * 27-9-2000 went public with build 4
68141cc406Sopenharmony_ci */
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_ci#include "../include/sane/config.h"
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci#include <errno.h>
73141cc406Sopenharmony_ci#include <fcntl.h>
74141cc406Sopenharmony_ci#include <limits.h>
75141cc406Sopenharmony_ci#include <signal.h>
76141cc406Sopenharmony_ci#include <stdio.h>
77141cc406Sopenharmony_ci#include <stdlib.h>
78141cc406Sopenharmony_ci#include <string.h>
79141cc406Sopenharmony_ci#include <sys/types.h>
80141cc406Sopenharmony_ci#include <sys/wait.h>
81141cc406Sopenharmony_ci#include <unistd.h>
82141cc406Sopenharmony_ci
83141cc406Sopenharmony_ci#include "../include/sane/sane.h"
84141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
85141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
86141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
87141cc406Sopenharmony_ci#include "../include/sane/sanei_debug.h"
88141cc406Sopenharmony_ci
89141cc406Sopenharmony_ci#define BACKEND_NAME	pie
90141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
91141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ci# include "../include/sane/sanei_thread.h"
94141cc406Sopenharmony_ci
95141cc406Sopenharmony_ci#include "pie-scsidef.h"
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci#define DBG_error0  0
98141cc406Sopenharmony_ci#define DBG_error   1
99141cc406Sopenharmony_ci#define DBG_sense   2
100141cc406Sopenharmony_ci#define DBG_warning 3
101141cc406Sopenharmony_ci#define DBG_inquiry 4
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci#define DBG_info    5
104141cc406Sopenharmony_ci#define DBG_info2   6
105141cc406Sopenharmony_ci#define DBG_proc    7
106141cc406Sopenharmony_ci#define DBG_read    8
107141cc406Sopenharmony_ci#define DBG_sane_init   10
108141cc406Sopenharmony_ci#define DBG_sane_proc   11
109141cc406Sopenharmony_ci#define DBG_sane_info   12
110141cc406Sopenharmony_ci#define DBG_sane_option 13
111141cc406Sopenharmony_ci#define DBG_dump	14
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_ci#define BUILD 9
114141cc406Sopenharmony_ci
115141cc406Sopenharmony_ci#define PIE_CONFIG_FILE "pie.conf"
116141cc406Sopenharmony_ci
117141cc406Sopenharmony_ci#define LINEART_STR         SANE_VALUE_SCAN_MODE_LINEART
118141cc406Sopenharmony_ci#define HALFTONE_STR        SANE_VALUE_SCAN_MODE_HALFTONE
119141cc406Sopenharmony_ci#define GRAY_STR            SANE_VALUE_SCAN_MODE_GRAY
120141cc406Sopenharmony_ci#define COLOR_STR           SANE_VALUE_SCAN_MODE_COLOR
121141cc406Sopenharmony_ci
122141cc406Sopenharmony_ci#define LINEART             1
123141cc406Sopenharmony_ci#define HALFTONE            2
124141cc406Sopenharmony_ci#define GRAYSCALE           3
125141cc406Sopenharmony_ci#define RGB                 4
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ci#define CAL_MODE_PREVIEW        (INQ_CAP_FAST_PREVIEW)
128141cc406Sopenharmony_ci#define CAL_MODE_FLATBED        0x00
129141cc406Sopenharmony_ci#define CAL_MODE_ADF            (INQ_OPT_DEV_ADF)
130141cc406Sopenharmony_ci#define CAL_MODE_TRANPSARENCY   (INQ_OPT_DEV_TP)
131141cc406Sopenharmony_ci#define CAL_MODE_TRANPSARENCY1  (INQ_OPT_DEV_TP1)
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci#define min(a,b) (((a)<(b))?(a):(b))
134141cc406Sopenharmony_ci#define max(a,b) (((a)>(b))?(a):(b))
135141cc406Sopenharmony_ci
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci/* names of scanners that are supported because */
138141cc406Sopenharmony_ci/* the inquiry_return_block is ok and driver is tested */
139141cc406Sopenharmony_ci
140141cc406Sopenharmony_cistatic char *scanner_str[] = {
141141cc406Sopenharmony_ci  "DEVCOM", "9636PRO",
142141cc406Sopenharmony_ci  "DEVCOM", "9636S",
143141cc406Sopenharmony_ci  "DEVCOM", "9630S",
144141cc406Sopenharmony_ci  "PIE", "ScanAce 1236S",
145141cc406Sopenharmony_ci  "PIE", "ScanAce 1230S",
146141cc406Sopenharmony_ci  "PIE", "ScanAce II",
147141cc406Sopenharmony_ci  "PIE", "ScanAce III",
148141cc406Sopenharmony_ci  "PIE", "ScanAce Plus",
149141cc406Sopenharmony_ci  "PIE", "ScanAce II Plus",
150141cc406Sopenharmony_ci  "PIE", "ScanAce III Plus",
151141cc406Sopenharmony_ci  "PIE", "ScanAce V",
152141cc406Sopenharmony_ci  "PIE", "ScanMedia",
153141cc406Sopenharmony_ci  "PIE", "ScanMedia II",
154141cc406Sopenharmony_ci  "PIE", "ScanAce 630S",
155141cc406Sopenharmony_ci  "PIE", "ScanAce 636S",
156141cc406Sopenharmony_ci  "AdLib", "JetScan 630",
157141cc406Sopenharmony_ci  "AdLib", "JetScan 636PRO",
158141cc406Sopenharmony_ci  "END_OF_LIST"
159141cc406Sopenharmony_ci};
160141cc406Sopenharmony_ci
161141cc406Sopenharmony_ci/* times (in us) to delay after certain commands. Scanner seems to lock up if it returns busy
162141cc406Sopenharmony_ci * status and commands are repeatedly reissued (by kernel error handler) */
163141cc406Sopenharmony_ci
164141cc406Sopenharmony_ci#define DOWNLOAD_GAMMA_WAIT_TIME	(1000000)
165141cc406Sopenharmony_ci#define SCAN_WAIT_TIME			(1000000)
166141cc406Sopenharmony_ci#define SCAN_WARMUP_WAIT_TIME		(500000)
167141cc406Sopenharmony_ci#define TUR_WAIT_TIME			(500000)
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci
170141cc406Sopenharmony_ci/* options supported by the scanner */
171141cc406Sopenharmony_ci
172141cc406Sopenharmony_cienum Pie_Option
173141cc406Sopenharmony_ci{
174141cc406Sopenharmony_ci  OPT_NUM_OPTS = 0,
175141cc406Sopenharmony_ci
176141cc406Sopenharmony_ci  /* ------------------------------------------- */
177141cc406Sopenharmony_ci  OPT_MODE_GROUP,
178141cc406Sopenharmony_ci  OPT_MODE,
179141cc406Sopenharmony_ci  OPT_RESOLUTION,
180141cc406Sopenharmony_ci
181141cc406Sopenharmony_ci
182141cc406Sopenharmony_ci  /* ------------------------------------------- */
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci  OPT_GEOMETRY_GROUP,
185141cc406Sopenharmony_ci  OPT_TL_X,			/* top-left x */
186141cc406Sopenharmony_ci  OPT_TL_Y,			/* top-left y */
187141cc406Sopenharmony_ci  OPT_BR_X,			/* bottom-right x */
188141cc406Sopenharmony_ci  OPT_BR_Y,			/* bottom-right y */
189141cc406Sopenharmony_ci
190141cc406Sopenharmony_ci  /* ------------------------------------------- */
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_ci  OPT_ENHANCEMENT_GROUP,
193141cc406Sopenharmony_ci
194141cc406Sopenharmony_ci  OPT_HALFTONE_PATTERN,
195141cc406Sopenharmony_ci  OPT_SPEED,
196141cc406Sopenharmony_ci  OPT_THRESHOLD,
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_ci  OPT_GAMMA_VECTOR,
199141cc406Sopenharmony_ci  OPT_GAMMA_VECTOR_R,
200141cc406Sopenharmony_ci  OPT_GAMMA_VECTOR_G,
201141cc406Sopenharmony_ci  OPT_GAMMA_VECTOR_B,
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_ci  /* ------------------------------------------- */
204141cc406Sopenharmony_ci
205141cc406Sopenharmony_ci  OPT_ADVANCED_GROUP,
206141cc406Sopenharmony_ci  OPT_PREVIEW,
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_ci  /* must come last: */
209141cc406Sopenharmony_ci  NUM_OPTIONS
210141cc406Sopenharmony_ci};
211141cc406Sopenharmony_ci
212141cc406Sopenharmony_ci
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci
215141cc406Sopenharmony_ci/* This defines the information needed during calibration */
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_cistruct Pie_cal_info
218141cc406Sopenharmony_ci{
219141cc406Sopenharmony_ci  int cal_type;
220141cc406Sopenharmony_ci  int receive_bits;
221141cc406Sopenharmony_ci  int send_bits;
222141cc406Sopenharmony_ci  int num_lines;
223141cc406Sopenharmony_ci  int pixels_per_line;
224141cc406Sopenharmony_ci};
225141cc406Sopenharmony_ci
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_ci/* This structure holds the information about a physical scanner */
228141cc406Sopenharmony_ci
229141cc406Sopenharmony_citypedef struct Pie_Device
230141cc406Sopenharmony_ci{
231141cc406Sopenharmony_ci  struct Pie_Device *next;
232141cc406Sopenharmony_ci
233141cc406Sopenharmony_ci  char *devicename;		/* name of the scanner device */
234141cc406Sopenharmony_ci
235141cc406Sopenharmony_ci  char vendor[9];		/* will be xxxxx */
236141cc406Sopenharmony_ci  char product[17];		/* e.g. "SuperVista_S12" or so */
237141cc406Sopenharmony_ci  char version[5];		/* e.g. V1.3 */
238141cc406Sopenharmony_ci
239141cc406Sopenharmony_ci  SANE_Device sane;
240141cc406Sopenharmony_ci  SANE_Range dpi_range;
241141cc406Sopenharmony_ci  SANE_Range x_range;
242141cc406Sopenharmony_ci  SANE_Range y_range;
243141cc406Sopenharmony_ci
244141cc406Sopenharmony_ci  SANE_Range exposure_range;
245141cc406Sopenharmony_ci  SANE_Range shadow_range;
246141cc406Sopenharmony_ci  SANE_Range highlight_range;
247141cc406Sopenharmony_ci
248141cc406Sopenharmony_ci  int inquiry_len;		/* length of inquiry return block */
249141cc406Sopenharmony_ci
250141cc406Sopenharmony_ci  int inquiry_x_res;		/* maximum x-resolution */
251141cc406Sopenharmony_ci  int inquiry_y_res;		/* maximum y-resolution */
252141cc406Sopenharmony_ci  int inquiry_pixel_resolution;
253141cc406Sopenharmony_ci  double inquiry_fb_width;	/* flatbed width in inches */
254141cc406Sopenharmony_ci  double inquiry_fb_length;	/* flatbed length in inches */
255141cc406Sopenharmony_ci
256141cc406Sopenharmony_ci  int inquiry_trans_top_left_x;
257141cc406Sopenharmony_ci  int inquiry_trans_top_left_y;
258141cc406Sopenharmony_ci  double inquiry_trans_width;	/* transparency width in inches */
259141cc406Sopenharmony_ci  double inquiry_trans_length;	/* transparency length in inches */
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci  int inquiry_halftones;	/* number of halftones supported */
262141cc406Sopenharmony_ci  int inquiry_filters;		/* available colour filters */
263141cc406Sopenharmony_ci  int inquiry_color_depths;	/* available colour depths */
264141cc406Sopenharmony_ci  int inquiry_color_format;	/* colour format from scanner */
265141cc406Sopenharmony_ci  int inquiry_image_format;	/* image data format */
266141cc406Sopenharmony_ci  int inquiry_scan_capability;	/* additional scanner features, number of speeds */
267141cc406Sopenharmony_ci  int inquiry_optional_devices;	/* optional devices */
268141cc406Sopenharmony_ci  int inquiry_enhancements;	/* enhancements */
269141cc406Sopenharmony_ci  int inquiry_gamma_bits;	/* no of bits used for gamma table */
270141cc406Sopenharmony_ci  int inquiry_fast_preview_res;	/* fast preview resolution */
271141cc406Sopenharmony_ci  int inquiry_min_highlight;	/* min highlight % that can be used */
272141cc406Sopenharmony_ci  int inquiry_max_shadow;	/* max shadow % that can be used */
273141cc406Sopenharmony_ci  int inquiry_cal_eqn;		/* which calibration equation to use */
274141cc406Sopenharmony_ci  int inquiry_min_exp;		/* min exposure % */
275141cc406Sopenharmony_ci  int inquiry_max_exp;		/* max exposure % */
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci  SANE_String scan_mode_list[7];	/* holds names of types of scan (color, ...) */
278141cc406Sopenharmony_ci
279141cc406Sopenharmony_ci  SANE_String halftone_list[17];	/* holds the names of the halftone patterns from the scanner */
280141cc406Sopenharmony_ci
281141cc406Sopenharmony_ci  SANE_String speed_list[9];	/* holds the names of available speeds */
282141cc406Sopenharmony_ci
283141cc406Sopenharmony_ci  int cal_info_count;		/* number of calibration info sets */
284141cc406Sopenharmony_ci  struct Pie_cal_info *cal_info;	/* points to the actual calibration information */
285141cc406Sopenharmony_ci}
286141cc406Sopenharmony_ciPie_Device;
287141cc406Sopenharmony_ci
288141cc406Sopenharmony_ci/* This structure holds information about an instance of an 'opened' scanner */
289141cc406Sopenharmony_ci
290141cc406Sopenharmony_citypedef struct Pie_Scanner
291141cc406Sopenharmony_ci{
292141cc406Sopenharmony_ci  struct Pie_Scanner *next;
293141cc406Sopenharmony_ci  Pie_Device *device;		/* pointer to physical scanner */
294141cc406Sopenharmony_ci
295141cc406Sopenharmony_ci  int sfd;			/* scanner file desc. */
296141cc406Sopenharmony_ci  int bufsize;			/* max scsi buffer size */
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci  SANE_Option_Descriptor opt[NUM_OPTIONS];	/* option descriptions for this instance */
299141cc406Sopenharmony_ci  Option_Value val[NUM_OPTIONS];	/* option settings for this instance */
300141cc406Sopenharmony_ci  SANE_Int *gamma_table[4];	/* gamma tables for this instance */
301141cc406Sopenharmony_ci  SANE_Range gamma_range;
302141cc406Sopenharmony_ci  int gamma_length;		/* size of gamma table */
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ci  int scanning;			/* true if actually doing a scan */
305141cc406Sopenharmony_ci  SANE_Parameters params;
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci  SANE_Pid reader_pid;
308141cc406Sopenharmony_ci  int pipe;
309141cc406Sopenharmony_ci  int reader_fds;
310141cc406Sopenharmony_ci
311141cc406Sopenharmony_ci  int colormode;		/* whether RGB, GRAY, LINEART, HALFTONE */
312141cc406Sopenharmony_ci  int resolution;
313141cc406Sopenharmony_ci  int cal_mode;			/* set to value to compare cal_info mode to */
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_ci  int cal_filter;		/* set to indicate which filters will provide data for cal */
316141cc406Sopenharmony_ci
317141cc406Sopenharmony_ci  int filter_offset1;		/* offsets between colors in indexed scan mode */
318141cc406Sopenharmony_ci  int filter_offset2;
319141cc406Sopenharmony_ci
320141cc406Sopenharmony_ci  int bytes_per_line;		/* number of bytes per line */
321141cc406Sopenharmony_ci
322141cc406Sopenharmony_ci}
323141cc406Sopenharmony_ciPie_Scanner;
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_cistatic const SANE_Range percentage_range_100 = {
326141cc406Sopenharmony_ci  0 << SANE_FIXED_SCALE_SHIFT,	/* minimum */
327141cc406Sopenharmony_ci  100 << SANE_FIXED_SCALE_SHIFT,	/* maximum */
328141cc406Sopenharmony_ci  0 << SANE_FIXED_SCALE_SHIFT	/* quantization */
329141cc406Sopenharmony_ci};
330141cc406Sopenharmony_ci
331141cc406Sopenharmony_cistatic Pie_Device *first_dev = NULL;
332141cc406Sopenharmony_cistatic Pie_Scanner *first_handle = NULL;
333141cc406Sopenharmony_cistatic const SANE_Device **devlist = NULL;
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_ci
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_cistatic SANE_Status pie_wait_scanner (Pie_Scanner * scanner);
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci
340141cc406Sopenharmony_ci/* ---------------------------------- PIE DUMP_BUFFER ---------------------------------- */
341141cc406Sopenharmony_ci
342141cc406Sopenharmony_ci#define DBG_DUMP(level, buf, n)	{ if (DBG_LEVEL >= (level)) pie_dump_buffer(level,buf,n); }
343141cc406Sopenharmony_ci
344141cc406Sopenharmony_ci
345141cc406Sopenharmony_cistatic void
346141cc406Sopenharmony_cipie_dump_buffer (int level, unsigned char *buf, int n)
347141cc406Sopenharmony_ci{
348141cc406Sopenharmony_ci  char s[80], *p = s;
349141cc406Sopenharmony_ci  int a = 0;
350141cc406Sopenharmony_ci
351141cc406Sopenharmony_ci  while (n--)
352141cc406Sopenharmony_ci    {
353141cc406Sopenharmony_ci      if ((a % 16) == 0)
354141cc406Sopenharmony_ci	p += sprintf (p, "  %04X  ", a);
355141cc406Sopenharmony_ci
356141cc406Sopenharmony_ci      p += sprintf (p, "%02X ", *buf++);
357141cc406Sopenharmony_ci
358141cc406Sopenharmony_ci      if ((n == 0) || (a % 16) == 15)
359141cc406Sopenharmony_ci	{
360141cc406Sopenharmony_ci	  DBG (level, "%s\n", s);
361141cc406Sopenharmony_ci	  p = s;
362141cc406Sopenharmony_ci	}
363141cc406Sopenharmony_ci      a++;
364141cc406Sopenharmony_ci    }
365141cc406Sopenharmony_ci}
366141cc406Sopenharmony_ci
367141cc406Sopenharmony_ci/* ---------------------------------- PIE INIT ---------------------------------- */
368141cc406Sopenharmony_ci
369141cc406Sopenharmony_cistatic void
370141cc406Sopenharmony_cipie_init (Pie_Device * dev)	/* pie_init is called once while driver-initialization */
371141cc406Sopenharmony_ci{
372141cc406Sopenharmony_ci  DBG (DBG_proc, "init\n");
373141cc406Sopenharmony_ci
374141cc406Sopenharmony_ci  dev->cal_info_count = 0;
375141cc406Sopenharmony_ci  dev->cal_info = NULL;
376141cc406Sopenharmony_ci
377141cc406Sopenharmony_ci  dev->devicename = NULL;
378141cc406Sopenharmony_ci  dev->inquiry_len = 0;
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
381141cc406Sopenharmony_ci  DBG (DBG_info,
382141cc406Sopenharmony_ci       "variable scsi buffer size (usage of sanei_scsi_open_extended)\n");
383141cc406Sopenharmony_ci#else
384141cc406Sopenharmony_ci  DBG (DBG_info, "fixed scsi buffer size = %d bytes\n",
385141cc406Sopenharmony_ci       sanei_scsi_max_request_size);
386141cc406Sopenharmony_ci#endif
387141cc406Sopenharmony_ci}
388141cc406Sopenharmony_ci
389141cc406Sopenharmony_ci
390141cc406Sopenharmony_ci/* ---------------------------- SENSE_HANDLER ------------------------------ */
391141cc406Sopenharmony_ci
392141cc406Sopenharmony_ci
393141cc406Sopenharmony_cistatic SANE_Status
394141cc406Sopenharmony_cisense_handler (__sane_unused__ int scsi_fd, unsigned char *result, __sane_unused__ void *arg)	/* is called by sanei_scsi */
395141cc406Sopenharmony_ci{
396141cc406Sopenharmony_ci  unsigned char asc, ascq, sensekey;
397141cc406Sopenharmony_ci  int asc_ascq, len;
398141cc406Sopenharmony_ci  /* Pie_Device *dev = arg; */
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci  DBG (DBG_proc, "check condition sense handler\n");
401141cc406Sopenharmony_ci
402141cc406Sopenharmony_ci  sensekey = get_RS_sense_key (result);
403141cc406Sopenharmony_ci  asc = get_RS_ASC (result);
404141cc406Sopenharmony_ci  ascq = get_RS_ASCQ (result);
405141cc406Sopenharmony_ci  asc_ascq = (int) (256 * asc + ascq);
406141cc406Sopenharmony_ci  len = 7 + get_RS_additional_length (result);
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_ci  if (get_RS_error_code (result) != 0x70)
409141cc406Sopenharmony_ci    {
410141cc406Sopenharmony_ci      DBG (DBG_proc, "invalid sense key => handled as DEVICE BUSY!\n");
411141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;	/* sense key invalid */
412141cc406Sopenharmony_ci    }
413141cc406Sopenharmony_ci
414141cc406Sopenharmony_ci  DBG (DBG_sense, "check condition sense: %s\n", sense_str[sensekey]);
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci  if (get_RS_ILI (result) != 0)
417141cc406Sopenharmony_ci    {
418141cc406Sopenharmony_ci      DBG (DBG_sense,
419141cc406Sopenharmony_ci	   "-> ILI-ERROR: requested data length is larger than actual length\n");
420141cc406Sopenharmony_ci    }
421141cc406Sopenharmony_ci
422141cc406Sopenharmony_ci  switch (sensekey)
423141cc406Sopenharmony_ci    {
424141cc406Sopenharmony_ci    case 0x00:			/* no sense, could have been busy */
425141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
426141cc406Sopenharmony_ci      break;
427141cc406Sopenharmony_ci
428141cc406Sopenharmony_ci    case 0x02:
429141cc406Sopenharmony_ci      if (asc_ascq == 0x0401)
430141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Not Ready - Warming Up\n");
431141cc406Sopenharmony_ci      else if (asc_ascq == 0x0483)
432141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Not Ready - Need manual service\n");
433141cc406Sopenharmony_ci      else if (asc_ascq == 0x0881)
434141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Not Ready - Communication time out\n");
435141cc406Sopenharmony_ci      else
436141cc406Sopenharmony_ci	DBG (DBG_sense, "-> unknown medium error: asc=%d, ascq=%d\n", asc,
437141cc406Sopenharmony_ci	     ascq);
438141cc406Sopenharmony_ci      break;
439141cc406Sopenharmony_ci
440141cc406Sopenharmony_ci    case 0x03:			/* medium error */
441141cc406Sopenharmony_ci      if (asc_ascq == 0x5300)
442141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Media load or eject failure\n");
443141cc406Sopenharmony_ci      else if (asc_ascq == 0x3a00)
444141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Media not present\n");
445141cc406Sopenharmony_ci      else if (asc_ascq == 0x3b05)
446141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Paper jam\n");
447141cc406Sopenharmony_ci      else if (asc_ascq == 0x3a80)
448141cc406Sopenharmony_ci	DBG (DBG_sense, "-> ADF paper out\n");
449141cc406Sopenharmony_ci      else
450141cc406Sopenharmony_ci	DBG (DBG_sense, "-> unknown medium error: asc=%d, ascq=%d\n", asc,
451141cc406Sopenharmony_ci	     ascq);
452141cc406Sopenharmony_ci      break;
453141cc406Sopenharmony_ci
454141cc406Sopenharmony_ci
455141cc406Sopenharmony_ci    case 0x04:			/* hardware error */
456141cc406Sopenharmony_ci      if (asc_ascq == 0x4081)
457141cc406Sopenharmony_ci	DBG (DBG_sense, "-> CPU RAM failure\n");
458141cc406Sopenharmony_ci      else if (asc_ascq == 0x4082)
459141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Scanning system RAM failure\n");
460141cc406Sopenharmony_ci      else if (asc_ascq == 0x4083)
461141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Image buffer failure\n");
462141cc406Sopenharmony_ci      else if (asc_ascq == 0x0403)
463141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Manual intervention required\n");
464141cc406Sopenharmony_ci      else if (asc_ascq == 0x6200)
465141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Scan head position error\n");
466141cc406Sopenharmony_ci      else if (asc_ascq == 0x6000)
467141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Lamp or CCD failure\n");
468141cc406Sopenharmony_ci      else if (asc_ascq == 0x6081)
469141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Transparency lamp failure\n");
470141cc406Sopenharmony_ci      else if (asc_ascq == 0x8180)
471141cc406Sopenharmony_ci	DBG (DBG_sense, "-> DC offset or black level calibration failure\n");
472141cc406Sopenharmony_ci      else if (asc_ascq == 0x8181)
473141cc406Sopenharmony_ci	DBG (DBG_sense,
474141cc406Sopenharmony_ci	     "-> Integration time adjustment failure (too light)\n");
475141cc406Sopenharmony_ci      else if (asc_ascq == 0x8182)
476141cc406Sopenharmony_ci	DBG (DBG_sense,
477141cc406Sopenharmony_ci	     "-> Integration time adjustment failure (too dark)\n");
478141cc406Sopenharmony_ci      else if (asc_ascq == 0x8183)
479141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Shading curve adjustment failure\n");
480141cc406Sopenharmony_ci      else if (asc_ascq == 0x8184)
481141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Gain adjustment failure\n");
482141cc406Sopenharmony_ci      else if (asc_ascq == 0x8185)
483141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Optical alignment failure\n");
484141cc406Sopenharmony_ci      else if (asc_ascq == 0x8186)
485141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Optical locating failure\n");
486141cc406Sopenharmony_ci      else if (asc_ascq == 0x8187)
487141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Scan pixel map less than 5100 pixels!\n");
488141cc406Sopenharmony_ci      else if (asc_ascq == 0x4700)
489141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Parity error on SCSI bus\n");
490141cc406Sopenharmony_ci      else if (asc_ascq == 0x4b00)
491141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Data phase error\n");
492141cc406Sopenharmony_ci      else
493141cc406Sopenharmony_ci	DBG (DBG_sense, "-> unknown hardware error: asc=%d, ascq=%d\n", asc,
494141cc406Sopenharmony_ci	     ascq);
495141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
496141cc406Sopenharmony_ci      break;
497141cc406Sopenharmony_ci
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_ci    case 0x05:			/* illegal request */
500141cc406Sopenharmony_ci      if (asc_ascq == 0x1a00)
501141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Parameter list length error\n");
502141cc406Sopenharmony_ci      else if (asc_ascq == 0x2c01)
503141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Too many windows specified\n");
504141cc406Sopenharmony_ci      else if (asc_ascq == 0x2c02)
505141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Invalid combination of windows\n");
506141cc406Sopenharmony_ci      else if (asc_ascq == 0x2c81)
507141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Illegal scanning frame\n");
508141cc406Sopenharmony_ci      else if (asc_ascq == 0x2400)
509141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Invalid field in CDB\n");
510141cc406Sopenharmony_ci      else if (asc_ascq == 0x2481)
511141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Request too many lines of data\n");
512141cc406Sopenharmony_ci      else if (asc_ascq == 0x2000)
513141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Invalid command OP code\n");
514141cc406Sopenharmony_ci      else if (asc_ascq == 0x2501)
515141cc406Sopenharmony_ci	DBG (DBG_sense, "-> LUN not supported\n");
516141cc406Sopenharmony_ci      else if (asc_ascq == 0x2601)
517141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Parameter not supported\n");
518141cc406Sopenharmony_ci      else if (asc_ascq == 0x2602)
519141cc406Sopenharmony_ci	DBG (DBG_sense,
520141cc406Sopenharmony_ci	     "-> Parameter value invalid - Parameter not specified\n");
521141cc406Sopenharmony_ci      else if (asc_ascq == 0x2603)
522141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Parameter value invalid - Invalid threshold\n");
523141cc406Sopenharmony_ci      else if (asc_ascq == 0x2680)
524141cc406Sopenharmony_ci	DBG (DBG_sense,
525141cc406Sopenharmony_ci	     "-> Parameter value invalid - Control command sequence error\n");
526141cc406Sopenharmony_ci      else if (asc_ascq == 0x2681)
527141cc406Sopenharmony_ci	DBG (DBG_sense,
528141cc406Sopenharmony_ci	     "-> Parameter value invalid - Grain setting (halftone pattern\n");
529141cc406Sopenharmony_ci      else if (asc_ascq == 0x2682)
530141cc406Sopenharmony_ci	DBG (DBG_sense,
531141cc406Sopenharmony_ci	     "-> Parameter value invalid - Illegal resolution setting\n");
532141cc406Sopenharmony_ci      else if (asc_ascq == 0x2683)
533141cc406Sopenharmony_ci	DBG (DBG_sense,
534141cc406Sopenharmony_ci	     "-> Parameter value invalid - Invalid filter assignment\n");
535141cc406Sopenharmony_ci      else if (asc_ascq == 0x2684)
536141cc406Sopenharmony_ci	DBG (DBG_sense,
537141cc406Sopenharmony_ci	     "-> Parameter value invalid - Illegal gamma adjustment setting (look-up table)\n");
538141cc406Sopenharmony_ci      else if (asc_ascq == 0x2685)
539141cc406Sopenharmony_ci	DBG (DBG_sense,
540141cc406Sopenharmony_ci	     "-> Parameter value invalid - Illegal offset setting (digital brightness)\n");
541141cc406Sopenharmony_ci      else if (asc_ascq == 0x2686)
542141cc406Sopenharmony_ci	DBG (DBG_sense,
543141cc406Sopenharmony_ci	     "-> Parameter value invalid - Illegal bits per pixel setting\n");
544141cc406Sopenharmony_ci      else if (asc_ascq == 0x2687)
545141cc406Sopenharmony_ci	DBG (DBG_sense,
546141cc406Sopenharmony_ci	     "-> Parameter value invalid - Illegal contrast setting\n");
547141cc406Sopenharmony_ci      else if (asc_ascq == 0x2688)
548141cc406Sopenharmony_ci	DBG (DBG_sense,
549141cc406Sopenharmony_ci	     "-> Parameter value invalid - Illegal paper length setting\n");
550141cc406Sopenharmony_ci      else if (asc_ascq == 0x2689)
551141cc406Sopenharmony_ci	DBG (DBG_sense,
552141cc406Sopenharmony_ci	     "-> Parameter value invalid - Illegal highlight/shadow setting\n");
553141cc406Sopenharmony_ci      else if (asc_ascq == 0x268a)
554141cc406Sopenharmony_ci	DBG (DBG_sense,
555141cc406Sopenharmony_ci	     "-> Parameter value invalid - Illegal exposure time setting (analog brightness)\n");
556141cc406Sopenharmony_ci      else if (asc_ascq == 0x268b)
557141cc406Sopenharmony_ci	DBG (DBG_sense,
558141cc406Sopenharmony_ci	     "-> Parameter value invalid - Invalid device select or device not exist\n");
559141cc406Sopenharmony_ci      else if (asc_ascq == 0x268c)
560141cc406Sopenharmony_ci	DBG (DBG_sense,
561141cc406Sopenharmony_ci	     "-> Parameter value invalid - Illegal color packing\n");
562141cc406Sopenharmony_ci      else if (asc_ascq == 0x3d00)
563141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Invalid bits in identify field\n");
564141cc406Sopenharmony_ci
565141cc406Sopenharmony_ci
566141cc406Sopenharmony_ci
567141cc406Sopenharmony_ci      else if (asc_ascq == 0x4900)
568141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Invalid message\n");
569141cc406Sopenharmony_ci      else if (asc_ascq == 0x8101)
570141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Not enough memory for color packing\n");
571141cc406Sopenharmony_ci
572141cc406Sopenharmony_ci      if (len >= 0x11)
573141cc406Sopenharmony_ci	{
574141cc406Sopenharmony_ci	  if (get_RS_SKSV (result) != 0)
575141cc406Sopenharmony_ci	    {
576141cc406Sopenharmony_ci	      if (get_RS_CD (result) == 0)
577141cc406Sopenharmony_ci		{
578141cc406Sopenharmony_ci
579141cc406Sopenharmony_ci		  DBG (DBG_sense, "-> illegal parameter in CDB\n");
580141cc406Sopenharmony_ci		}
581141cc406Sopenharmony_ci	      else
582141cc406Sopenharmony_ci		{
583141cc406Sopenharmony_ci		  DBG (DBG_sense,
584141cc406Sopenharmony_ci		       "-> illegal parameter is in the data parameters sent during data out phase\n");
585141cc406Sopenharmony_ci		}
586141cc406Sopenharmony_ci
587141cc406Sopenharmony_ci	      DBG (DBG_sense, "-> error detected in byte %d\n",
588141cc406Sopenharmony_ci		   get_RS_field_pointer (result));
589141cc406Sopenharmony_ci	    }
590141cc406Sopenharmony_ci	}
591141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
592141cc406Sopenharmony_ci      break;
593141cc406Sopenharmony_ci
594141cc406Sopenharmony_ci
595141cc406Sopenharmony_ci    case 0x06:			/* unit attention */
596141cc406Sopenharmony_ci      if (asc_ascq == 0x2900)
597141cc406Sopenharmony_ci	DBG (DBG_sense, "-> power on, reset or bus device reset\n");
598141cc406Sopenharmony_ci      if (asc_ascq == 0x8200)
599141cc406Sopenharmony_ci	DBG (DBG_sense,
600141cc406Sopenharmony_ci	     "-> unit attention - calibration disable not granted\n");
601141cc406Sopenharmony_ci      if (asc_ascq == 0x8300)
602141cc406Sopenharmony_ci	DBG (DBG_sense, "-> unit attention - calibration will be ignored\n");
603141cc406Sopenharmony_ci      else
604141cc406Sopenharmony_ci	DBG (DBG_sense, "-> unit attention: asc=%d, ascq=%d\n", asc, ascq);
605141cc406Sopenharmony_ci      break;
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci
608141cc406Sopenharmony_ci    case 0x09:			/* vendor specific */
609141cc406Sopenharmony_ci      DBG (DBG_sense, "-> vendor specific sense-code: asc=%d, ascq=%d\n", asc,
610141cc406Sopenharmony_ci	   ascq);
611141cc406Sopenharmony_ci      break;
612141cc406Sopenharmony_ci
613141cc406Sopenharmony_ci    case 0x0b:
614141cc406Sopenharmony_ci      if (asc_ascq == 0x0006)
615141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Received ABORT message from initiator\n");
616141cc406Sopenharmony_ci      if (asc_ascq == 0x4800)
617141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Initiator detected error message received\n");
618141cc406Sopenharmony_ci      if (asc_ascq == 0x4300)
619141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Message error\n");
620141cc406Sopenharmony_ci      if (asc_ascq == 0x4500)
621141cc406Sopenharmony_ci	DBG (DBG_sense, "-> Select or re-select error\n");
622141cc406Sopenharmony_ci      else
623141cc406Sopenharmony_ci	DBG (DBG_sense, "-> aborted command: asc=%d, ascq=%d\n", asc, ascq);
624141cc406Sopenharmony_ci      break;
625141cc406Sopenharmony_ci
626141cc406Sopenharmony_ci    }
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
629141cc406Sopenharmony_ci}
630141cc406Sopenharmony_ci
631141cc406Sopenharmony_ci
632141cc406Sopenharmony_ci/* -------------------------------- PIE PRINT INQUIRY ------------------------- */
633141cc406Sopenharmony_ci
634141cc406Sopenharmony_ci
635141cc406Sopenharmony_cistatic void
636141cc406Sopenharmony_cipie_print_inquiry (Pie_Device * dev)
637141cc406Sopenharmony_ci{
638141cc406Sopenharmony_ci  DBG (DBG_inquiry, "INQUIRY:\n");
639141cc406Sopenharmony_ci  DBG (DBG_inquiry, "========\n");
640141cc406Sopenharmony_ci  DBG (DBG_inquiry, "\n");
641141cc406Sopenharmony_ci  DBG (DBG_inquiry, "vendor........................: '%s'\n", dev->vendor);
642141cc406Sopenharmony_ci  DBG (DBG_inquiry, "product.......................: '%s'\n", dev->product);
643141cc406Sopenharmony_ci  DBG (DBG_inquiry, "version.......................: '%s'\n", dev->version);
644141cc406Sopenharmony_ci
645141cc406Sopenharmony_ci  DBG (DBG_inquiry, "X resolution..................: %d dpi\n",
646141cc406Sopenharmony_ci       dev->inquiry_x_res);
647141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Y resolution..................: %d dpi\n",
648141cc406Sopenharmony_ci       dev->inquiry_y_res);
649141cc406Sopenharmony_ci  DBG (DBG_inquiry, "pixel resolution..............: %d dpi\n",
650141cc406Sopenharmony_ci       dev->inquiry_pixel_resolution);
651141cc406Sopenharmony_ci  DBG (DBG_inquiry, "fb width......................: %f in\n",
652141cc406Sopenharmony_ci       dev->inquiry_fb_width);
653141cc406Sopenharmony_ci  DBG (DBG_inquiry, "fb length.....................: %f in\n",
654141cc406Sopenharmony_ci       dev->inquiry_fb_length);
655141cc406Sopenharmony_ci
656141cc406Sopenharmony_ci  DBG (DBG_inquiry, "transparency width............: %f in\n",
657141cc406Sopenharmony_ci       dev->inquiry_trans_width);
658141cc406Sopenharmony_ci  DBG (DBG_inquiry, "transparency length...........: %f in\n",
659141cc406Sopenharmony_ci       dev->inquiry_trans_length);
660141cc406Sopenharmony_ci  DBG (DBG_inquiry, "transparency offset...........: %d,%d\n",
661141cc406Sopenharmony_ci       dev->inquiry_trans_top_left_x, dev->inquiry_trans_top_left_y);
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci  DBG (DBG_inquiry, "# of halftones................: %d\n",
664141cc406Sopenharmony_ci       dev->inquiry_halftones);
665141cc406Sopenharmony_ci
666141cc406Sopenharmony_ci  DBG (DBG_inquiry, "One pass color................: %s\n",
667141cc406Sopenharmony_ci       dev->inquiry_filters & INQ_ONE_PASS_COLOR ? "yes" : "no");
668141cc406Sopenharmony_ci
669141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Filters.......................: %s%s%s%s (%02x)\n",
670141cc406Sopenharmony_ci       dev->inquiry_filters & INQ_FILTER_RED ? "Red " : "",
671141cc406Sopenharmony_ci       dev->inquiry_filters & INQ_FILTER_GREEN ? "Green " : "",
672141cc406Sopenharmony_ci       dev->inquiry_filters & INQ_FILTER_BLUE ? "Blue " : "",
673141cc406Sopenharmony_ci       dev->inquiry_filters & INQ_FILTER_NEUTRAL ? "Neutral " : "",
674141cc406Sopenharmony_ci       dev->inquiry_filters);
675141cc406Sopenharmony_ci
676141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Color depths..................: %s%s%s%s%s%s (%02x)\n",
677141cc406Sopenharmony_ci       dev->inquiry_color_depths & INQ_COLOR_DEPTH_16 ? "16 bit " : "",
678141cc406Sopenharmony_ci       dev->inquiry_color_depths & INQ_COLOR_DEPTH_12 ? "12 bit " : "",
679141cc406Sopenharmony_ci       dev->inquiry_color_depths & INQ_COLOR_DEPTH_10 ? "10 bit " : "",
680141cc406Sopenharmony_ci       dev->inquiry_color_depths & INQ_COLOR_DEPTH_8 ? "8 bit " : "",
681141cc406Sopenharmony_ci       dev->inquiry_color_depths & INQ_COLOR_DEPTH_4 ? "4 bit " : "",
682141cc406Sopenharmony_ci       dev->inquiry_color_depths & INQ_COLOR_DEPTH_1 ? "1 bit " : "",
683141cc406Sopenharmony_ci       dev->inquiry_color_depths);
684141cc406Sopenharmony_ci
685141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Color Format..................: %s%s%s (%02x)\n",
686141cc406Sopenharmony_ci       dev->inquiry_color_format & INQ_COLOR_FORMAT_INDEX ? "Indexed " : "",
687141cc406Sopenharmony_ci       dev->inquiry_color_format & INQ_COLOR_FORMAT_LINE ? "Line " : "",
688141cc406Sopenharmony_ci       dev->inquiry_color_format & INQ_COLOR_FORMAT_PIXEL ? "Pixel " : "",
689141cc406Sopenharmony_ci       dev->inquiry_color_format);
690141cc406Sopenharmony_ci
691141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Image Format..................: %s%s%s%s (%02x)\n",
692141cc406Sopenharmony_ci       dev->inquiry_image_format & INQ_IMG_FMT_OKLINE ? "OKLine " : "",
693141cc406Sopenharmony_ci       dev->inquiry_image_format & INQ_IMG_FMT_BLK_ONE ? "BlackOne " : "",
694141cc406Sopenharmony_ci       dev->inquiry_image_format & INQ_IMG_FMT_MOTOROLA ? "Motorola " : "",
695141cc406Sopenharmony_ci       dev->inquiry_image_format & INQ_IMG_FMT_INTEL ? "Intel" : "",
696141cc406Sopenharmony_ci       dev->inquiry_image_format);
697141cc406Sopenharmony_ci
698141cc406Sopenharmony_ci  DBG (DBG_inquiry,
699141cc406Sopenharmony_ci       "Scan Capability...............: %s%s%s%s%d speeds (%02x)\n",
700141cc406Sopenharmony_ci       dev->inquiry_scan_capability & INQ_CAP_PWRSAV ? "PowerSave " : "",
701141cc406Sopenharmony_ci       dev->inquiry_scan_capability & INQ_CAP_EXT_CAL ? "ExtCal " : "",
702141cc406Sopenharmony_ci       dev->inquiry_scan_capability & INQ_CAP_FAST_PREVIEW ? "FastPreview" :
703141cc406Sopenharmony_ci       "",
704141cc406Sopenharmony_ci       dev->inquiry_scan_capability & INQ_CAP_DISABLE_CAL ? "DisCal " : "",
705141cc406Sopenharmony_ci       dev->inquiry_scan_capability & INQ_CAP_SPEEDS,
706141cc406Sopenharmony_ci       dev->inquiry_scan_capability);
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Optional Devices..............: %s%s%s%s (%02x)\n",
709141cc406Sopenharmony_ci       dev->inquiry_optional_devices & INQ_OPT_DEV_MPCL ? "MultiPageLoad " :
710141cc406Sopenharmony_ci       "",
711141cc406Sopenharmony_ci       dev->inquiry_optional_devices & INQ_OPT_DEV_TP1 ? "TransModule1 " : "",
712141cc406Sopenharmony_ci       dev->inquiry_optional_devices & INQ_OPT_DEV_TP ? "TransModule " : "",
713141cc406Sopenharmony_ci       dev->inquiry_optional_devices & INQ_OPT_DEV_ADF ? "ADF " : "",
714141cc406Sopenharmony_ci       dev->inquiry_optional_devices);
715141cc406Sopenharmony_ci
716141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Enhancement...................: %02x\n",
717141cc406Sopenharmony_ci       dev->inquiry_enhancements);
718141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Gamma bits....................: %d\n",
719141cc406Sopenharmony_ci       dev->inquiry_gamma_bits);
720141cc406Sopenharmony_ci
721141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Fast Preview Resolution.......: %d\n",
722141cc406Sopenharmony_ci       dev->inquiry_fast_preview_res);
723141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Min Highlight.................: %d\n",
724141cc406Sopenharmony_ci       dev->inquiry_min_highlight);
725141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Max Shadow....................: %d\n",
726141cc406Sopenharmony_ci       dev->inquiry_max_shadow);
727141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Cal Eqn.......................: %d\n",
728141cc406Sopenharmony_ci       dev->inquiry_cal_eqn);
729141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Min Exposure..................: %d\n",
730141cc406Sopenharmony_ci       dev->inquiry_min_exp);
731141cc406Sopenharmony_ci  DBG (DBG_inquiry, "Max Exposure..................: %d\n",
732141cc406Sopenharmony_ci       dev->inquiry_max_exp);
733141cc406Sopenharmony_ci}
734141cc406Sopenharmony_ci
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci/* ------------------------------ PIE GET INQUIRY VALUES -------------------- */
737141cc406Sopenharmony_ci
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_cistatic void
740141cc406Sopenharmony_cipie_get_inquiry_values (Pie_Device * dev, unsigned char *buffer)
741141cc406Sopenharmony_ci{
742141cc406Sopenharmony_ci  DBG (DBG_proc, "get_inquiry_values\n");
743141cc406Sopenharmony_ci
744141cc406Sopenharmony_ci  dev->inquiry_len = get_inquiry_additional_length (buffer) + 5;
745141cc406Sopenharmony_ci
746141cc406Sopenharmony_ci  get_inquiry_vendor ((char *) buffer, dev->vendor);
747141cc406Sopenharmony_ci  get_inquiry_product ((char *) buffer, dev->product);
748141cc406Sopenharmony_ci  get_inquiry_version ((char *) buffer, dev->version);
749141cc406Sopenharmony_ci
750141cc406Sopenharmony_ci  dev->inquiry_x_res = get_inquiry_max_x_res (buffer);
751141cc406Sopenharmony_ci  dev->inquiry_y_res = get_inquiry_max_y_res (buffer);
752141cc406Sopenharmony_ci
753141cc406Sopenharmony_ci  if (dev->inquiry_y_res < 256)
754141cc406Sopenharmony_ci    {
755141cc406Sopenharmony_ci      /* y res is a multiplier */
756141cc406Sopenharmony_ci      dev->inquiry_pixel_resolution = dev->inquiry_x_res;
757141cc406Sopenharmony_ci      dev->inquiry_x_res *= dev->inquiry_y_res;
758141cc406Sopenharmony_ci      dev->inquiry_y_res = dev->inquiry_x_res;
759141cc406Sopenharmony_ci    }
760141cc406Sopenharmony_ci  else
761141cc406Sopenharmony_ci    {
762141cc406Sopenharmony_ci      /* y res really is resolution */
763141cc406Sopenharmony_ci      dev->inquiry_pixel_resolution =
764141cc406Sopenharmony_ci	min (dev->inquiry_x_res, dev->inquiry_y_res);
765141cc406Sopenharmony_ci    }
766141cc406Sopenharmony_ci
767141cc406Sopenharmony_ci  dev->inquiry_fb_width =
768141cc406Sopenharmony_ci    (double) get_inquiry_fb_max_scan_width (buffer) /
769141cc406Sopenharmony_ci    dev->inquiry_pixel_resolution;
770141cc406Sopenharmony_ci  dev->inquiry_fb_length =
771141cc406Sopenharmony_ci    (double) get_inquiry_fb_max_scan_length (buffer) /
772141cc406Sopenharmony_ci    dev->inquiry_pixel_resolution;
773141cc406Sopenharmony_ci
774141cc406Sopenharmony_ci  dev->inquiry_trans_top_left_x = get_inquiry_trans_x1 (buffer);
775141cc406Sopenharmony_ci  dev->inquiry_trans_top_left_y = get_inquiry_trans_y1 (buffer);
776141cc406Sopenharmony_ci
777141cc406Sopenharmony_ci  dev->inquiry_trans_width =
778141cc406Sopenharmony_ci    (double) (get_inquiry_trans_x2 (buffer) -
779141cc406Sopenharmony_ci	      get_inquiry_trans_x1 (buffer)) / dev->inquiry_pixel_resolution;
780141cc406Sopenharmony_ci  dev->inquiry_trans_length =
781141cc406Sopenharmony_ci    (double) (get_inquiry_trans_y2 (buffer) -
782141cc406Sopenharmony_ci	      get_inquiry_trans_y1 (buffer)) / dev->inquiry_pixel_resolution;
783141cc406Sopenharmony_ci
784141cc406Sopenharmony_ci  dev->inquiry_halftones = get_inquiry_halftones (buffer) & 0x0f;
785141cc406Sopenharmony_ci
786141cc406Sopenharmony_ci  dev->inquiry_filters = get_inquiry_filters (buffer);
787141cc406Sopenharmony_ci  dev->inquiry_color_depths = get_inquiry_color_depths (buffer);
788141cc406Sopenharmony_ci  dev->inquiry_color_format = get_inquiry_color_format (buffer);
789141cc406Sopenharmony_ci  dev->inquiry_image_format = get_inquiry_image_format (buffer);
790141cc406Sopenharmony_ci
791141cc406Sopenharmony_ci  dev->inquiry_scan_capability = get_inquiry_scan_capability (buffer);
792141cc406Sopenharmony_ci  dev->inquiry_optional_devices = get_inquiry_optional_devices (buffer);
793141cc406Sopenharmony_ci  dev->inquiry_enhancements = get_inquiry_enhancements (buffer);
794141cc406Sopenharmony_ci  dev->inquiry_gamma_bits = get_inquiry_gamma_bits (buffer);
795141cc406Sopenharmony_ci  dev->inquiry_fast_preview_res = get_inquiry_fast_preview_res (buffer);
796141cc406Sopenharmony_ci  dev->inquiry_min_highlight = get_inquiry_min_highlight (buffer);
797141cc406Sopenharmony_ci  dev->inquiry_max_shadow = get_inquiry_max_shadow (buffer);
798141cc406Sopenharmony_ci  dev->inquiry_cal_eqn = get_inquiry_cal_eqn (buffer);
799141cc406Sopenharmony_ci  dev->inquiry_min_exp = get_inquiry_min_exp (buffer);
800141cc406Sopenharmony_ci  dev->inquiry_max_exp = get_inquiry_max_exp (buffer);
801141cc406Sopenharmony_ci
802141cc406Sopenharmony_ci  pie_print_inquiry (dev);
803141cc406Sopenharmony_ci
804141cc406Sopenharmony_ci  return;
805141cc406Sopenharmony_ci}
806141cc406Sopenharmony_ci
807141cc406Sopenharmony_ci/* ----------------------------- PIE DO INQUIRY ---------------------------- */
808141cc406Sopenharmony_ci
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_cistatic void
811141cc406Sopenharmony_cipie_do_inquiry (int sfd, unsigned char *buffer)
812141cc406Sopenharmony_ci{
813141cc406Sopenharmony_ci  size_t size;
814141cc406Sopenharmony_ci  SANE_Status status;
815141cc406Sopenharmony_ci
816141cc406Sopenharmony_ci  DBG (DBG_proc, "do_inquiry\n");
817141cc406Sopenharmony_ci  memset (buffer, '\0', 256);	/* clear buffer */
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_ci  size = 5;
820141cc406Sopenharmony_ci
821141cc406Sopenharmony_ci  set_inquiry_return_size (inquiry.cmd, size);	/* first get only 5 bytes to get size of inquiry_return_block */
822141cc406Sopenharmony_ci  status = sanei_scsi_cmd (sfd, inquiry.cmd, inquiry.size, buffer, &size);
823141cc406Sopenharmony_ci  if (status)
824141cc406Sopenharmony_ci    {
825141cc406Sopenharmony_ci      DBG (DBG_error, "pie_do_inquiry: command returned status %s\n",
826141cc406Sopenharmony_ci	   sane_strstatus (status));
827141cc406Sopenharmony_ci    }
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci  size = get_inquiry_additional_length (buffer) + 5;
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci  set_inquiry_return_size (inquiry.cmd, size);	/* then get inquiry with actual size */
832141cc406Sopenharmony_ci  status = sanei_scsi_cmd (sfd, inquiry.cmd, inquiry.size, buffer, &size);
833141cc406Sopenharmony_ci  if (status)
834141cc406Sopenharmony_ci    {
835141cc406Sopenharmony_ci      DBG (DBG_error, "pie_do_inquiry: command returned status %s\n",
836141cc406Sopenharmony_ci	   sane_strstatus (status));
837141cc406Sopenharmony_ci    }
838141cc406Sopenharmony_ci}
839141cc406Sopenharmony_ci
840141cc406Sopenharmony_ci/* ---------------------- PIE IDENTIFY SCANNER ---------------------- */
841141cc406Sopenharmony_ci
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_cistatic int
844141cc406Sopenharmony_cipie_identify_scanner (Pie_Device * dev, int sfd)
845141cc406Sopenharmony_ci{
846141cc406Sopenharmony_ci  char vendor[9];
847141cc406Sopenharmony_ci  char product[0x11];
848141cc406Sopenharmony_ci  char version[5];
849141cc406Sopenharmony_ci  char *pp;
850141cc406Sopenharmony_ci  int i = 0;
851141cc406Sopenharmony_ci  unsigned char inquiry_block[256];
852141cc406Sopenharmony_ci
853141cc406Sopenharmony_ci  DBG (DBG_proc, "identify_scanner\n");
854141cc406Sopenharmony_ci
855141cc406Sopenharmony_ci  pie_do_inquiry (sfd, inquiry_block);	/* get inquiry */
856141cc406Sopenharmony_ci
857141cc406Sopenharmony_ci  if (get_inquiry_periph_devtype (inquiry_block) != IN_periph_devtype_scanner)
858141cc406Sopenharmony_ci    {
859141cc406Sopenharmony_ci      return 1;
860141cc406Sopenharmony_ci    }				/* no scanner */
861141cc406Sopenharmony_ci
862141cc406Sopenharmony_ci  get_inquiry_vendor ((char *) inquiry_block, vendor);
863141cc406Sopenharmony_ci  get_inquiry_product ((char *) inquiry_block, product);
864141cc406Sopenharmony_ci  get_inquiry_version ((char *) inquiry_block, version);
865141cc406Sopenharmony_ci
866141cc406Sopenharmony_ci  pp = &vendor[8];
867141cc406Sopenharmony_ci  vendor[8] = ' ';
868141cc406Sopenharmony_ci  while (*pp == ' ')
869141cc406Sopenharmony_ci    {
870141cc406Sopenharmony_ci      *pp-- = '\0';
871141cc406Sopenharmony_ci    }
872141cc406Sopenharmony_ci
873141cc406Sopenharmony_ci  pp = &product[0x10];
874141cc406Sopenharmony_ci  product[0x10] = ' ';
875141cc406Sopenharmony_ci  while (*pp == ' ')
876141cc406Sopenharmony_ci    {
877141cc406Sopenharmony_ci      *pp-- = '\0';
878141cc406Sopenharmony_ci    }
879141cc406Sopenharmony_ci
880141cc406Sopenharmony_ci  pp = &version[4];
881141cc406Sopenharmony_ci
882141cc406Sopenharmony_ci  version[4] = ' ';
883141cc406Sopenharmony_ci  while (*pp == ' ')
884141cc406Sopenharmony_ci    {
885141cc406Sopenharmony_ci      *pp-- = '\0';
886141cc406Sopenharmony_ci    }
887141cc406Sopenharmony_ci
888141cc406Sopenharmony_ci  DBG (DBG_info, "Found %s scanner %s version %s on device %s\n", vendor,
889141cc406Sopenharmony_ci       product, version, dev->devicename);
890141cc406Sopenharmony_ci
891141cc406Sopenharmony_ci  while (strncmp ("END_OF_LIST", scanner_str[2 * i], 11) != 0)	/* Now identify full supported scanners */
892141cc406Sopenharmony_ci    {
893141cc406Sopenharmony_ci      if (!strncmp (vendor, scanner_str[2 * i], strlen (scanner_str[2 * i])))
894141cc406Sopenharmony_ci	{
895141cc406Sopenharmony_ci	  if (!strncmp
896141cc406Sopenharmony_ci	      (product, scanner_str[2 * i + 1],
897141cc406Sopenharmony_ci	       strlen (scanner_str[2 * i + 1])))
898141cc406Sopenharmony_ci	    {
899141cc406Sopenharmony_ci	      DBG (DBG_info, "found supported scanner\n");
900141cc406Sopenharmony_ci
901141cc406Sopenharmony_ci	      pie_get_inquiry_values (dev, inquiry_block);
902141cc406Sopenharmony_ci	      return 0;
903141cc406Sopenharmony_ci	    }
904141cc406Sopenharmony_ci	}
905141cc406Sopenharmony_ci      i++;
906141cc406Sopenharmony_ci    }
907141cc406Sopenharmony_ci
908141cc406Sopenharmony_ci  return 1;			/* NO SUPPORTED SCANNER: short inquiry-block and unknown scanner */
909141cc406Sopenharmony_ci}
910141cc406Sopenharmony_ci
911141cc406Sopenharmony_ci
912141cc406Sopenharmony_ci/* ------------------------------- GET SPEEDS ----------------------------- */
913141cc406Sopenharmony_ci
914141cc406Sopenharmony_cistatic void
915141cc406Sopenharmony_cipie_get_speeds (Pie_Device * dev)
916141cc406Sopenharmony_ci{
917141cc406Sopenharmony_ci  int speeds = dev->inquiry_scan_capability & INQ_CAP_SPEEDS;
918141cc406Sopenharmony_ci
919141cc406Sopenharmony_ci  DBG (DBG_proc, "get_speeds\n");
920141cc406Sopenharmony_ci
921141cc406Sopenharmony_ci  if (speeds == 3)
922141cc406Sopenharmony_ci    {
923141cc406Sopenharmony_ci      dev->speed_list[0] = strdup ("Normal");
924141cc406Sopenharmony_ci      dev->speed_list[1] = strdup ("Fine");
925141cc406Sopenharmony_ci      dev->speed_list[2] = strdup ("Pro");
926141cc406Sopenharmony_ci      dev->speed_list[3] = NULL;
927141cc406Sopenharmony_ci    }
928141cc406Sopenharmony_ci  else
929141cc406Sopenharmony_ci    {
930141cc406Sopenharmony_ci      int i;
931141cc406Sopenharmony_ci      char buf[2];
932141cc406Sopenharmony_ci
933141cc406Sopenharmony_ci      buf[1] = '\0';
934141cc406Sopenharmony_ci
935141cc406Sopenharmony_ci      for (i = 0; i < speeds; i++)
936141cc406Sopenharmony_ci	{
937141cc406Sopenharmony_ci	  buf[0] = '1' + i;
938141cc406Sopenharmony_ci	  dev->speed_list[i] = strdup (buf);
939141cc406Sopenharmony_ci	}
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_ci      dev->speed_list[i] = NULL;
942141cc406Sopenharmony_ci    }
943141cc406Sopenharmony_ci}
944141cc406Sopenharmony_ci
945141cc406Sopenharmony_ci/* ------------------------------- GET HALFTONES ----------------------------- */
946141cc406Sopenharmony_ci
947141cc406Sopenharmony_cistatic void
948141cc406Sopenharmony_cipie_get_halftones (Pie_Device * dev, int sfd)
949141cc406Sopenharmony_ci{
950141cc406Sopenharmony_ci  int i;
951141cc406Sopenharmony_ci  size_t size;
952141cc406Sopenharmony_ci  SANE_Status status;
953141cc406Sopenharmony_ci  unsigned char *data;
954141cc406Sopenharmony_ci  unsigned char buffer[128];
955141cc406Sopenharmony_ci
956141cc406Sopenharmony_ci  DBG (DBG_proc, "get_halftones\n");
957141cc406Sopenharmony_ci
958141cc406Sopenharmony_ci  for (i = 0; i < dev->inquiry_halftones; i++)
959141cc406Sopenharmony_ci    {
960141cc406Sopenharmony_ci      size = 6;
961141cc406Sopenharmony_ci
962141cc406Sopenharmony_ci      set_write_length (swrite.cmd, size);
963141cc406Sopenharmony_ci
964141cc406Sopenharmony_ci      memcpy (buffer, swrite.cmd, swrite.size);
965141cc406Sopenharmony_ci
966141cc406Sopenharmony_ci      data = buffer + swrite.size;
967141cc406Sopenharmony_ci      memset (data, 0, size);
968141cc406Sopenharmony_ci
969141cc406Sopenharmony_ci      set_command (data, READ_HALFTONE);
970141cc406Sopenharmony_ci      set_data_length (data, 2);
971141cc406Sopenharmony_ci      data[4] = i;
972141cc406Sopenharmony_ci
973141cc406Sopenharmony_ci      status = sanei_scsi_cmd (sfd, buffer, swrite.size + size, NULL, NULL);
974141cc406Sopenharmony_ci      if (status)
975141cc406Sopenharmony_ci	{
976141cc406Sopenharmony_ci	  DBG (DBG_error,
977141cc406Sopenharmony_ci	       "pie_get_halftones: write command returned status %s\n",
978141cc406Sopenharmony_ci	       sane_strstatus (status));
979141cc406Sopenharmony_ci	}
980141cc406Sopenharmony_ci      else
981141cc406Sopenharmony_ci	{
982141cc406Sopenharmony_ci	  /* now read the halftone data */
983141cc406Sopenharmony_ci	  memset (buffer, '\0', sizeof buffer);	/* clear buffer */
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci	  size = 128;
986141cc406Sopenharmony_ci	  set_read_length (sread.cmd, size);
987141cc406Sopenharmony_ci
988141cc406Sopenharmony_ci	  DBG (DBG_info, "doing read\n");
989141cc406Sopenharmony_ci	  status = sanei_scsi_cmd (sfd, sread.cmd, sread.size, buffer, &size);
990141cc406Sopenharmony_ci	  if (status)
991141cc406Sopenharmony_ci	    {
992141cc406Sopenharmony_ci	      DBG (DBG_error,
993141cc406Sopenharmony_ci		   "pie_get_halftones: read command returned status %s\n",
994141cc406Sopenharmony_ci		   sane_strstatus (status));
995141cc406Sopenharmony_ci	    }
996141cc406Sopenharmony_ci	  else
997141cc406Sopenharmony_ci	    {
998141cc406Sopenharmony_ci	      unsigned char *s;
999141cc406Sopenharmony_ci
1000141cc406Sopenharmony_ci	      s = buffer + 8 + buffer[6] * buffer[7];
1001141cc406Sopenharmony_ci
1002141cc406Sopenharmony_ci	      DBG (DBG_info, "halftone %d: %s\n", i, s);
1003141cc406Sopenharmony_ci
1004141cc406Sopenharmony_ci	      dev->halftone_list[i] = strdup ((char *)s);
1005141cc406Sopenharmony_ci	    }
1006141cc406Sopenharmony_ci	}
1007141cc406Sopenharmony_ci    }
1008141cc406Sopenharmony_ci  dev->halftone_list[i] = NULL;
1009141cc406Sopenharmony_ci}
1010141cc406Sopenharmony_ci
1011141cc406Sopenharmony_ci/* ------------------------------- GET CAL DATA ----------------------------- */
1012141cc406Sopenharmony_ci
1013141cc406Sopenharmony_cistatic void
1014141cc406Sopenharmony_cipie_get_cal_info (Pie_Device * dev, int sfd)
1015141cc406Sopenharmony_ci{
1016141cc406Sopenharmony_ci  size_t size;
1017141cc406Sopenharmony_ci  SANE_Status status;
1018141cc406Sopenharmony_ci  unsigned char *data;
1019141cc406Sopenharmony_ci  unsigned char buffer[280];
1020141cc406Sopenharmony_ci
1021141cc406Sopenharmony_ci  DBG (DBG_proc, "get_cal_info\n");
1022141cc406Sopenharmony_ci
1023141cc406Sopenharmony_ci  if (!(dev->inquiry_scan_capability & INQ_CAP_EXT_CAL))
1024141cc406Sopenharmony_ci    return;
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci  size = 6;
1027141cc406Sopenharmony_ci
1028141cc406Sopenharmony_ci  set_write_length (swrite.cmd, size);
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ci  memcpy (buffer, swrite.cmd, swrite.size);
1031141cc406Sopenharmony_ci
1032141cc406Sopenharmony_ci  data = buffer + swrite.size;
1033141cc406Sopenharmony_ci  memset (data, 0, size);
1034141cc406Sopenharmony_ci
1035141cc406Sopenharmony_ci  set_command (data, READ_CAL_INFO);
1036141cc406Sopenharmony_ci
1037141cc406Sopenharmony_ci  status = sanei_scsi_cmd (sfd, buffer, swrite.size + size, NULL, NULL);
1038141cc406Sopenharmony_ci  if (status)
1039141cc406Sopenharmony_ci    {
1040141cc406Sopenharmony_ci      DBG (DBG_error, "pie_get_cal_info: write command returned status %s\n",
1041141cc406Sopenharmony_ci	   sane_strstatus (status));
1042141cc406Sopenharmony_ci    }
1043141cc406Sopenharmony_ci  else
1044141cc406Sopenharmony_ci    {
1045141cc406Sopenharmony_ci      /* now read the cal data */
1046141cc406Sopenharmony_ci      memset (buffer, '\0', sizeof buffer);	/* clear buffer */
1047141cc406Sopenharmony_ci
1048141cc406Sopenharmony_ci      size = 128;
1049141cc406Sopenharmony_ci      set_read_length (sread.cmd, size);
1050141cc406Sopenharmony_ci
1051141cc406Sopenharmony_ci      DBG (DBG_info, "doing read\n");
1052141cc406Sopenharmony_ci      status = sanei_scsi_cmd (sfd, sread.cmd, sread.size, buffer, &size);
1053141cc406Sopenharmony_ci      if (status)
1054141cc406Sopenharmony_ci	{
1055141cc406Sopenharmony_ci	  DBG (DBG_error,
1056141cc406Sopenharmony_ci	       "pie_get_cal_info: read command returned status %s\n",
1057141cc406Sopenharmony_ci	       sane_strstatus (status));
1058141cc406Sopenharmony_ci	}
1059141cc406Sopenharmony_ci      else
1060141cc406Sopenharmony_ci	{
1061141cc406Sopenharmony_ci	  int i;
1062141cc406Sopenharmony_ci
1063141cc406Sopenharmony_ci	  dev->cal_info_count = buffer[4];
1064141cc406Sopenharmony_ci	  dev->cal_info =
1065141cc406Sopenharmony_ci	    malloc (sizeof (struct Pie_cal_info) * dev->cal_info_count);
1066141cc406Sopenharmony_ci
1067141cc406Sopenharmony_ci	  for (i = 0; i < dev->cal_info_count; i++)
1068141cc406Sopenharmony_ci	    {
1069141cc406Sopenharmony_ci	      dev->cal_info[i].cal_type = buffer[8 + i * buffer[5]];
1070141cc406Sopenharmony_ci	      dev->cal_info[i].send_bits = buffer[9 + i * buffer[5]];
1071141cc406Sopenharmony_ci	      dev->cal_info[i].receive_bits = buffer[10 + i * buffer[5]];
1072141cc406Sopenharmony_ci	      dev->cal_info[i].num_lines = buffer[11 + i * buffer[5]];
1073141cc406Sopenharmony_ci	      dev->cal_info[i].pixels_per_line =
1074141cc406Sopenharmony_ci		(buffer[13 + i * buffer[5]] << 8) + buffer[12 +
1075141cc406Sopenharmony_ci							   i * buffer[5]];
1076141cc406Sopenharmony_ci
1077141cc406Sopenharmony_ci	      DBG (DBG_info2, "%02x %2d %2d %2d %d\n",
1078141cc406Sopenharmony_ci		   dev->cal_info[i].cal_type, dev->cal_info[i].send_bits,
1079141cc406Sopenharmony_ci		   dev->cal_info[i].receive_bits, dev->cal_info[i].num_lines,
1080141cc406Sopenharmony_ci		   dev->cal_info[i].pixels_per_line);
1081141cc406Sopenharmony_ci	    }
1082141cc406Sopenharmony_ci	}
1083141cc406Sopenharmony_ci    }
1084141cc406Sopenharmony_ci}
1085141cc406Sopenharmony_ci
1086141cc406Sopenharmony_ci/* ------------------------------- ATTACH SCANNER ----------------------------- */
1087141cc406Sopenharmony_ci
1088141cc406Sopenharmony_cistatic SANE_Status
1089141cc406Sopenharmony_ciattach_scanner (const char *devicename, Pie_Device ** devp)
1090141cc406Sopenharmony_ci{
1091141cc406Sopenharmony_ci  Pie_Device *dev;
1092141cc406Sopenharmony_ci  int sfd;
1093141cc406Sopenharmony_ci  int bufsize;
1094141cc406Sopenharmony_ci
1095141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "attach_scanner: %s\n", devicename);
1096141cc406Sopenharmony_ci
1097141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
1098141cc406Sopenharmony_ci    {
1099141cc406Sopenharmony_ci      if (strcmp (dev->sane.name, devicename) == 0)
1100141cc406Sopenharmony_ci	{
1101141cc406Sopenharmony_ci	  if (devp)
1102141cc406Sopenharmony_ci	    {
1103141cc406Sopenharmony_ci	      *devp = dev;
1104141cc406Sopenharmony_ci	    }
1105141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
1106141cc406Sopenharmony_ci	}
1107141cc406Sopenharmony_ci    }
1108141cc406Sopenharmony_ci
1109141cc406Sopenharmony_ci  dev = malloc (sizeof (*dev));
1110141cc406Sopenharmony_ci  if (!dev)
1111141cc406Sopenharmony_ci    {
1112141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1113141cc406Sopenharmony_ci    }
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci  DBG (DBG_info, "attach_scanner: opening %s\n", devicename);
1116141cc406Sopenharmony_ci
1117141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
1118141cc406Sopenharmony_ci  bufsize = 16384;		/* 16KB */
1119141cc406Sopenharmony_ci
1120141cc406Sopenharmony_ci  if (sanei_scsi_open_extended
1121141cc406Sopenharmony_ci      (devicename, &sfd, sense_handler, dev, &bufsize) != 0)
1122141cc406Sopenharmony_ci    {
1123141cc406Sopenharmony_ci      DBG (DBG_error, "attach_scanner: open failed\n");
1124141cc406Sopenharmony_ci      free (dev);
1125141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1126141cc406Sopenharmony_ci    }
1127141cc406Sopenharmony_ci
1128141cc406Sopenharmony_ci  if (bufsize < 4096)		/* < 4KB */
1129141cc406Sopenharmony_ci    {
1130141cc406Sopenharmony_ci      DBG (DBG_error,
1131141cc406Sopenharmony_ci	   "attach_scanner: sanei_scsi_open_extended returned too small scsi buffer (%d)\n",
1132141cc406Sopenharmony_ci	   bufsize);
1133141cc406Sopenharmony_ci      sanei_scsi_close (sfd);
1134141cc406Sopenharmony_ci      free (dev);
1135141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1136141cc406Sopenharmony_ci    }
1137141cc406Sopenharmony_ci
1138141cc406Sopenharmony_ci  DBG (DBG_info,
1139141cc406Sopenharmony_ci       "attach_scanner: sanei_scsi_open_extended returned scsi buffer size = %d\n",
1140141cc406Sopenharmony_ci       bufsize);
1141141cc406Sopenharmony_ci#else
1142141cc406Sopenharmony_ci  bufsize = sanei_scsi_max_request_size;
1143141cc406Sopenharmony_ci
1144141cc406Sopenharmony_ci  if (sanei_scsi_open (devicename, &sfd, sense_handler, dev) != 0)
1145141cc406Sopenharmony_ci    {
1146141cc406Sopenharmony_ci      DBG (DBG_error, "attach_scanner: open failed\n");
1147141cc406Sopenharmony_ci      free (dev);
1148141cc406Sopenharmony_ci
1149141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1150141cc406Sopenharmony_ci
1151141cc406Sopenharmony_ci    }
1152141cc406Sopenharmony_ci#endif
1153141cc406Sopenharmony_ci
1154141cc406Sopenharmony_ci  pie_init (dev);		/* preset values in structure dev */
1155141cc406Sopenharmony_ci
1156141cc406Sopenharmony_ci  dev->devicename = strdup (devicename);
1157141cc406Sopenharmony_ci
1158141cc406Sopenharmony_ci  if (pie_identify_scanner (dev, sfd) != 0)
1159141cc406Sopenharmony_ci    {
1160141cc406Sopenharmony_ci      DBG (DBG_error, "attach_scanner: scanner-identification failed\n");
1161141cc406Sopenharmony_ci      sanei_scsi_close (sfd);
1162141cc406Sopenharmony_ci      free (dev);
1163141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
1164141cc406Sopenharmony_ci    }
1165141cc406Sopenharmony_ci
1166141cc406Sopenharmony_ci  pie_get_halftones (dev, sfd);
1167141cc406Sopenharmony_ci  pie_get_cal_info (dev, sfd);
1168141cc406Sopenharmony_ci  pie_get_speeds (dev);
1169141cc406Sopenharmony_ci
1170141cc406Sopenharmony_ci  dev->scan_mode_list[0] = COLOR_STR;
1171141cc406Sopenharmony_ci  dev->scan_mode_list[1] = GRAY_STR;
1172141cc406Sopenharmony_ci  dev->scan_mode_list[2] = LINEART_STR;
1173141cc406Sopenharmony_ci  dev->scan_mode_list[3] = HALFTONE_STR;
1174141cc406Sopenharmony_ci  dev->scan_mode_list[4] = 0;
1175141cc406Sopenharmony_ci
1176141cc406Sopenharmony_ci  sanei_scsi_close (sfd);
1177141cc406Sopenharmony_ci
1178141cc406Sopenharmony_ci  dev->sane.name = dev->devicename;
1179141cc406Sopenharmony_ci  dev->sane.vendor = dev->vendor;
1180141cc406Sopenharmony_ci  dev->sane.model = dev->product;
1181141cc406Sopenharmony_ci  dev->sane.type = "flatbed scanner";
1182141cc406Sopenharmony_ci
1183141cc406Sopenharmony_ci  dev->x_range.min = SANE_FIX (0);
1184141cc406Sopenharmony_ci  dev->x_range.quant = SANE_FIX (0);
1185141cc406Sopenharmony_ci  dev->x_range.max = SANE_FIX (dev->inquiry_fb_width * MM_PER_INCH);
1186141cc406Sopenharmony_ci
1187141cc406Sopenharmony_ci  dev->y_range.min = SANE_FIX (0);
1188141cc406Sopenharmony_ci  dev->y_range.quant = SANE_FIX (0);
1189141cc406Sopenharmony_ci  dev->y_range.max = SANE_FIX (dev->inquiry_fb_length * MM_PER_INCH);
1190141cc406Sopenharmony_ci
1191141cc406Sopenharmony_ci  dev->dpi_range.min = SANE_FIX (25);
1192141cc406Sopenharmony_ci  dev->dpi_range.quant = SANE_FIX (1);
1193141cc406Sopenharmony_ci  dev->dpi_range.max =
1194141cc406Sopenharmony_ci    SANE_FIX (max (dev->inquiry_x_res, dev->inquiry_y_res));
1195141cc406Sopenharmony_ci
1196141cc406Sopenharmony_ci  dev->shadow_range.min = SANE_FIX (0);
1197141cc406Sopenharmony_ci  dev->shadow_range.quant = SANE_FIX (1);
1198141cc406Sopenharmony_ci  dev->shadow_range.max = SANE_FIX (dev->inquiry_max_shadow);
1199141cc406Sopenharmony_ci
1200141cc406Sopenharmony_ci  dev->highlight_range.min = SANE_FIX (dev->inquiry_min_highlight);
1201141cc406Sopenharmony_ci  dev->highlight_range.quant = SANE_FIX (1);
1202141cc406Sopenharmony_ci  dev->highlight_range.max = SANE_FIX (100);
1203141cc406Sopenharmony_ci
1204141cc406Sopenharmony_ci  dev->exposure_range.min = SANE_FIX (dev->inquiry_min_exp);
1205141cc406Sopenharmony_ci  dev->exposure_range.quant = SANE_FIX (1);
1206141cc406Sopenharmony_ci  dev->exposure_range.max = SANE_FIX (dev->inquiry_max_exp);
1207141cc406Sopenharmony_ci
1208141cc406Sopenharmony_ci#if 0
1209141cc406Sopenharmony_ci  dev->analog_gamma_range.min = SANE_FIX (1.0);
1210141cc406Sopenharmony_ci  dev->analog_gamma_range.quant = SANE_FIX (0.01);
1211141cc406Sopenharmony_ci  dev->analog_gamma_range.max = SANE_FIX (2.0);
1212141cc406Sopenharmony_ci
1213141cc406Sopenharmony_ci#endif
1214141cc406Sopenharmony_ci
1215141cc406Sopenharmony_ci  dev->next = first_dev;
1216141cc406Sopenharmony_ci  first_dev = dev;
1217141cc406Sopenharmony_ci
1218141cc406Sopenharmony_ci  if (devp)
1219141cc406Sopenharmony_ci    {
1220141cc406Sopenharmony_ci      *devp = dev;
1221141cc406Sopenharmony_ci    }
1222141cc406Sopenharmony_ci
1223141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1224141cc406Sopenharmony_ci}
1225141cc406Sopenharmony_ci
1226141cc406Sopenharmony_ci/* --------------------------- MAX STRING SIZE ---------------------------- */
1227141cc406Sopenharmony_ci
1228141cc406Sopenharmony_ci
1229141cc406Sopenharmony_cistatic size_t
1230141cc406Sopenharmony_cimax_string_size (SANE_String_Const strings[])
1231141cc406Sopenharmony_ci{
1232141cc406Sopenharmony_ci  size_t size, max_size = 0;
1233141cc406Sopenharmony_ci  int i;
1234141cc406Sopenharmony_ci
1235141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i)
1236141cc406Sopenharmony_ci    {
1237141cc406Sopenharmony_ci      size = strlen (strings[i]) + 1;
1238141cc406Sopenharmony_ci      if (size > max_size)
1239141cc406Sopenharmony_ci	{
1240141cc406Sopenharmony_ci	  max_size = size;
1241141cc406Sopenharmony_ci	}
1242141cc406Sopenharmony_ci    }
1243141cc406Sopenharmony_ci
1244141cc406Sopenharmony_ci  return max_size;
1245141cc406Sopenharmony_ci}
1246141cc406Sopenharmony_ci
1247141cc406Sopenharmony_ci
1248141cc406Sopenharmony_ci/* --------------------------- INIT OPTIONS ------------------------------- */
1249141cc406Sopenharmony_ci
1250141cc406Sopenharmony_ci
1251141cc406Sopenharmony_cistatic SANE_Status
1252141cc406Sopenharmony_ciinit_options (Pie_Scanner * scanner)
1253141cc406Sopenharmony_ci{
1254141cc406Sopenharmony_ci  int i;
1255141cc406Sopenharmony_ci
1256141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "init_options\n");
1257141cc406Sopenharmony_ci
1258141cc406Sopenharmony_ci  memset (scanner->opt, 0, sizeof (scanner->opt));
1259141cc406Sopenharmony_ci  memset (scanner->val, 0, sizeof (scanner->val));
1260141cc406Sopenharmony_ci
1261141cc406Sopenharmony_ci  for (i = 0; i < NUM_OPTIONS; ++i)
1262141cc406Sopenharmony_ci    {
1263141cc406Sopenharmony_ci      scanner->opt[i].size = sizeof (SANE_Word);
1264141cc406Sopenharmony_ci      scanner->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1265141cc406Sopenharmony_ci    }
1266141cc406Sopenharmony_ci
1267141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
1268141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
1269141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
1270141cc406Sopenharmony_ci  scanner->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
1271141cc406Sopenharmony_ci  scanner->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
1272141cc406Sopenharmony_ci
1273141cc406Sopenharmony_ci  /* "Mode" group: */
1274141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].title = "Scan Mode";
1275141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].desc = "";
1276141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
1277141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].cap = 0;
1278141cc406Sopenharmony_ci  scanner->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1279141cc406Sopenharmony_ci
1280141cc406Sopenharmony_ci  /* scan mode */
1281141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
1282141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
1283141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
1284141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].type = SANE_TYPE_STRING;
1285141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].size =
1286141cc406Sopenharmony_ci    max_string_size ((SANE_String_Const *) scanner->device->scan_mode_list);
1287141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1288141cc406Sopenharmony_ci  scanner->opt[OPT_MODE].constraint.string_list =
1289141cc406Sopenharmony_ci    (SANE_String_Const *) scanner->device->scan_mode_list;
1290141cc406Sopenharmony_ci  scanner->val[OPT_MODE].s =
1291141cc406Sopenharmony_ci    (SANE_Char *) strdup (scanner->device->scan_mode_list[0]);
1292141cc406Sopenharmony_ci
1293141cc406Sopenharmony_ci  /* x-resolution */
1294141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
1295141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
1296141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
1297141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].type = SANE_TYPE_FIXED;
1298141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
1299141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE;
1300141cc406Sopenharmony_ci  scanner->opt[OPT_RESOLUTION].constraint.range = &scanner->device->dpi_range;
1301141cc406Sopenharmony_ci  scanner->val[OPT_RESOLUTION].w = 100 << SANE_FIXED_SCALE_SHIFT;
1302141cc406Sopenharmony_ci
1303141cc406Sopenharmony_ci  /* "Geometry" group: */
1304141cc406Sopenharmony_ci
1305141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].title = "Geometry";
1306141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].desc = "";
1307141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
1308141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
1309141cc406Sopenharmony_ci  scanner->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1310141cc406Sopenharmony_ci
1311141cc406Sopenharmony_ci  /* top-left x */
1312141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
1313141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
1314141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
1315141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
1316141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].unit = SANE_UNIT_MM;
1317141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
1318141cc406Sopenharmony_ci  scanner->opt[OPT_TL_X].constraint.range = &(scanner->device->x_range);
1319141cc406Sopenharmony_ci  scanner->val[OPT_TL_X].w = 0;
1320141cc406Sopenharmony_ci
1321141cc406Sopenharmony_ci  /* top-left y */
1322141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
1323141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
1324141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
1325141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
1326141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
1327141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1328141cc406Sopenharmony_ci  scanner->opt[OPT_TL_Y].constraint.range = &(scanner->device->y_range);
1329141cc406Sopenharmony_ci  scanner->val[OPT_TL_Y].w = 0;
1330141cc406Sopenharmony_ci
1331141cc406Sopenharmony_ci  /* bottom-right x */
1332141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
1333141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
1334141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
1335141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
1336141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].unit = SANE_UNIT_MM;
1337141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1338141cc406Sopenharmony_ci  scanner->opt[OPT_BR_X].constraint.range = &(scanner->device->x_range);
1339141cc406Sopenharmony_ci  scanner->val[OPT_BR_X].w = scanner->device->x_range.max;
1340141cc406Sopenharmony_ci
1341141cc406Sopenharmony_ci  /* bottom-right y */
1342141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
1343141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
1344141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
1345141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
1346141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
1347141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1348141cc406Sopenharmony_ci  scanner->opt[OPT_BR_Y].constraint.range = &(scanner->device->y_range);
1349141cc406Sopenharmony_ci  scanner->val[OPT_BR_Y].w = scanner->device->y_range.max;
1350141cc406Sopenharmony_ci
1351141cc406Sopenharmony_ci  /* "enhancement" group: */
1352141cc406Sopenharmony_ci
1353141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement";
1354141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].desc = "";
1355141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
1356141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
1357141cc406Sopenharmony_ci  scanner->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1358141cc406Sopenharmony_ci
1359141cc406Sopenharmony_ci  /* grayscale gamma vector */
1360141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
1361141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
1362141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR;
1363141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].type = SANE_TYPE_INT;
1364141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].unit = SANE_UNIT_NONE;
1365141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
1366141cc406Sopenharmony_ci  scanner->val[OPT_GAMMA_VECTOR].wa = scanner->gamma_table[0];
1367141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].constraint.range = &scanner->gamma_range;
1368141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].size =
1369141cc406Sopenharmony_ci    scanner->gamma_length * sizeof (SANE_Word);
1370141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1371141cc406Sopenharmony_ci
1372141cc406Sopenharmony_ci  /* red gamma vector */
1373141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
1374141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
1375141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
1376141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
1377141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
1378141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
1379141cc406Sopenharmony_ci  scanner->val[OPT_GAMMA_VECTOR_R].wa = scanner->gamma_table[1];
1380141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].constraint.range = &(scanner->gamma_range);
1381141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_R].size =
1382141cc406Sopenharmony_ci    scanner->gamma_length * sizeof (SANE_Word);
1383141cc406Sopenharmony_ci
1384141cc406Sopenharmony_ci  /* green gamma vector */
1385141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
1386141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
1387141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
1388141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
1389141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
1390141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
1391141cc406Sopenharmony_ci  scanner->val[OPT_GAMMA_VECTOR_G].wa = scanner->gamma_table[2];
1392141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].constraint.range = &(scanner->gamma_range);
1393141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_G].size =
1394141cc406Sopenharmony_ci    scanner->gamma_length * sizeof (SANE_Word);
1395141cc406Sopenharmony_ci
1396141cc406Sopenharmony_ci
1397141cc406Sopenharmony_ci  /* blue gamma vector */
1398141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
1399141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
1400141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
1401141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
1402141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
1403141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
1404141cc406Sopenharmony_ci  scanner->val[OPT_GAMMA_VECTOR_B].wa = scanner->gamma_table[3];
1405141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].constraint.range = &(scanner->gamma_range);
1406141cc406Sopenharmony_ci  scanner->opt[OPT_GAMMA_VECTOR_B].size =
1407141cc406Sopenharmony_ci    scanner->gamma_length * sizeof (SANE_Word);
1408141cc406Sopenharmony_ci
1409141cc406Sopenharmony_ci  /* halftone pattern */
1410141cc406Sopenharmony_ci  scanner->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN;
1411141cc406Sopenharmony_ci  scanner->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN;
1412141cc406Sopenharmony_ci  scanner->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN;
1413141cc406Sopenharmony_ci  scanner->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING;
1414141cc406Sopenharmony_ci  scanner->opt[OPT_HALFTONE_PATTERN].size =
1415141cc406Sopenharmony_ci    max_string_size ((SANE_String_Const *) scanner->device->halftone_list);
1416141cc406Sopenharmony_ci  scanner->opt[OPT_HALFTONE_PATTERN].constraint_type =
1417141cc406Sopenharmony_ci    SANE_CONSTRAINT_STRING_LIST;
1418141cc406Sopenharmony_ci  scanner->opt[OPT_HALFTONE_PATTERN].constraint.string_list =
1419141cc406Sopenharmony_ci    (SANE_String_Const *) scanner->device->halftone_list;
1420141cc406Sopenharmony_ci  scanner->val[OPT_HALFTONE_PATTERN].s =
1421141cc406Sopenharmony_ci    (SANE_Char *) strdup (scanner->device->halftone_list[0]);
1422141cc406Sopenharmony_ci  scanner->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
1423141cc406Sopenharmony_ci
1424141cc406Sopenharmony_ci  /* speed */
1425141cc406Sopenharmony_ci  scanner->opt[OPT_SPEED].name = SANE_NAME_SCAN_SPEED;
1426141cc406Sopenharmony_ci  scanner->opt[OPT_SPEED].title = SANE_TITLE_SCAN_SPEED;
1427141cc406Sopenharmony_ci  scanner->opt[OPT_SPEED].desc = SANE_DESC_SCAN_SPEED;
1428141cc406Sopenharmony_ci  scanner->opt[OPT_SPEED].type = SANE_TYPE_STRING;
1429141cc406Sopenharmony_ci  scanner->opt[OPT_SPEED].size =
1430141cc406Sopenharmony_ci    max_string_size ((SANE_String_Const *) scanner->device->speed_list);
1431141cc406Sopenharmony_ci  scanner->opt[OPT_SPEED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1432141cc406Sopenharmony_ci  scanner->opt[OPT_SPEED].constraint.string_list =
1433141cc406Sopenharmony_ci    (SANE_String_Const *) scanner->device->speed_list;
1434141cc406Sopenharmony_ci  scanner->val[OPT_SPEED].s =
1435141cc406Sopenharmony_ci    (SANE_Char *) strdup (scanner->device->speed_list[0]);
1436141cc406Sopenharmony_ci
1437141cc406Sopenharmony_ci  /* lineart threshold */
1438141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
1439141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
1440141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
1441141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED;
1442141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT;
1443141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
1444141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].constraint.range = &percentage_range_100;
1445141cc406Sopenharmony_ci  scanner->val[OPT_THRESHOLD].w = SANE_FIX (50);
1446141cc406Sopenharmony_ci  scanner->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1447141cc406Sopenharmony_ci
1448141cc406Sopenharmony_ci  /* "advanced" group: */
1449141cc406Sopenharmony_ci
1450141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].title = "Advanced";
1451141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].desc = "";
1452141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].type = SANE_TYPE_GROUP;
1453141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].cap = SANE_CAP_ADVANCED;
1454141cc406Sopenharmony_ci  scanner->opt[OPT_ADVANCED_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1455141cc406Sopenharmony_ci
1456141cc406Sopenharmony_ci  /* preview */
1457141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
1458141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
1459141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
1460141cc406Sopenharmony_ci  scanner->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
1461141cc406Sopenharmony_ci  scanner->val[OPT_PREVIEW].w = SANE_FALSE;
1462141cc406Sopenharmony_ci
1463141cc406Sopenharmony_ci
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1466141cc406Sopenharmony_ci}
1467141cc406Sopenharmony_ci
1468141cc406Sopenharmony_ci
1469141cc406Sopenharmony_ci/*------------------------- PIE POWER SAVE -----------------------------*/
1470141cc406Sopenharmony_ci
1471141cc406Sopenharmony_cistatic SANE_Status
1472141cc406Sopenharmony_cipie_power_save (Pie_Scanner * scanner, int time)
1473141cc406Sopenharmony_ci{
1474141cc406Sopenharmony_ci  unsigned char buffer[128];
1475141cc406Sopenharmony_ci  size_t size;
1476141cc406Sopenharmony_ci  SANE_Status status;
1477141cc406Sopenharmony_ci  unsigned char *data;
1478141cc406Sopenharmony_ci
1479141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_power_save: %d min\n", time);
1480141cc406Sopenharmony_ci
1481141cc406Sopenharmony_ci  size = 6;
1482141cc406Sopenharmony_ci
1483141cc406Sopenharmony_ci  set_write_length (swrite.cmd, size);
1484141cc406Sopenharmony_ci
1485141cc406Sopenharmony_ci  memcpy (buffer, swrite.cmd, swrite.size);
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci  data = buffer + swrite.size;
1488141cc406Sopenharmony_ci  memset (data, 0, size);
1489141cc406Sopenharmony_ci
1490141cc406Sopenharmony_ci  set_command (data, SET_POWER_SAVE_CONTROL);
1491141cc406Sopenharmony_ci  set_data_length (data, size - 4);
1492141cc406Sopenharmony_ci  data[4] = time & 0x7f;
1493141cc406Sopenharmony_ci
1494141cc406Sopenharmony_ci  status =
1495141cc406Sopenharmony_ci    sanei_scsi_cmd (scanner->sfd, buffer, swrite.size + size, NULL, NULL);
1496141cc406Sopenharmony_ci  if (status)
1497141cc406Sopenharmony_ci    {
1498141cc406Sopenharmony_ci      DBG (DBG_error, "pie_power_save: write command returned status %s\n",
1499141cc406Sopenharmony_ci	   sane_strstatus (status));
1500141cc406Sopenharmony_ci    }
1501141cc406Sopenharmony_ci
1502141cc406Sopenharmony_ci  return status;
1503141cc406Sopenharmony_ci}
1504141cc406Sopenharmony_ci
1505141cc406Sopenharmony_ci/*------------------------- PIE SEND EXPOSURE ONE -----------------------------*/
1506141cc406Sopenharmony_ci
1507141cc406Sopenharmony_ci
1508141cc406Sopenharmony_cistatic SANE_Status
1509141cc406Sopenharmony_cipie_send_exposure_one (Pie_Scanner * scanner, int filter, int value)
1510141cc406Sopenharmony_ci{
1511141cc406Sopenharmony_ci  unsigned char buffer[128];
1512141cc406Sopenharmony_ci  size_t size;
1513141cc406Sopenharmony_ci  SANE_Status status;
1514141cc406Sopenharmony_ci  unsigned char *data;
1515141cc406Sopenharmony_ci
1516141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_send_exposure_one\n");
1517141cc406Sopenharmony_ci
1518141cc406Sopenharmony_ci  size = 8;
1519141cc406Sopenharmony_ci
1520141cc406Sopenharmony_ci  set_write_length (swrite.cmd, size);
1521141cc406Sopenharmony_ci
1522141cc406Sopenharmony_ci  memcpy (buffer, swrite.cmd, swrite.size);
1523141cc406Sopenharmony_ci
1524141cc406Sopenharmony_ci  data = buffer + swrite.size;
1525141cc406Sopenharmony_ci  memset (data, 0, size);
1526141cc406Sopenharmony_ci
1527141cc406Sopenharmony_ci  set_command (data, SET_EXP_TIME);
1528141cc406Sopenharmony_ci  set_data_length (data, size - 4);
1529141cc406Sopenharmony_ci
1530141cc406Sopenharmony_ci  data[4] = filter;
1531141cc406Sopenharmony_ci
1532141cc406Sopenharmony_ci  set_data (data, 6, (int) value, 2);
1533141cc406Sopenharmony_ci
1534141cc406Sopenharmony_ci  status =
1535141cc406Sopenharmony_ci    sanei_scsi_cmd (scanner->sfd, buffer, swrite.size + size, NULL, NULL);
1536141cc406Sopenharmony_ci  if (status)
1537141cc406Sopenharmony_ci    {
1538141cc406Sopenharmony_ci      DBG (DBG_error,
1539141cc406Sopenharmony_ci	   "pie_send_exposure_one: write command returned status %s\n",
1540141cc406Sopenharmony_ci	   sane_strstatus (status));
1541141cc406Sopenharmony_ci    }
1542141cc406Sopenharmony_ci
1543141cc406Sopenharmony_ci  return status;
1544141cc406Sopenharmony_ci}
1545141cc406Sopenharmony_ci
1546141cc406Sopenharmony_ci/*------------------------- PIE SEND EXPOSURE -----------------------------*/
1547141cc406Sopenharmony_ci
1548141cc406Sopenharmony_cistatic SANE_Status
1549141cc406Sopenharmony_cipie_send_exposure (Pie_Scanner * scanner)
1550141cc406Sopenharmony_ci{
1551141cc406Sopenharmony_ci  SANE_Status status;
1552141cc406Sopenharmony_ci
1553141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_send_exposure\n");
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_ci  status = pie_send_exposure_one (scanner, FILTER_RED, 100);
1556141cc406Sopenharmony_ci  if (status)
1557141cc406Sopenharmony_ci    return status;
1558141cc406Sopenharmony_ci
1559141cc406Sopenharmony_ci  status = pie_send_exposure_one (scanner, FILTER_GREEN, 100);
1560141cc406Sopenharmony_ci  if (status)
1561141cc406Sopenharmony_ci    return status;
1562141cc406Sopenharmony_ci
1563141cc406Sopenharmony_ci  status = pie_send_exposure_one (scanner, FILTER_BLUE, 100);
1564141cc406Sopenharmony_ci  if (status)
1565141cc406Sopenharmony_ci    return status;
1566141cc406Sopenharmony_ci
1567141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1568141cc406Sopenharmony_ci}
1569141cc406Sopenharmony_ci
1570141cc406Sopenharmony_ci
1571141cc406Sopenharmony_ci/*------------------------- PIE SEND HIGHLIGHT/SHADOW ONE -----------------------------*/
1572141cc406Sopenharmony_ci
1573141cc406Sopenharmony_cistatic SANE_Status
1574141cc406Sopenharmony_cipie_send_highlight_shadow_one (Pie_Scanner * scanner, int filter,
1575141cc406Sopenharmony_ci			       int highlight, int shadow)
1576141cc406Sopenharmony_ci{
1577141cc406Sopenharmony_ci  unsigned char buffer[128];
1578141cc406Sopenharmony_ci  size_t size;
1579141cc406Sopenharmony_ci  SANE_Status status;
1580141cc406Sopenharmony_ci  unsigned char *data;
1581141cc406Sopenharmony_ci
1582141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_send_highlight_shadow_one\n");
1583141cc406Sopenharmony_ci
1584141cc406Sopenharmony_ci  size = 8;
1585141cc406Sopenharmony_ci
1586141cc406Sopenharmony_ci  set_write_length (swrite.cmd, size);
1587141cc406Sopenharmony_ci
1588141cc406Sopenharmony_ci  memcpy (buffer, swrite.cmd, swrite.size);
1589141cc406Sopenharmony_ci
1590141cc406Sopenharmony_ci  data = buffer + swrite.size;
1591141cc406Sopenharmony_ci  memset (data, 0, size);
1592141cc406Sopenharmony_ci
1593141cc406Sopenharmony_ci  set_command (data, SET_EXP_TIME);
1594141cc406Sopenharmony_ci  set_data_length (data, size - 4);
1595141cc406Sopenharmony_ci
1596141cc406Sopenharmony_ci  data[4] = filter;
1597141cc406Sopenharmony_ci
1598141cc406Sopenharmony_ci  data[6] = highlight;
1599141cc406Sopenharmony_ci  data[7] = shadow;
1600141cc406Sopenharmony_ci
1601141cc406Sopenharmony_ci  status =
1602141cc406Sopenharmony_ci    sanei_scsi_cmd (scanner->sfd, buffer, swrite.size + size, NULL, NULL);
1603141cc406Sopenharmony_ci  if (status)
1604141cc406Sopenharmony_ci    {
1605141cc406Sopenharmony_ci      DBG (DBG_error,
1606141cc406Sopenharmony_ci	   "pie_send_highlight_shadow_one: write command returned status %s\n",
1607141cc406Sopenharmony_ci	   sane_strstatus (status));
1608141cc406Sopenharmony_ci    }
1609141cc406Sopenharmony_ci
1610141cc406Sopenharmony_ci  return status;
1611141cc406Sopenharmony_ci}
1612141cc406Sopenharmony_ci
1613141cc406Sopenharmony_ci/*------------------------- PIE SEND HIGHLIGHT/SHADOW -----------------------------*/
1614141cc406Sopenharmony_ci
1615141cc406Sopenharmony_cistatic SANE_Status
1616141cc406Sopenharmony_cipie_send_highlight_shadow (Pie_Scanner * scanner)
1617141cc406Sopenharmony_ci{
1618141cc406Sopenharmony_ci  SANE_Status status;
1619141cc406Sopenharmony_ci
1620141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_send_highlight_shadow\n");
1621141cc406Sopenharmony_ci
1622141cc406Sopenharmony_ci  status = pie_send_highlight_shadow_one (scanner, FILTER_RED, 100, 0);
1623141cc406Sopenharmony_ci  if (status)
1624141cc406Sopenharmony_ci    return status;
1625141cc406Sopenharmony_ci
1626141cc406Sopenharmony_ci  status = pie_send_highlight_shadow_one (scanner, FILTER_GREEN, 100, 0);
1627141cc406Sopenharmony_ci  if (status)
1628141cc406Sopenharmony_ci    return status;
1629141cc406Sopenharmony_ci
1630141cc406Sopenharmony_ci  status = pie_send_highlight_shadow_one (scanner, FILTER_BLUE, 100, 0);
1631141cc406Sopenharmony_ci  if (status)
1632141cc406Sopenharmony_ci    return status;
1633141cc406Sopenharmony_ci
1634141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1635141cc406Sopenharmony_ci}
1636141cc406Sopenharmony_ci
1637141cc406Sopenharmony_ci/*------------------------- PIE PERFORM CAL ----------------------------*/
1638141cc406Sopenharmony_ci
1639141cc406Sopenharmony_cistatic SANE_Status
1640141cc406Sopenharmony_cipie_perform_cal (Pie_Scanner * scanner, int cal_index)
1641141cc406Sopenharmony_ci{
1642141cc406Sopenharmony_ci  long *red_result;
1643141cc406Sopenharmony_ci  long *green_result;
1644141cc406Sopenharmony_ci  long *blue_result;
1645141cc406Sopenharmony_ci  long *neutral_result;
1646141cc406Sopenharmony_ci  long *result = NULL;
1647141cc406Sopenharmony_ci  int rcv_length, send_length;
1648141cc406Sopenharmony_ci  int rcv_lines, rcv_bits, send_bits;
1649141cc406Sopenharmony_ci  int pixels_per_line;
1650141cc406Sopenharmony_ci  int i;
1651141cc406Sopenharmony_ci  unsigned char *rcv_buffer, *rcv_ptr;
1652141cc406Sopenharmony_ci  unsigned char *send_buffer, *send_ptr;
1653141cc406Sopenharmony_ci  size_t size;
1654141cc406Sopenharmony_ci  int fullscale;
1655141cc406Sopenharmony_ci  int cal_limit;
1656141cc406Sopenharmony_ci  int k;
1657141cc406Sopenharmony_ci  int filter;
1658141cc406Sopenharmony_ci  SANE_Status status;
1659141cc406Sopenharmony_ci
1660141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_perform_cal\n");
1661141cc406Sopenharmony_ci
1662141cc406Sopenharmony_ci  pixels_per_line = scanner->device->cal_info[cal_index].pixels_per_line;
1663141cc406Sopenharmony_ci  rcv_length = pixels_per_line;
1664141cc406Sopenharmony_ci  send_length = pixels_per_line;
1665141cc406Sopenharmony_ci
1666141cc406Sopenharmony_ci  rcv_bits = scanner->device->cal_info[cal_index].receive_bits;
1667141cc406Sopenharmony_ci  if (rcv_bits > 8)
1668141cc406Sopenharmony_ci    rcv_length *= 2;		/* 2 bytes / sample */
1669141cc406Sopenharmony_ci
1670141cc406Sopenharmony_ci  send_bits = scanner->device->cal_info[cal_index].send_bits;
1671141cc406Sopenharmony_ci  if (send_bits > 8)
1672141cc406Sopenharmony_ci    send_length *= 2;		/* 2 bytes / sample */
1673141cc406Sopenharmony_ci
1674141cc406Sopenharmony_ci  rcv_lines = scanner->device->cal_info[cal_index].num_lines;
1675141cc406Sopenharmony_ci
1676141cc406Sopenharmony_ci  send_length += 2;		/* space for filter at start */
1677141cc406Sopenharmony_ci
1678141cc406Sopenharmony_ci  if (scanner->colormode == RGB)
1679141cc406Sopenharmony_ci    {
1680141cc406Sopenharmony_ci      rcv_lines *= 3;
1681141cc406Sopenharmony_ci      send_length *= 3;
1682141cc406Sopenharmony_ci      rcv_length += 2;		/* 2 bytes for index at front of data (only in RGB??) */
1683141cc406Sopenharmony_ci    }
1684141cc406Sopenharmony_ci
1685141cc406Sopenharmony_ci  send_length += 4;		/* space for header at start of data */
1686141cc406Sopenharmony_ci
1687141cc406Sopenharmony_ci  /* allocate buffers for the receive data, the result buffers, and for the send data */
1688141cc406Sopenharmony_ci  rcv_buffer = (unsigned char *) malloc (rcv_length);
1689141cc406Sopenharmony_ci
1690141cc406Sopenharmony_ci  red_result = (long *) calloc (pixels_per_line, sizeof (long));
1691141cc406Sopenharmony_ci  green_result = (long *) calloc (pixels_per_line, sizeof (long));
1692141cc406Sopenharmony_ci  blue_result = (long *) calloc (pixels_per_line, sizeof (long));
1693141cc406Sopenharmony_ci  neutral_result = (long *) calloc (pixels_per_line, sizeof (long));
1694141cc406Sopenharmony_ci
1695141cc406Sopenharmony_ci  if (!rcv_buffer || !red_result || !green_result || !blue_result
1696141cc406Sopenharmony_ci      || !neutral_result)
1697141cc406Sopenharmony_ci    {
1698141cc406Sopenharmony_ci      /* at least one malloc failed, so free all buffers (free accepts NULL) */
1699141cc406Sopenharmony_ci      free (rcv_buffer);
1700141cc406Sopenharmony_ci      free (red_result);
1701141cc406Sopenharmony_ci      free (green_result);
1702141cc406Sopenharmony_ci      free (blue_result);
1703141cc406Sopenharmony_ci      free (neutral_result);
1704141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1705141cc406Sopenharmony_ci    }
1706141cc406Sopenharmony_ci
1707141cc406Sopenharmony_ci  /* read the cal data a line at a time, and accumulate into the result arrays */
1708141cc406Sopenharmony_ci  while (rcv_lines--)
1709141cc406Sopenharmony_ci    {
1710141cc406Sopenharmony_ci      /* TUR */
1711141cc406Sopenharmony_ci      status = pie_wait_scanner (scanner);
1712141cc406Sopenharmony_ci      if (status)
1713141cc406Sopenharmony_ci	{
1714141cc406Sopenharmony_ci	  free (rcv_buffer);
1715141cc406Sopenharmony_ci	  free (red_result);
1716141cc406Sopenharmony_ci	  free (green_result);
1717141cc406Sopenharmony_ci	  free (blue_result);
1718141cc406Sopenharmony_ci	  free (neutral_result);
1719141cc406Sopenharmony_ci	  return status;
1720141cc406Sopenharmony_ci	}
1721141cc406Sopenharmony_ci
1722141cc406Sopenharmony_ci      set_read_length (sread.cmd, 1);
1723141cc406Sopenharmony_ci      size = rcv_length;
1724141cc406Sopenharmony_ci
1725141cc406Sopenharmony_ci      DBG (DBG_info, "pie_perform_cal: reading 1 line (%lu bytes)\n", (u_long) size);
1726141cc406Sopenharmony_ci
1727141cc406Sopenharmony_ci      status =
1728141cc406Sopenharmony_ci	sanei_scsi_cmd (scanner->sfd, sread.cmd, sread.size, rcv_buffer,
1729141cc406Sopenharmony_ci			&size);
1730141cc406Sopenharmony_ci
1731141cc406Sopenharmony_ci      if (status)
1732141cc406Sopenharmony_ci	{
1733141cc406Sopenharmony_ci	  DBG (DBG_error,
1734141cc406Sopenharmony_ci	       "pie_perform_cal: read command returned status %s\n",
1735141cc406Sopenharmony_ci	       sane_strstatus (status));
1736141cc406Sopenharmony_ci	  free (rcv_buffer);
1737141cc406Sopenharmony_ci	  free (red_result);
1738141cc406Sopenharmony_ci	  free (green_result);
1739141cc406Sopenharmony_ci	  free (blue_result);
1740141cc406Sopenharmony_ci	  free (neutral_result);
1741141cc406Sopenharmony_ci	  return status;
1742141cc406Sopenharmony_ci	}
1743141cc406Sopenharmony_ci
1744141cc406Sopenharmony_ci      DBG_DUMP (DBG_dump, rcv_buffer, 32);
1745141cc406Sopenharmony_ci
1746141cc406Sopenharmony_ci      /* which result buffer does this line belong to? */
1747141cc406Sopenharmony_ci      if (scanner->colormode == RGB)
1748141cc406Sopenharmony_ci	{
1749141cc406Sopenharmony_ci	  if (*rcv_buffer == 'R')
1750141cc406Sopenharmony_ci	    result = red_result;
1751141cc406Sopenharmony_ci	  else if (*rcv_buffer == 'G')
1752141cc406Sopenharmony_ci	    result = green_result;
1753141cc406Sopenharmony_ci	  else if (*rcv_buffer == 'B')
1754141cc406Sopenharmony_ci	    result = blue_result;
1755141cc406Sopenharmony_ci	  else if (*rcv_buffer == 'N')
1756141cc406Sopenharmony_ci	    result = neutral_result;
1757141cc406Sopenharmony_ci	  else
1758141cc406Sopenharmony_ci	    {
1759141cc406Sopenharmony_ci	      DBG (DBG_error, "pie_perform_cal: invalid index byte (%02x)\n",
1760141cc406Sopenharmony_ci		   *rcv_buffer);
1761141cc406Sopenharmony_ci	      DBG_DUMP (DBG_error, rcv_buffer, 32);
1762141cc406Sopenharmony_ci	      free (rcv_buffer);
1763141cc406Sopenharmony_ci	      free (red_result);
1764141cc406Sopenharmony_ci	      free (green_result);
1765141cc406Sopenharmony_ci	      free (blue_result);
1766141cc406Sopenharmony_ci	      free (neutral_result);
1767141cc406Sopenharmony_ci	      return SANE_STATUS_INVAL;
1768141cc406Sopenharmony_ci	    }
1769141cc406Sopenharmony_ci	  rcv_ptr = rcv_buffer + 2;
1770141cc406Sopenharmony_ci	}
1771141cc406Sopenharmony_ci      else
1772141cc406Sopenharmony_ci	{
1773141cc406Sopenharmony_ci	  /* monochrome - no bytes indicating filter here */
1774141cc406Sopenharmony_ci	  result = neutral_result;
1775141cc406Sopenharmony_ci	  rcv_ptr = rcv_buffer;
1776141cc406Sopenharmony_ci	}
1777141cc406Sopenharmony_ci
1778141cc406Sopenharmony_ci      /* now add the values in this line to the result array */
1779141cc406Sopenharmony_ci      for (i = 0; i < pixels_per_line; i++)
1780141cc406Sopenharmony_ci	{
1781141cc406Sopenharmony_ci	  result[i] += *rcv_ptr++;
1782141cc406Sopenharmony_ci	  if (rcv_bits > 8)
1783141cc406Sopenharmony_ci	    {
1784141cc406Sopenharmony_ci	      result[i] += (*rcv_ptr++) << 8;
1785141cc406Sopenharmony_ci	    }
1786141cc406Sopenharmony_ci	}
1787141cc406Sopenharmony_ci    }
1788141cc406Sopenharmony_ci
1789141cc406Sopenharmony_ci  /* got all the cal data, now process it ready to send back */
1790141cc406Sopenharmony_ci  free (rcv_buffer);
1791141cc406Sopenharmony_ci  send_buffer = (unsigned char *) malloc (send_length + swrite.size);
1792141cc406Sopenharmony_ci
1793141cc406Sopenharmony_ci  if (!send_buffer)
1794141cc406Sopenharmony_ci    {
1795141cc406Sopenharmony_ci      free (red_result);
1796141cc406Sopenharmony_ci      free (green_result);
1797141cc406Sopenharmony_ci      free (blue_result);
1798141cc406Sopenharmony_ci      free (neutral_result);
1799141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
1800141cc406Sopenharmony_ci    }
1801141cc406Sopenharmony_ci
1802141cc406Sopenharmony_ci  rcv_lines = scanner->device->cal_info[cal_index].num_lines;
1803141cc406Sopenharmony_ci  fullscale = (1 << rcv_bits) - 1;
1804141cc406Sopenharmony_ci  cal_limit = fullscale / (1 << scanner->device->inquiry_cal_eqn);
1805141cc406Sopenharmony_ci  k = (1 << scanner->device->inquiry_cal_eqn) - 1;
1806141cc406Sopenharmony_ci
1807141cc406Sopenharmony_ci  /* set up scsi command and data */
1808141cc406Sopenharmony_ci  size = send_length;
1809141cc406Sopenharmony_ci
1810141cc406Sopenharmony_ci  memcpy (send_buffer, swrite.cmd, swrite.size);
1811141cc406Sopenharmony_ci  set_write_length (send_buffer, size);
1812141cc406Sopenharmony_ci
1813141cc406Sopenharmony_ci  set_command (send_buffer + swrite.size, SEND_CAL_DATA);
1814141cc406Sopenharmony_ci  set_data_length (send_buffer + swrite.size, size - 4);
1815141cc406Sopenharmony_ci
1816141cc406Sopenharmony_ci  send_ptr = send_buffer + swrite.size + 4;
1817141cc406Sopenharmony_ci
1818141cc406Sopenharmony_ci  for (filter = FILTER_NEUTRAL; filter <= FILTER_BLUE; filter <<= 1)
1819141cc406Sopenharmony_ci    {
1820141cc406Sopenharmony_ci
1821141cc406Sopenharmony_ci      /* only send data for filter we expect to send */
1822141cc406Sopenharmony_ci      if (!(filter & scanner->cal_filter))
1823141cc406Sopenharmony_ci	continue;
1824141cc406Sopenharmony_ci
1825141cc406Sopenharmony_ci      set_data (send_ptr, 0, filter, 2);
1826141cc406Sopenharmony_ci      send_ptr += 2;
1827141cc406Sopenharmony_ci
1828141cc406Sopenharmony_ci      if (scanner->colormode == RGB)
1829141cc406Sopenharmony_ci	{
1830141cc406Sopenharmony_ci	  switch (filter)
1831141cc406Sopenharmony_ci	    {
1832141cc406Sopenharmony_ci	    case FILTER_RED:
1833141cc406Sopenharmony_ci	      result = red_result;
1834141cc406Sopenharmony_ci	      break;
1835141cc406Sopenharmony_ci
1836141cc406Sopenharmony_ci	    case FILTER_GREEN:
1837141cc406Sopenharmony_ci	      result = green_result;
1838141cc406Sopenharmony_ci	      break;
1839141cc406Sopenharmony_ci
1840141cc406Sopenharmony_ci	    case FILTER_BLUE:
1841141cc406Sopenharmony_ci	      result = blue_result;
1842141cc406Sopenharmony_ci	      break;
1843141cc406Sopenharmony_ci
1844141cc406Sopenharmony_ci	    case FILTER_NEUTRAL:
1845141cc406Sopenharmony_ci	      result = neutral_result;
1846141cc406Sopenharmony_ci	      break;
1847141cc406Sopenharmony_ci	    }
1848141cc406Sopenharmony_ci	}
1849141cc406Sopenharmony_ci      else
1850141cc406Sopenharmony_ci	result = neutral_result;
1851141cc406Sopenharmony_ci
1852141cc406Sopenharmony_ci      /* for each pixel */
1853141cc406Sopenharmony_ci      for (i = 0; i < pixels_per_line; i++)
1854141cc406Sopenharmony_ci	{
1855141cc406Sopenharmony_ci	  long x;
1856141cc406Sopenharmony_ci
1857141cc406Sopenharmony_ci	  /* make average */
1858141cc406Sopenharmony_ci	  x = result[i] / rcv_lines;
1859141cc406Sopenharmony_ci
1860141cc406Sopenharmony_ci	  /* ensure not overflowed */
1861141cc406Sopenharmony_ci	  if (x > fullscale)
1862141cc406Sopenharmony_ci	    x = fullscale;
1863141cc406Sopenharmony_ci
1864141cc406Sopenharmony_ci	  /* process according to required calibration equation */
1865141cc406Sopenharmony_ci	  if (scanner->device->inquiry_cal_eqn)
1866141cc406Sopenharmony_ci	    {
1867141cc406Sopenharmony_ci	      if (x <= cal_limit)
1868141cc406Sopenharmony_ci		x = fullscale;
1869141cc406Sopenharmony_ci	      else
1870141cc406Sopenharmony_ci		x = ((fullscale - x) * fullscale) / (x * k);
1871141cc406Sopenharmony_ci	    }
1872141cc406Sopenharmony_ci
1873141cc406Sopenharmony_ci	  if (rcv_bits > send_bits)
1874141cc406Sopenharmony_ci	    x >>= (rcv_bits - send_bits);
1875141cc406Sopenharmony_ci	  else if (send_bits > rcv_bits)
1876141cc406Sopenharmony_ci	    x <<= (send_bits - rcv_bits);
1877141cc406Sopenharmony_ci
1878141cc406Sopenharmony_ci	  /* put result into send buffer */
1879141cc406Sopenharmony_ci	  *send_ptr++ = x;
1880141cc406Sopenharmony_ci	  if (send_bits > 8)
1881141cc406Sopenharmony_ci	    *send_ptr++ = x >> 8;
1882141cc406Sopenharmony_ci	}
1883141cc406Sopenharmony_ci    }
1884141cc406Sopenharmony_ci
1885141cc406Sopenharmony_ci  /* now send the data back to scanner */
1886141cc406Sopenharmony_ci
1887141cc406Sopenharmony_ci  /* TUR */
1888141cc406Sopenharmony_ci  status = pie_wait_scanner (scanner);
1889141cc406Sopenharmony_ci  if (status)
1890141cc406Sopenharmony_ci    {
1891141cc406Sopenharmony_ci      free (red_result);
1892141cc406Sopenharmony_ci      free (green_result);
1893141cc406Sopenharmony_ci      free (blue_result);
1894141cc406Sopenharmony_ci      free (neutral_result);
1895141cc406Sopenharmony_ci      free (send_buffer);
1896141cc406Sopenharmony_ci      return status;
1897141cc406Sopenharmony_ci    }
1898141cc406Sopenharmony_ci
1899141cc406Sopenharmony_ci  DBG (DBG_info, "pie_perform_cal: sending cal data (%lu bytes)\n", (u_long) size);
1900141cc406Sopenharmony_ci  DBG_DUMP (DBG_dump, send_buffer, 64);
1901141cc406Sopenharmony_ci
1902141cc406Sopenharmony_ci  status =
1903141cc406Sopenharmony_ci    sanei_scsi_cmd (scanner->sfd, send_buffer, swrite.size + size, NULL,
1904141cc406Sopenharmony_ci		    NULL);
1905141cc406Sopenharmony_ci  if (status)
1906141cc406Sopenharmony_ci    {
1907141cc406Sopenharmony_ci      DBG (DBG_error, "pie_perform_cal: write command returned status %s\n",
1908141cc406Sopenharmony_ci	   sane_strstatus (status));
1909141cc406Sopenharmony_ci      free (red_result);
1910141cc406Sopenharmony_ci      free (green_result);
1911141cc406Sopenharmony_ci      free (blue_result);
1912141cc406Sopenharmony_ci      free (neutral_result);
1913141cc406Sopenharmony_ci      free (send_buffer);
1914141cc406Sopenharmony_ci      return status;
1915141cc406Sopenharmony_ci    }
1916141cc406Sopenharmony_ci
1917141cc406Sopenharmony_ci  free (red_result);
1918141cc406Sopenharmony_ci  free (green_result);
1919141cc406Sopenharmony_ci  free (blue_result);
1920141cc406Sopenharmony_ci  free (neutral_result);
1921141cc406Sopenharmony_ci  free (send_buffer);
1922141cc406Sopenharmony_ci
1923141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1924141cc406Sopenharmony_ci}
1925141cc406Sopenharmony_ci
1926141cc406Sopenharmony_ci/*------------------------- PIE DO CAL -----------------------------*/
1927141cc406Sopenharmony_ci
1928141cc406Sopenharmony_cistatic SANE_Status
1929141cc406Sopenharmony_cipie_do_cal (Pie_Scanner * scanner)
1930141cc406Sopenharmony_ci{
1931141cc406Sopenharmony_ci  SANE_Status status;
1932141cc406Sopenharmony_ci  int cal_index;
1933141cc406Sopenharmony_ci
1934141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_do_cal\n");
1935141cc406Sopenharmony_ci
1936141cc406Sopenharmony_ci  if (scanner->device->inquiry_scan_capability & INQ_CAP_EXT_CAL)
1937141cc406Sopenharmony_ci    {
1938141cc406Sopenharmony_ci      for (cal_index = 0; cal_index < scanner->device->cal_info_count;
1939141cc406Sopenharmony_ci	   cal_index++)
1940141cc406Sopenharmony_ci	if (scanner->device->cal_info[cal_index].cal_type ==
1941141cc406Sopenharmony_ci	    scanner->cal_mode)
1942141cc406Sopenharmony_ci	  {
1943141cc406Sopenharmony_ci	    status = pie_perform_cal (scanner, cal_index);
1944141cc406Sopenharmony_ci	    if (status != SANE_STATUS_GOOD)
1945141cc406Sopenharmony_ci	      return status;
1946141cc406Sopenharmony_ci	  }
1947141cc406Sopenharmony_ci    }
1948141cc406Sopenharmony_ci
1949141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1950141cc406Sopenharmony_ci}
1951141cc406Sopenharmony_ci
1952141cc406Sopenharmony_ci/*------------------------- PIE DWNLD GAMMA ONE -----------------------------*/
1953141cc406Sopenharmony_ci
1954141cc406Sopenharmony_cistatic SANE_Status
1955141cc406Sopenharmony_cipie_dwnld_gamma_one (Pie_Scanner * scanner, int filter, SANE_Int * table)
1956141cc406Sopenharmony_ci{
1957141cc406Sopenharmony_ci  unsigned char *buffer;
1958141cc406Sopenharmony_ci  size_t size;
1959141cc406Sopenharmony_ci  SANE_Status status;
1960141cc406Sopenharmony_ci  unsigned char *data;
1961141cc406Sopenharmony_ci  int i;
1962141cc406Sopenharmony_ci
1963141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_dwnld_gamma_one\n");
1964141cc406Sopenharmony_ci
1965141cc406Sopenharmony_ci  /* TUR */
1966141cc406Sopenharmony_ci  status = pie_wait_scanner (scanner);
1967141cc406Sopenharmony_ci  if (status)
1968141cc406Sopenharmony_ci    {
1969141cc406Sopenharmony_ci      return status;
1970141cc406Sopenharmony_ci    }
1971141cc406Sopenharmony_ci
1972141cc406Sopenharmony_ci  if (scanner->device->inquiry_gamma_bits > 8)
1973141cc406Sopenharmony_ci    size = scanner->gamma_length * 2 + 6;
1974141cc406Sopenharmony_ci  else
1975141cc406Sopenharmony_ci    size = scanner->gamma_length + 6;
1976141cc406Sopenharmony_ci
1977141cc406Sopenharmony_ci  buffer = malloc (size + swrite.size);
1978141cc406Sopenharmony_ci  if (!buffer)
1979141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
1980141cc406Sopenharmony_ci
1981141cc406Sopenharmony_ci  set_write_length (swrite.cmd, size);
1982141cc406Sopenharmony_ci
1983141cc406Sopenharmony_ci  memcpy (buffer, swrite.cmd, swrite.size);
1984141cc406Sopenharmony_ci
1985141cc406Sopenharmony_ci  data = buffer + swrite.size;
1986141cc406Sopenharmony_ci  memset (data, 0, size);
1987141cc406Sopenharmony_ci
1988141cc406Sopenharmony_ci  set_command (data, DWNLD_GAMMA_TABLE);
1989141cc406Sopenharmony_ci  set_data_length (data, size - 4);
1990141cc406Sopenharmony_ci
1991141cc406Sopenharmony_ci  data[4] = filter;
1992141cc406Sopenharmony_ci
1993141cc406Sopenharmony_ci  for (i = 0; i < scanner->gamma_length; i++)
1994141cc406Sopenharmony_ci    {
1995141cc406Sopenharmony_ci      if (scanner->device->inquiry_gamma_bits > 8)
1996141cc406Sopenharmony_ci	{
1997141cc406Sopenharmony_ci	  set_data (data, 6 + 2 * i, table ? table[i] : i, 2);
1998141cc406Sopenharmony_ci	}
1999141cc406Sopenharmony_ci      else
2000141cc406Sopenharmony_ci	{
2001141cc406Sopenharmony_ci	  set_data (data, 6 + i, table ? table[i] : i, 1);
2002141cc406Sopenharmony_ci	}
2003141cc406Sopenharmony_ci    }
2004141cc406Sopenharmony_ci
2005141cc406Sopenharmony_ci  DBG_DUMP (DBG_dump, data, 128);
2006141cc406Sopenharmony_ci
2007141cc406Sopenharmony_ci  status =
2008141cc406Sopenharmony_ci    sanei_scsi_cmd (scanner->sfd, buffer, swrite.size + size, NULL, NULL);
2009141cc406Sopenharmony_ci  if (status)
2010141cc406Sopenharmony_ci    {
2011141cc406Sopenharmony_ci      DBG (DBG_error,
2012141cc406Sopenharmony_ci	   "pie_dwnld_gamma_one: write command returned status %s\n",
2013141cc406Sopenharmony_ci	   sane_strstatus (status));
2014141cc406Sopenharmony_ci    }
2015141cc406Sopenharmony_ci
2016141cc406Sopenharmony_ci  free (buffer);
2017141cc406Sopenharmony_ci
2018141cc406Sopenharmony_ci  return status;
2019141cc406Sopenharmony_ci}
2020141cc406Sopenharmony_ci
2021141cc406Sopenharmony_ci/*------------------------- PIE DWNLD GAMMA -----------------------------*/
2022141cc406Sopenharmony_ci
2023141cc406Sopenharmony_cistatic SANE_Status
2024141cc406Sopenharmony_cipie_dwnld_gamma (Pie_Scanner * scanner)
2025141cc406Sopenharmony_ci{
2026141cc406Sopenharmony_ci  SANE_Status status;
2027141cc406Sopenharmony_ci
2028141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_dwnld_gamma\n");
2029141cc406Sopenharmony_ci
2030141cc406Sopenharmony_ci  if (scanner->colormode == RGB)
2031141cc406Sopenharmony_ci    {
2032141cc406Sopenharmony_ci      status =
2033141cc406Sopenharmony_ci	pie_dwnld_gamma_one (scanner, FILTER_RED, scanner->gamma_table[1]);
2034141cc406Sopenharmony_ci      if (status)
2035141cc406Sopenharmony_ci	return status;
2036141cc406Sopenharmony_ci
2037141cc406Sopenharmony_ci
2038141cc406Sopenharmony_ci      status =
2039141cc406Sopenharmony_ci	pie_dwnld_gamma_one (scanner, FILTER_GREEN, scanner->gamma_table[2]);
2040141cc406Sopenharmony_ci      if (status)
2041141cc406Sopenharmony_ci	return status;
2042141cc406Sopenharmony_ci
2043141cc406Sopenharmony_ci      status =
2044141cc406Sopenharmony_ci	pie_dwnld_gamma_one (scanner, FILTER_BLUE, scanner->gamma_table[3]);
2045141cc406Sopenharmony_ci      if (status)
2046141cc406Sopenharmony_ci	return status;
2047141cc406Sopenharmony_ci    }
2048141cc406Sopenharmony_ci  else
2049141cc406Sopenharmony_ci    {
2050141cc406Sopenharmony_ci      SANE_Int *table;
2051141cc406Sopenharmony_ci
2052141cc406Sopenharmony_ci      /* if lineart or half tone, force gamma to be one to one by passing NULL */
2053141cc406Sopenharmony_ci      if (scanner->colormode == GRAYSCALE)
2054141cc406Sopenharmony_ci	table = scanner->gamma_table[0];
2055141cc406Sopenharmony_ci      else
2056141cc406Sopenharmony_ci	table = NULL;
2057141cc406Sopenharmony_ci
2058141cc406Sopenharmony_ci      status = pie_dwnld_gamma_one (scanner, FILTER_GREEN, table);
2059141cc406Sopenharmony_ci      if (status)
2060141cc406Sopenharmony_ci	return status;
2061141cc406Sopenharmony_ci    }
2062141cc406Sopenharmony_ci
2063141cc406Sopenharmony_ci  usleep (DOWNLOAD_GAMMA_WAIT_TIME);
2064141cc406Sopenharmony_ci
2065141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2066141cc406Sopenharmony_ci}
2067141cc406Sopenharmony_ci
2068141cc406Sopenharmony_ci/*------------------------- PIE SET WINDOW -----------------------------*/
2069141cc406Sopenharmony_ci
2070141cc406Sopenharmony_cistatic SANE_Status
2071141cc406Sopenharmony_cipie_set_window (Pie_Scanner * scanner)
2072141cc406Sopenharmony_ci{
2073141cc406Sopenharmony_ci  unsigned char buffer[128];
2074141cc406Sopenharmony_ci  size_t size;
2075141cc406Sopenharmony_ci  SANE_Status status;
2076141cc406Sopenharmony_ci  unsigned char *data;
2077141cc406Sopenharmony_ci  double x, dpmm;
2078141cc406Sopenharmony_ci
2079141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_set_window\n");
2080141cc406Sopenharmony_ci
2081141cc406Sopenharmony_ci  size = 14;
2082141cc406Sopenharmony_ci
2083141cc406Sopenharmony_ci  set_write_length (swrite.cmd, size);
2084141cc406Sopenharmony_ci
2085141cc406Sopenharmony_ci  memcpy (buffer, swrite.cmd, swrite.size);
2086141cc406Sopenharmony_ci
2087141cc406Sopenharmony_ci  data = buffer + swrite.size;
2088141cc406Sopenharmony_ci  memset (data, 0, size);
2089141cc406Sopenharmony_ci
2090141cc406Sopenharmony_ci  set_command (data, SET_SCAN_FRAME);
2091141cc406Sopenharmony_ci  set_data_length (data, size - 4);
2092141cc406Sopenharmony_ci
2093141cc406Sopenharmony_ci  data[4] = 0x80;
2094141cc406Sopenharmony_ci  if (scanner->colormode == HALFTONE)
2095141cc406Sopenharmony_ci    data[4] |= 0x40;
2096141cc406Sopenharmony_ci
2097141cc406Sopenharmony_ci  dpmm = (double) scanner->device->inquiry_pixel_resolution / MM_PER_INCH;
2098141cc406Sopenharmony_ci
2099141cc406Sopenharmony_ci  x = SANE_UNFIX (scanner->val[OPT_TL_X].w) * dpmm;
2100141cc406Sopenharmony_ci  set_data (data, 6, (int) x, 2);
2101141cc406Sopenharmony_ci  DBG (DBG_info, "TL_X: %d\n", (int) x);
2102141cc406Sopenharmony_ci
2103141cc406Sopenharmony_ci  x = SANE_UNFIX (scanner->val[OPT_TL_Y].w) * dpmm;
2104141cc406Sopenharmony_ci  set_data (data, 8, (int) x, 2);
2105141cc406Sopenharmony_ci  DBG (DBG_info, "TL_Y: %d\n", (int) x);
2106141cc406Sopenharmony_ci
2107141cc406Sopenharmony_ci  x = SANE_UNFIX (scanner->val[OPT_BR_X].w) * dpmm;
2108141cc406Sopenharmony_ci  set_data (data, 10, (int) x, 2);
2109141cc406Sopenharmony_ci  DBG (DBG_info, "BR_X: %d\n", (int) x);
2110141cc406Sopenharmony_ci
2111141cc406Sopenharmony_ci  x = SANE_UNFIX (scanner->val[OPT_BR_Y].w) * dpmm;
2112141cc406Sopenharmony_ci  set_data (data, 12, (int) x, 2);
2113141cc406Sopenharmony_ci  DBG (DBG_info, "BR_Y: %d\n", (int) x);
2114141cc406Sopenharmony_ci
2115141cc406Sopenharmony_ci  status =
2116141cc406Sopenharmony_ci    sanei_scsi_cmd (scanner->sfd, buffer, swrite.size + size, NULL, NULL);
2117141cc406Sopenharmony_ci  if (status)
2118141cc406Sopenharmony_ci    {
2119141cc406Sopenharmony_ci      DBG (DBG_error, "pie_set_window: write command returned status %s\n",
2120141cc406Sopenharmony_ci	   sane_strstatus (status));
2121141cc406Sopenharmony_ci    }
2122141cc406Sopenharmony_ci
2123141cc406Sopenharmony_ci  return status;
2124141cc406Sopenharmony_ci}
2125141cc406Sopenharmony_ci
2126141cc406Sopenharmony_ci
2127141cc406Sopenharmony_ci/*------------------------- PIE MODE SELECT -----------------------------*/
2128141cc406Sopenharmony_ci
2129141cc406Sopenharmony_cistatic SANE_Status
2130141cc406Sopenharmony_cipie_mode_select (Pie_Scanner * scanner)
2131141cc406Sopenharmony_ci{
2132141cc406Sopenharmony_ci
2133141cc406Sopenharmony_ci  SANE_Status status;
2134141cc406Sopenharmony_ci  unsigned char buffer[128];
2135141cc406Sopenharmony_ci  size_t size;
2136141cc406Sopenharmony_ci  unsigned char *data;
2137141cc406Sopenharmony_ci  int i;
2138141cc406Sopenharmony_ci
2139141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_mode_select\n");
2140141cc406Sopenharmony_ci
2141141cc406Sopenharmony_ci  size = 14;
2142141cc406Sopenharmony_ci
2143141cc406Sopenharmony_ci  set_mode_length (smode.cmd, size);
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_ci  memcpy (buffer, smode.cmd, smode.size);
2146141cc406Sopenharmony_ci
2147141cc406Sopenharmony_ci  data = buffer + smode.size;
2148141cc406Sopenharmony_ci  memset (data, 0, size);
2149141cc406Sopenharmony_ci
2150141cc406Sopenharmony_ci  /* size of data */
2151141cc406Sopenharmony_ci  data[1] = size - 2;
2152141cc406Sopenharmony_ci
2153141cc406Sopenharmony_ci  /* set resolution required */
2154141cc406Sopenharmony_ci  set_data (data, 2, scanner->resolution, 2);
2155141cc406Sopenharmony_ci
2156141cc406Sopenharmony_ci  /* set color filter and color depth */
2157141cc406Sopenharmony_ci  switch (scanner->colormode)
2158141cc406Sopenharmony_ci    {
2159141cc406Sopenharmony_ci    case RGB:
2160141cc406Sopenharmony_ci      if (scanner->device->inquiry_filters & INQ_ONE_PASS_COLOR)
2161141cc406Sopenharmony_ci	{
2162141cc406Sopenharmony_ci	  data[4] = INQ_ONE_PASS_COLOR;
2163141cc406Sopenharmony_ci	  scanner->cal_filter = FILTER_RED | FILTER_GREEN | FILTER_BLUE;
2164141cc406Sopenharmony_ci	}
2165141cc406Sopenharmony_ci      else
2166141cc406Sopenharmony_ci	{
2167141cc406Sopenharmony_ci	  DBG (DBG_error,
2168141cc406Sopenharmony_ci	       "pie_mode_select: support for multipass color not yet implemented\n");
2169141cc406Sopenharmony_ci	  return SANE_STATUS_UNSUPPORTED;
2170141cc406Sopenharmony_ci	}
2171141cc406Sopenharmony_ci      data[5] = INQ_COLOR_DEPTH_8;
2172141cc406Sopenharmony_ci      break;
2173141cc406Sopenharmony_ci
2174141cc406Sopenharmony_ci    case GRAYSCALE:
2175141cc406Sopenharmony_ci    case LINEART:
2176141cc406Sopenharmony_ci    case HALFTONE:
2177141cc406Sopenharmony_ci      /* choose which filter to use for monochrome mode */
2178141cc406Sopenharmony_ci      if (scanner->device->inquiry_filters & INQ_FILTER_NEUTRAL)
2179141cc406Sopenharmony_ci	{
2180141cc406Sopenharmony_ci	  data[4] = FILTER_NEUTRAL;
2181141cc406Sopenharmony_ci	  scanner->cal_filter = FILTER_NEUTRAL;
2182141cc406Sopenharmony_ci	}
2183141cc406Sopenharmony_ci      else if (scanner->device->inquiry_filters & INQ_FILTER_GREEN)
2184141cc406Sopenharmony_ci	{
2185141cc406Sopenharmony_ci	  data[4] = FILTER_GREEN;
2186141cc406Sopenharmony_ci	  scanner->cal_filter = FILTER_GREEN;
2187141cc406Sopenharmony_ci	}
2188141cc406Sopenharmony_ci      else if (scanner->device->inquiry_filters & INQ_FILTER_RED)
2189141cc406Sopenharmony_ci	{
2190141cc406Sopenharmony_ci	  data[4] = FILTER_RED;
2191141cc406Sopenharmony_ci	  scanner->cal_filter = FILTER_RED;
2192141cc406Sopenharmony_ci	}
2193141cc406Sopenharmony_ci      else if (scanner->device->inquiry_filters & INQ_FILTER_BLUE)
2194141cc406Sopenharmony_ci	{
2195141cc406Sopenharmony_ci	  data[4] = FILTER_BLUE;
2196141cc406Sopenharmony_ci	  scanner->cal_filter = FILTER_BLUE;
2197141cc406Sopenharmony_ci	}
2198141cc406Sopenharmony_ci      else
2199141cc406Sopenharmony_ci	{
2200141cc406Sopenharmony_ci	  DBG (DBG_error,
2201141cc406Sopenharmony_ci	       "pie_mode_select: scanner doesn't appear to support monochrome\n");
2202141cc406Sopenharmony_ci	  return SANE_STATUS_UNSUPPORTED;
2203141cc406Sopenharmony_ci	}
2204141cc406Sopenharmony_ci
2205141cc406Sopenharmony_ci      if (scanner->colormode == GRAYSCALE)
2206141cc406Sopenharmony_ci	data[5] = INQ_COLOR_DEPTH_8;
2207141cc406Sopenharmony_ci      else
2208141cc406Sopenharmony_ci	data[5] = INQ_COLOR_DEPTH_1;
2209141cc406Sopenharmony_ci      break;
2210141cc406Sopenharmony_ci    }
2211141cc406Sopenharmony_ci
2212141cc406Sopenharmony_ci  /* choose color packing method */
2213141cc406Sopenharmony_ci  if (scanner->device->inquiry_color_format & INQ_COLOR_FORMAT_LINE)
2214141cc406Sopenharmony_ci    data[6] = INQ_COLOR_FORMAT_LINE;
2215141cc406Sopenharmony_ci  else if (scanner->device->inquiry_color_format & INQ_COLOR_FORMAT_INDEX)
2216141cc406Sopenharmony_ci    data[6] = INQ_COLOR_FORMAT_INDEX;
2217141cc406Sopenharmony_ci  else
2218141cc406Sopenharmony_ci    {
2219141cc406Sopenharmony_ci      DBG (DBG_error,
2220141cc406Sopenharmony_ci	   "pie_mode_select: support for pixel packing not yet implemented\n");
2221141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
2222141cc406Sopenharmony_ci    }
2223141cc406Sopenharmony_ci
2224141cc406Sopenharmony_ci  /* choose data format */
2225141cc406Sopenharmony_ci  if (scanner->device->inquiry_image_format & INQ_IMG_FMT_INTEL)
2226141cc406Sopenharmony_ci    data[8] = INQ_IMG_FMT_INTEL;
2227141cc406Sopenharmony_ci  else
2228141cc406Sopenharmony_ci    {
2229141cc406Sopenharmony_ci      DBG (DBG_error,
2230141cc406Sopenharmony_ci	   "pie_mode_select: support for Motorola format not yet implemented\n");
2231141cc406Sopenharmony_ci      return SANE_STATUS_UNSUPPORTED;
2232141cc406Sopenharmony_ci    }
2233141cc406Sopenharmony_ci
2234141cc406Sopenharmony_ci  /* set required speed */
2235141cc406Sopenharmony_ci  i = 0;
2236141cc406Sopenharmony_ci  while (scanner->device->speed_list[i] != NULL)
2237141cc406Sopenharmony_ci    {
2238141cc406Sopenharmony_ci      if (strcmp (scanner->device->speed_list[i], scanner->val[OPT_SPEED].s)
2239141cc406Sopenharmony_ci	  == 0)
2240141cc406Sopenharmony_ci	break;
2241141cc406Sopenharmony_ci      i++;
2242141cc406Sopenharmony_ci    }
2243141cc406Sopenharmony_ci
2244141cc406Sopenharmony_ci  if (scanner->device->speed_list[i] == NULL)
2245141cc406Sopenharmony_ci    data[9] = 0;
2246141cc406Sopenharmony_ci  else
2247141cc406Sopenharmony_ci    data[9] = i;
2248141cc406Sopenharmony_ci
2249141cc406Sopenharmony_ci  scanner->cal_mode = CAL_MODE_FLATBED;
2250141cc406Sopenharmony_ci
2251141cc406Sopenharmony_ci  /* if preview supported, ask for preview, limit resolution to max for fast preview */
2252141cc406Sopenharmony_ci  if (scanner->val[OPT_PREVIEW].w
2253141cc406Sopenharmony_ci      && (scanner->device->inquiry_scan_capability & INQ_CAP_FAST_PREVIEW))
2254141cc406Sopenharmony_ci    {
2255141cc406Sopenharmony_ci      DBG (DBG_info, "pie_mode_select: setting preview\n");
2256141cc406Sopenharmony_ci      scanner->cal_mode |= CAL_MODE_PREVIEW;
2257141cc406Sopenharmony_ci      data[9] |= INQ_CAP_FAST_PREVIEW;
2258141cc406Sopenharmony_ci      data[9] &= ~INQ_CAP_SPEEDS;
2259141cc406Sopenharmony_ci      if (scanner->resolution > scanner->device->inquiry_fast_preview_res)
2260141cc406Sopenharmony_ci	set_data (data, 2, scanner->device->inquiry_fast_preview_res, 2);
2261141cc406Sopenharmony_ci    }
2262141cc406Sopenharmony_ci
2263141cc406Sopenharmony_ci
2264141cc406Sopenharmony_ci  /* set required halftone pattern */
2265141cc406Sopenharmony_ci  i = 0;
2266141cc406Sopenharmony_ci  while (scanner->device->halftone_list[i] != NULL)
2267141cc406Sopenharmony_ci    {
2268141cc406Sopenharmony_ci      if (strcmp
2269141cc406Sopenharmony_ci	  (scanner->device->halftone_list[i],
2270141cc406Sopenharmony_ci	   scanner->val[OPT_HALFTONE_PATTERN].s) == 0)
2271141cc406Sopenharmony_ci	break;
2272141cc406Sopenharmony_ci      i++;
2273141cc406Sopenharmony_ci    }
2274141cc406Sopenharmony_ci
2275141cc406Sopenharmony_ci  if (scanner->device->halftone_list[i] == NULL)
2276141cc406Sopenharmony_ci    data[12] = 0;		/* halftone pattern */
2277141cc406Sopenharmony_ci  else
2278141cc406Sopenharmony_ci    data[12] = i;
2279141cc406Sopenharmony_ci
2280141cc406Sopenharmony_ci  data[13] = SANE_UNFIX (scanner->val[OPT_THRESHOLD].w) * 255 / 100;	/* lineart threshold */
2281141cc406Sopenharmony_ci
2282141cc406Sopenharmony_ci  DBG (DBG_info, "pie_mode_select: speed %02x\n", data[9]);
2283141cc406Sopenharmony_ci  DBG (DBG_info, "pie_mode_select: halftone %d\n", data[12]);
2284141cc406Sopenharmony_ci  DBG (DBG_info, "pie_mode_select: threshold %02x\n", data[13]);
2285141cc406Sopenharmony_ci
2286141cc406Sopenharmony_ci  status =
2287141cc406Sopenharmony_ci    sanei_scsi_cmd (scanner->sfd, buffer, smode.size + size, NULL, NULL);
2288141cc406Sopenharmony_ci  if (status)
2289141cc406Sopenharmony_ci    {
2290141cc406Sopenharmony_ci      DBG (DBG_error, "pie_mode_select: write command returned status %s\n",
2291141cc406Sopenharmony_ci	   sane_strstatus (status));
2292141cc406Sopenharmony_ci    }
2293141cc406Sopenharmony_ci
2294141cc406Sopenharmony_ci  return status;
2295141cc406Sopenharmony_ci}
2296141cc406Sopenharmony_ci
2297141cc406Sopenharmony_ci
2298141cc406Sopenharmony_ci/*------------------------- PIE SCAN -----------------------------*/
2299141cc406Sopenharmony_ci
2300141cc406Sopenharmony_cistatic SANE_Status
2301141cc406Sopenharmony_cipie_scan (Pie_Scanner * scanner, int start)
2302141cc406Sopenharmony_ci{
2303141cc406Sopenharmony_ci  SANE_Status status;
2304141cc406Sopenharmony_ci
2305141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_scan\n");
2306141cc406Sopenharmony_ci
2307141cc406Sopenharmony_ci  /* TUR */
2308141cc406Sopenharmony_ci  status = pie_wait_scanner (scanner);
2309141cc406Sopenharmony_ci  if (status)
2310141cc406Sopenharmony_ci    {
2311141cc406Sopenharmony_ci      return status;
2312141cc406Sopenharmony_ci    }
2313141cc406Sopenharmony_ci
2314141cc406Sopenharmony_ci  set_scan_cmd (scan.cmd, start);
2315141cc406Sopenharmony_ci
2316141cc406Sopenharmony_ci  do
2317141cc406Sopenharmony_ci    {
2318141cc406Sopenharmony_ci      status = sanei_scsi_cmd (scanner->sfd, scan.cmd, scan.size, NULL, NULL);
2319141cc406Sopenharmony_ci      if (status)
2320141cc406Sopenharmony_ci	{
2321141cc406Sopenharmony_ci	  DBG (DBG_error, "pie_scan: write command returned status %s\n",
2322141cc406Sopenharmony_ci	       sane_strstatus (status));
2323141cc406Sopenharmony_ci	  usleep (SCAN_WARMUP_WAIT_TIME);
2324141cc406Sopenharmony_ci	}
2325141cc406Sopenharmony_ci    }
2326141cc406Sopenharmony_ci  while (start && status);
2327141cc406Sopenharmony_ci
2328141cc406Sopenharmony_ci  usleep (SCAN_WAIT_TIME);
2329141cc406Sopenharmony_ci
2330141cc406Sopenharmony_ci  return status;
2331141cc406Sopenharmony_ci}
2332141cc406Sopenharmony_ci
2333141cc406Sopenharmony_ci
2334141cc406Sopenharmony_ci/* --------------------------------------- PIE WAIT SCANNER -------------------------- */
2335141cc406Sopenharmony_ci
2336141cc406Sopenharmony_ci
2337141cc406Sopenharmony_cistatic SANE_Status
2338141cc406Sopenharmony_cipie_wait_scanner (Pie_Scanner * scanner)
2339141cc406Sopenharmony_ci{
2340141cc406Sopenharmony_ci  SANE_Status status;
2341141cc406Sopenharmony_ci  int cnt = 0;
2342141cc406Sopenharmony_ci
2343141cc406Sopenharmony_ci  DBG (DBG_proc, "wait_scanner\n");
2344141cc406Sopenharmony_ci
2345141cc406Sopenharmony_ci  do
2346141cc406Sopenharmony_ci    {
2347141cc406Sopenharmony_ci      if (cnt > 100)		/* maximal 100 * 0.5 sec = 50 sec */
2348141cc406Sopenharmony_ci	{
2349141cc406Sopenharmony_ci	  DBG (DBG_warning, "scanner does not get ready\n");
2350141cc406Sopenharmony_ci	  return -1;
2351141cc406Sopenharmony_ci	}
2352141cc406Sopenharmony_ci      /* test unit ready */
2353141cc406Sopenharmony_ci      status =
2354141cc406Sopenharmony_ci	sanei_scsi_cmd (scanner->sfd, test_unit_ready.cmd,
2355141cc406Sopenharmony_ci			test_unit_ready.size, NULL, NULL);
2356141cc406Sopenharmony_ci      cnt++;
2357141cc406Sopenharmony_ci
2358141cc406Sopenharmony_ci      if (status)
2359141cc406Sopenharmony_ci	{
2360141cc406Sopenharmony_ci	  if (cnt == 1)
2361141cc406Sopenharmony_ci	    {
2362141cc406Sopenharmony_ci	      DBG (DBG_info2, "scanner reports %s, waiting ...\n",
2363141cc406Sopenharmony_ci		   sane_strstatus (status));
2364141cc406Sopenharmony_ci	    }
2365141cc406Sopenharmony_ci
2366141cc406Sopenharmony_ci	  usleep (TUR_WAIT_TIME);
2367141cc406Sopenharmony_ci	}
2368141cc406Sopenharmony_ci    }
2369141cc406Sopenharmony_ci  while (status != SANE_STATUS_GOOD);
2370141cc406Sopenharmony_ci
2371141cc406Sopenharmony_ci  DBG (DBG_info, "scanner ready\n");
2372141cc406Sopenharmony_ci
2373141cc406Sopenharmony_ci
2374141cc406Sopenharmony_ci  return status;
2375141cc406Sopenharmony_ci}
2376141cc406Sopenharmony_ci
2377141cc406Sopenharmony_ci
2378141cc406Sopenharmony_ci/* -------------------------------------- PIE GET PARAMS -------------------------- */
2379141cc406Sopenharmony_ci
2380141cc406Sopenharmony_ci
2381141cc406Sopenharmony_cistatic SANE_Status
2382141cc406Sopenharmony_cipie_get_params (Pie_Scanner * scanner)
2383141cc406Sopenharmony_ci{
2384141cc406Sopenharmony_ci  SANE_Status status;
2385141cc406Sopenharmony_ci  size_t size;
2386141cc406Sopenharmony_ci  unsigned char buffer[128];
2387141cc406Sopenharmony_ci
2388141cc406Sopenharmony_ci  DBG (DBG_proc, "pie_get_params\n");
2389141cc406Sopenharmony_ci
2390141cc406Sopenharmony_ci  status = pie_wait_scanner (scanner);
2391141cc406Sopenharmony_ci  if (status)
2392141cc406Sopenharmony_ci    return status;
2393141cc406Sopenharmony_ci
2394141cc406Sopenharmony_ci  if (scanner->device->inquiry_image_format & INQ_IMG_FMT_OKLINE)
2395141cc406Sopenharmony_ci    size = 16;
2396141cc406Sopenharmony_ci  else
2397141cc406Sopenharmony_ci
2398141cc406Sopenharmony_ci    size = 14;
2399141cc406Sopenharmony_ci
2400141cc406Sopenharmony_ci  set_param_length (param.cmd, size);
2401141cc406Sopenharmony_ci
2402141cc406Sopenharmony_ci  status =
2403141cc406Sopenharmony_ci    sanei_scsi_cmd (scanner->sfd, param.cmd, param.size, buffer, &size);
2404141cc406Sopenharmony_ci
2405141cc406Sopenharmony_ci  if (status)
2406141cc406Sopenharmony_ci    {
2407141cc406Sopenharmony_ci      DBG (DBG_error, "pie_get_params: command returned status %s\n",
2408141cc406Sopenharmony_ci	   sane_strstatus (status));
2409141cc406Sopenharmony_ci    }
2410141cc406Sopenharmony_ci  else
2411141cc406Sopenharmony_ci    {
2412141cc406Sopenharmony_ci      DBG (DBG_info, "Scan Width:  %d\n", get_param_scan_width (buffer));
2413141cc406Sopenharmony_ci      DBG (DBG_info, "Scan Lines:  %d\n", get_param_scan_lines (buffer));
2414141cc406Sopenharmony_ci      DBG (DBG_info, "Scan bytes:  %d\n", get_param_scan_bytes (buffer));
2415141cc406Sopenharmony_ci
2416141cc406Sopenharmony_ci      DBG (DBG_info, "Offset 1:    %d\n",
2417141cc406Sopenharmony_ci	   get_param_scan_filter_offset1 (buffer));
2418141cc406Sopenharmony_ci      DBG (DBG_info, "Offset 2:    %d\n",
2419141cc406Sopenharmony_ci	   get_param_scan_filter_offset2 (buffer));
2420141cc406Sopenharmony_ci      DBG (DBG_info, "Scan period: %d\n", get_param_scan_period (buffer));
2421141cc406Sopenharmony_ci      DBG (DBG_info, "Xfer rate:   %d\n", get_param_scsi_xfer_rate (buffer));
2422141cc406Sopenharmony_ci      if (scanner->device->inquiry_image_format & INQ_IMG_FMT_OKLINE)
2423141cc406Sopenharmony_ci	DBG (DBG_info, "Avail lines: %d\n",
2424141cc406Sopenharmony_ci	     get_param_scan_available_lines (buffer));
2425141cc406Sopenharmony_ci
2426141cc406Sopenharmony_ci      scanner->filter_offset1 = get_param_scan_filter_offset1 (buffer);
2427141cc406Sopenharmony_ci      scanner->filter_offset2 = get_param_scan_filter_offset2 (buffer);
2428141cc406Sopenharmony_ci      scanner->bytes_per_line = get_param_scan_bytes (buffer);
2429141cc406Sopenharmony_ci
2430141cc406Sopenharmony_ci      scanner->params.pixels_per_line = get_param_scan_width (buffer);
2431141cc406Sopenharmony_ci      scanner->params.lines = get_param_scan_lines (buffer);
2432141cc406Sopenharmony_ci
2433141cc406Sopenharmony_ci      switch (scanner->colormode)
2434141cc406Sopenharmony_ci	{
2435141cc406Sopenharmony_ci	case RGB:
2436141cc406Sopenharmony_ci	  scanner->params.format = SANE_FRAME_RGB;
2437141cc406Sopenharmony_ci	  scanner->params.depth = 8;
2438141cc406Sopenharmony_ci	  scanner->params.bytes_per_line = 3 * get_param_scan_bytes (buffer);
2439141cc406Sopenharmony_ci	  break;
2440141cc406Sopenharmony_ci
2441141cc406Sopenharmony_ci	case GRAYSCALE:
2442141cc406Sopenharmony_ci	  scanner->params.format = SANE_FRAME_GRAY;
2443141cc406Sopenharmony_ci	  scanner->params.depth = 8;
2444141cc406Sopenharmony_ci	  scanner->params.bytes_per_line = get_param_scan_bytes (buffer);
2445141cc406Sopenharmony_ci	  break;
2446141cc406Sopenharmony_ci
2447141cc406Sopenharmony_ci	case HALFTONE:
2448141cc406Sopenharmony_ci	case LINEART:
2449141cc406Sopenharmony_ci	  scanner->params.format = SANE_FRAME_GRAY;
2450141cc406Sopenharmony_ci	  scanner->params.depth = 1;
2451141cc406Sopenharmony_ci	  scanner->params.bytes_per_line = get_param_scan_bytes (buffer);
2452141cc406Sopenharmony_ci	  break;
2453141cc406Sopenharmony_ci	}
2454141cc406Sopenharmony_ci
2455141cc406Sopenharmony_ci      scanner->params.last_frame = 0;
2456141cc406Sopenharmony_ci    }
2457141cc406Sopenharmony_ci
2458141cc406Sopenharmony_ci  return status;
2459141cc406Sopenharmony_ci}
2460141cc406Sopenharmony_ci
2461141cc406Sopenharmony_ci
2462141cc406Sopenharmony_ci/* -------------------------------------- PIE GRAB SCANNER -------------------------- */
2463141cc406Sopenharmony_ci
2464141cc406Sopenharmony_ci
2465141cc406Sopenharmony_cistatic SANE_Status
2466141cc406Sopenharmony_cipie_grab_scanner (Pie_Scanner * scanner)
2467141cc406Sopenharmony_ci{
2468141cc406Sopenharmony_ci  SANE_Status status;
2469141cc406Sopenharmony_ci
2470141cc406Sopenharmony_ci  DBG (DBG_proc, "grab_scanner\n");
2471141cc406Sopenharmony_ci
2472141cc406Sopenharmony_ci
2473141cc406Sopenharmony_ci  status = pie_wait_scanner (scanner);
2474141cc406Sopenharmony_ci  if (status)
2475141cc406Sopenharmony_ci    return status;
2476141cc406Sopenharmony_ci
2477141cc406Sopenharmony_ci  status =
2478141cc406Sopenharmony_ci    sanei_scsi_cmd (scanner->sfd, reserve_unit.cmd, reserve_unit.size, NULL,
2479141cc406Sopenharmony_ci		    NULL);
2480141cc406Sopenharmony_ci
2481141cc406Sopenharmony_ci
2482141cc406Sopenharmony_ci  if (status)
2483141cc406Sopenharmony_ci    {
2484141cc406Sopenharmony_ci      DBG (DBG_error, "pie_grab_scanner: command returned status %s\n",
2485141cc406Sopenharmony_ci	   sane_strstatus (status));
2486141cc406Sopenharmony_ci    }
2487141cc406Sopenharmony_ci  else
2488141cc406Sopenharmony_ci    {
2489141cc406Sopenharmony_ci      DBG (DBG_info, "scanner reserved\n");
2490141cc406Sopenharmony_ci    }
2491141cc406Sopenharmony_ci
2492141cc406Sopenharmony_ci  return status;
2493141cc406Sopenharmony_ci}
2494141cc406Sopenharmony_ci
2495141cc406Sopenharmony_ci
2496141cc406Sopenharmony_ci/* ------------------------------------ PIE GIVE SCANNER -------------------------- */
2497141cc406Sopenharmony_ci
2498141cc406Sopenharmony_ci
2499141cc406Sopenharmony_cistatic SANE_Status
2500141cc406Sopenharmony_cipie_give_scanner (Pie_Scanner * scanner)
2501141cc406Sopenharmony_ci{
2502141cc406Sopenharmony_ci  SANE_Status status;
2503141cc406Sopenharmony_ci
2504141cc406Sopenharmony_ci  DBG (DBG_info2, "trying to release scanner ...\n");
2505141cc406Sopenharmony_ci
2506141cc406Sopenharmony_ci  status =
2507141cc406Sopenharmony_ci    sanei_scsi_cmd (scanner->sfd, release_unit.cmd, release_unit.size, NULL,
2508141cc406Sopenharmony_ci		    NULL);
2509141cc406Sopenharmony_ci  if (status)
2510141cc406Sopenharmony_ci    {
2511141cc406Sopenharmony_ci      DBG (DBG_error, "pie_give_scanner: command returned status %s\n",
2512141cc406Sopenharmony_ci	   sane_strstatus (status));
2513141cc406Sopenharmony_ci    }
2514141cc406Sopenharmony_ci  else
2515141cc406Sopenharmony_ci    {
2516141cc406Sopenharmony_ci      DBG (DBG_info, "scanner released\n");
2517141cc406Sopenharmony_ci    }
2518141cc406Sopenharmony_ci  return status;
2519141cc406Sopenharmony_ci}
2520141cc406Sopenharmony_ci
2521141cc406Sopenharmony_ci
2522141cc406Sopenharmony_ci/* ------------------- PIE READER PROCESS INDEXED ------------------- */
2523141cc406Sopenharmony_ci
2524141cc406Sopenharmony_cistatic int
2525141cc406Sopenharmony_cipie_reader_process_indexed (Pie_Scanner * scanner, FILE * fp)
2526141cc406Sopenharmony_ci{
2527141cc406Sopenharmony_ci  int status;
2528141cc406Sopenharmony_ci  int lines;
2529141cc406Sopenharmony_ci  unsigned char *buffer, *reorder = NULL;
2530141cc406Sopenharmony_ci  unsigned char *red_buffer = NULL, *green_buffer = NULL;
2531141cc406Sopenharmony_ci  unsigned char *red_in = NULL, *red_out = NULL;
2532141cc406Sopenharmony_ci  unsigned char *green_in = NULL, *green_out = NULL;
2533141cc406Sopenharmony_ci  int red_size = 0, green_size = 0;
2534141cc406Sopenharmony_ci  int bytes_per_line;
2535141cc406Sopenharmony_ci  int red_count = 0, green_count = 0;
2536141cc406Sopenharmony_ci
2537141cc406Sopenharmony_ci  size_t size;
2538141cc406Sopenharmony_ci
2539141cc406Sopenharmony_ci  DBG (DBG_read, "reading %d lines of %d bytes/line (indexed)\n",
2540141cc406Sopenharmony_ci       scanner->params.lines, scanner->params.bytes_per_line);
2541141cc406Sopenharmony_ci
2542141cc406Sopenharmony_ci  lines = scanner->params.lines;
2543141cc406Sopenharmony_ci  bytes_per_line = scanner->bytes_per_line;
2544141cc406Sopenharmony_ci
2545141cc406Sopenharmony_ci  /* allocate receive buffer */
2546141cc406Sopenharmony_ci  buffer = malloc (bytes_per_line + 2);
2547141cc406Sopenharmony_ci  if (!buffer)
2548141cc406Sopenharmony_ci    {
2549141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
2550141cc406Sopenharmony_ci    }
2551141cc406Sopenharmony_ci
2552141cc406Sopenharmony_ci  /* allocate deskew buffers for RGB mode */
2553141cc406Sopenharmony_ci  if (scanner->colormode == RGB)
2554141cc406Sopenharmony_ci    {
2555141cc406Sopenharmony_ci      lines *= 3;
2556141cc406Sopenharmony_ci
2557141cc406Sopenharmony_ci      red_size = bytes_per_line * (scanner->filter_offset1 +
2558141cc406Sopenharmony_ci				   scanner->filter_offset2 + 2);
2559141cc406Sopenharmony_ci      green_size = bytes_per_line * (scanner->filter_offset2 + 2);
2560141cc406Sopenharmony_ci
2561141cc406Sopenharmony_ci      DBG (DBG_info2,
2562141cc406Sopenharmony_ci	   "pie_reader_process_indexed: alloc %d lines (%d bytes) for red buffer\n",
2563141cc406Sopenharmony_ci	   red_size / bytes_per_line, red_size);
2564141cc406Sopenharmony_ci      DBG (DBG_info2,
2565141cc406Sopenharmony_ci	   "pie_reader_process_indexed: alloc %d lines (%d bytes) for green buffer\n",
2566141cc406Sopenharmony_ci	   green_size / bytes_per_line, green_size);
2567141cc406Sopenharmony_ci
2568141cc406Sopenharmony_ci      reorder = malloc (scanner->params.bytes_per_line);
2569141cc406Sopenharmony_ci      red_buffer = malloc (red_size);
2570141cc406Sopenharmony_ci      green_buffer = malloc (green_size);
2571141cc406Sopenharmony_ci
2572141cc406Sopenharmony_ci      if (!reorder || !red_buffer || !green_buffer)
2573141cc406Sopenharmony_ci	{
2574141cc406Sopenharmony_ci	  free (buffer);
2575141cc406Sopenharmony_ci	  free (reorder);
2576141cc406Sopenharmony_ci	  free (red_buffer);
2577141cc406Sopenharmony_ci	  free (green_buffer);
2578141cc406Sopenharmony_ci	  return SANE_STATUS_NO_MEM;
2579141cc406Sopenharmony_ci	}
2580141cc406Sopenharmony_ci
2581141cc406Sopenharmony_ci      red_in = red_out = red_buffer;
2582141cc406Sopenharmony_ci      green_in = green_out = green_buffer;
2583141cc406Sopenharmony_ci    }
2584141cc406Sopenharmony_ci
2585141cc406Sopenharmony_ci  while (lines--)
2586141cc406Sopenharmony_ci    {
2587141cc406Sopenharmony_ci      set_read_length (sread.cmd, 1);
2588141cc406Sopenharmony_ci      size = bytes_per_line + 2;
2589141cc406Sopenharmony_ci
2590141cc406Sopenharmony_ci      do
2591141cc406Sopenharmony_ci	{
2592141cc406Sopenharmony_ci	  status =
2593141cc406Sopenharmony_ci	    sanei_scsi_cmd (scanner->sfd, sread.cmd, sread.size, buffer,
2594141cc406Sopenharmony_ci			    &size);
2595141cc406Sopenharmony_ci	}
2596141cc406Sopenharmony_ci      while (status);
2597141cc406Sopenharmony_ci
2598141cc406Sopenharmony_ci      DBG_DUMP (DBG_dump, buffer, 64);
2599141cc406Sopenharmony_ci
2600141cc406Sopenharmony_ci      if (scanner->colormode == RGB)
2601141cc406Sopenharmony_ci	{
2602141cc406Sopenharmony_ci	  /* we're assuming that we get red before green before blue here */
2603141cc406Sopenharmony_ci	  switch (*buffer)
2604141cc406Sopenharmony_ci	    {
2605141cc406Sopenharmony_ci	    case 'R':
2606141cc406Sopenharmony_ci	      /* copy to red buffer */
2607141cc406Sopenharmony_ci	      memcpy (red_in, buffer + 2, bytes_per_line);
2608141cc406Sopenharmony_ci
2609141cc406Sopenharmony_ci	      /* advance in pointer, and check for wrap */
2610141cc406Sopenharmony_ci	      red_in += bytes_per_line;
2611141cc406Sopenharmony_ci	      if (red_in >= (red_buffer + red_size))
2612141cc406Sopenharmony_ci		red_in = red_buffer;
2613141cc406Sopenharmony_ci
2614141cc406Sopenharmony_ci	      /* increment red line count */
2615141cc406Sopenharmony_ci	      red_count++;
2616141cc406Sopenharmony_ci	      DBG (DBG_info2,
2617141cc406Sopenharmony_ci		   "pie_reader_process_indexed: got a red line (%d)\n",
2618141cc406Sopenharmony_ci		   red_count);
2619141cc406Sopenharmony_ci	      break;
2620141cc406Sopenharmony_ci
2621141cc406Sopenharmony_ci	    case 'G':
2622141cc406Sopenharmony_ci	      /* copy to green buffer */
2623141cc406Sopenharmony_ci	      memcpy (green_in, buffer + 2, bytes_per_line);
2624141cc406Sopenharmony_ci
2625141cc406Sopenharmony_ci	      /* advance in pointer, and check for wrap */
2626141cc406Sopenharmony_ci	      green_in += bytes_per_line;
2627141cc406Sopenharmony_ci	      if (green_in >= (green_buffer + green_size))
2628141cc406Sopenharmony_ci		green_in = green_buffer;
2629141cc406Sopenharmony_ci
2630141cc406Sopenharmony_ci	      /* increment green line count */
2631141cc406Sopenharmony_ci	      green_count++;
2632141cc406Sopenharmony_ci	      DBG (DBG_info2,
2633141cc406Sopenharmony_ci		   "pie_reader_process_indexed: got a green line (%d)\n",
2634141cc406Sopenharmony_ci		   green_count);
2635141cc406Sopenharmony_ci	      break;
2636141cc406Sopenharmony_ci
2637141cc406Sopenharmony_ci	    case 'B':
2638141cc406Sopenharmony_ci	      /* check we actually have red and green data available */
2639141cc406Sopenharmony_ci	      if (!red_count || !green_count)
2640141cc406Sopenharmony_ci		{
2641141cc406Sopenharmony_ci		  DBG (DBG_error,
2642141cc406Sopenharmony_ci		       "pie_reader_process_indexed: deskew buffer empty (%d %d)\n",
2643141cc406Sopenharmony_ci		       red_count, green_count);
2644141cc406Sopenharmony_ci		  return SANE_STATUS_INVAL;
2645141cc406Sopenharmony_ci		}
2646141cc406Sopenharmony_ci	      red_count--;
2647141cc406Sopenharmony_ci	      green_count--;
2648141cc406Sopenharmony_ci
2649141cc406Sopenharmony_ci	      DBG (DBG_info2,
2650141cc406Sopenharmony_ci		   "pie_reader_process_indexed: got a blue line\n");
2651141cc406Sopenharmony_ci
2652141cc406Sopenharmony_ci	      {
2653141cc406Sopenharmony_ci		int i;
2654141cc406Sopenharmony_ci		unsigned char *red, *green, *blue, *dest;
2655141cc406Sopenharmony_ci
2656141cc406Sopenharmony_ci		/* now pack the pixels lines into RGB format */
2657141cc406Sopenharmony_ci		dest = reorder;
2658141cc406Sopenharmony_ci		red = red_out;
2659141cc406Sopenharmony_ci		green = green_out;
2660141cc406Sopenharmony_ci		blue = buffer + 2;
2661141cc406Sopenharmony_ci
2662141cc406Sopenharmony_ci		for (i = bytes_per_line; i > 0; i--)
2663141cc406Sopenharmony_ci		  {
2664141cc406Sopenharmony_ci		    *dest++ = *red++;
2665141cc406Sopenharmony_ci		    *dest++ = *green++;
2666141cc406Sopenharmony_ci		    *dest++ = *blue++;
2667141cc406Sopenharmony_ci		  }
2668141cc406Sopenharmony_ci		fwrite (reorder, 1, scanner->params.bytes_per_line, fp);
2669141cc406Sopenharmony_ci
2670141cc406Sopenharmony_ci		/* advance out pointers, and check for wrap */
2671141cc406Sopenharmony_ci		red_out += bytes_per_line;
2672141cc406Sopenharmony_ci		if (red_out >= (red_buffer + red_size))
2673141cc406Sopenharmony_ci		  red_out = red_buffer;
2674141cc406Sopenharmony_ci		green_out += bytes_per_line;
2675141cc406Sopenharmony_ci		if (green_out >= (green_buffer + green_size))
2676141cc406Sopenharmony_ci		  green_out = green_buffer;
2677141cc406Sopenharmony_ci	      }
2678141cc406Sopenharmony_ci	      break;
2679141cc406Sopenharmony_ci
2680141cc406Sopenharmony_ci	    default:
2681141cc406Sopenharmony_ci	      DBG (DBG_error,
2682141cc406Sopenharmony_ci		   "pie_reader_process_indexed: bad filter index\n");
2683141cc406Sopenharmony_ci	    }
2684141cc406Sopenharmony_ci	}
2685141cc406Sopenharmony_ci      else
2686141cc406Sopenharmony_ci	{
2687141cc406Sopenharmony_ci	  DBG (DBG_info2,
2688141cc406Sopenharmony_ci	       "pie_reader_process_indexed: got a line (%lu bytes)\n", (u_long) size);
2689141cc406Sopenharmony_ci
2690141cc406Sopenharmony_ci	  /* just send the data on, assume filter bytes not present as per calibration case */
2691141cc406Sopenharmony_ci	  fwrite (buffer, 1, scanner->params.bytes_per_line, fp);
2692141cc406Sopenharmony_ci	}
2693141cc406Sopenharmony_ci    }
2694141cc406Sopenharmony_ci
2695141cc406Sopenharmony_ci  free (buffer);
2696141cc406Sopenharmony_ci  free (reorder);
2697141cc406Sopenharmony_ci  free (red_buffer);
2698141cc406Sopenharmony_ci  free (green_buffer);
2699141cc406Sopenharmony_ci  return 0;
2700141cc406Sopenharmony_ci}
2701141cc406Sopenharmony_ci
2702141cc406Sopenharmony_ci/* --------------------------------- PIE READER PROCESS ------------------------ */
2703141cc406Sopenharmony_ci
2704141cc406Sopenharmony_cistatic int
2705141cc406Sopenharmony_cipie_reader_process (Pie_Scanner * scanner, FILE * fp)
2706141cc406Sopenharmony_ci{
2707141cc406Sopenharmony_ci  int status;
2708141cc406Sopenharmony_ci  int lines;
2709141cc406Sopenharmony_ci  unsigned char *buffer, *reorder;
2710141cc406Sopenharmony_ci  size_t size;
2711141cc406Sopenharmony_ci
2712141cc406Sopenharmony_ci  DBG (DBG_read, "reading %d lines of %d bytes/line\n", scanner->params.lines,
2713141cc406Sopenharmony_ci       scanner->params.bytes_per_line);
2714141cc406Sopenharmony_ci
2715141cc406Sopenharmony_ci  buffer = malloc (scanner->params.bytes_per_line);
2716141cc406Sopenharmony_ci  reorder = malloc (scanner->params.bytes_per_line);
2717141cc406Sopenharmony_ci  if (!buffer || !reorder)
2718141cc406Sopenharmony_ci    {
2719141cc406Sopenharmony_ci      free (buffer);
2720141cc406Sopenharmony_ci      free (reorder);
2721141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
2722141cc406Sopenharmony_ci    }
2723141cc406Sopenharmony_ci
2724141cc406Sopenharmony_ci  lines = scanner->params.lines;
2725141cc406Sopenharmony_ci
2726141cc406Sopenharmony_ci  while (lines--)
2727141cc406Sopenharmony_ci    {
2728141cc406Sopenharmony_ci      set_read_length (sread.cmd, 1);
2729141cc406Sopenharmony_ci      size = scanner->params.bytes_per_line;
2730141cc406Sopenharmony_ci
2731141cc406Sopenharmony_ci      do
2732141cc406Sopenharmony_ci	{
2733141cc406Sopenharmony_ci	  status =
2734141cc406Sopenharmony_ci	    sanei_scsi_cmd (scanner->sfd, sread.cmd, sread.size, buffer,
2735141cc406Sopenharmony_ci			    &size);
2736141cc406Sopenharmony_ci	}
2737141cc406Sopenharmony_ci      while (status);
2738141cc406Sopenharmony_ci
2739141cc406Sopenharmony_ci      DBG_DUMP (DBG_dump, buffer, 64);
2740141cc406Sopenharmony_ci
2741141cc406Sopenharmony_ci      if (scanner->colormode == RGB)
2742141cc406Sopenharmony_ci	{
2743141cc406Sopenharmony_ci	  int i;
2744141cc406Sopenharmony_ci	  unsigned char *src, *dest;
2745141cc406Sopenharmony_ci	  int offset;
2746141cc406Sopenharmony_ci
2747141cc406Sopenharmony_ci	  dest = reorder;
2748141cc406Sopenharmony_ci	  src = buffer;
2749141cc406Sopenharmony_ci	  offset = scanner->params.pixels_per_line;
2750141cc406Sopenharmony_ci
2751141cc406Sopenharmony_ci	  for (i = scanner->params.pixels_per_line; i > 0; i--)
2752141cc406Sopenharmony_ci	    {
2753141cc406Sopenharmony_ci	      *dest++ = *src;
2754141cc406Sopenharmony_ci	      *dest++ = *(src + offset);
2755141cc406Sopenharmony_ci	      *dest++ = *(src + 2 * offset);
2756141cc406Sopenharmony_ci	      src++;
2757141cc406Sopenharmony_ci	    }
2758141cc406Sopenharmony_ci	  fwrite (reorder, 1, scanner->params.bytes_per_line, fp);
2759141cc406Sopenharmony_ci	}
2760141cc406Sopenharmony_ci      else
2761141cc406Sopenharmony_ci	{
2762141cc406Sopenharmony_ci	  fwrite (buffer, 1, scanner->params.bytes_per_line, fp);
2763141cc406Sopenharmony_ci	}
2764141cc406Sopenharmony_ci
2765141cc406Sopenharmony_ci      fflush (fp);
2766141cc406Sopenharmony_ci    }
2767141cc406Sopenharmony_ci
2768141cc406Sopenharmony_ci  free (buffer);
2769141cc406Sopenharmony_ci  free (reorder);
2770141cc406Sopenharmony_ci
2771141cc406Sopenharmony_ci  return 0;
2772141cc406Sopenharmony_ci}
2773141cc406Sopenharmony_ci
2774141cc406Sopenharmony_ci
2775141cc406Sopenharmony_ci
2776141cc406Sopenharmony_ci/* --------------------------------- READER PROCESS SIGTERM HANDLER  ------------ */
2777141cc406Sopenharmony_ci
2778141cc406Sopenharmony_ci
2779141cc406Sopenharmony_cistatic void
2780141cc406Sopenharmony_cireader_process_sigterm_handler (int signal)
2781141cc406Sopenharmony_ci{
2782141cc406Sopenharmony_ci  DBG (DBG_sane_info, "reader_process: terminated by signal %d\n", signal);
2783141cc406Sopenharmony_ci
2784141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
2785141cc406Sopenharmony_ci  sanei_scsi_req_flush_all ();	/* flush SCSI queue */
2786141cc406Sopenharmony_ci#else
2787141cc406Sopenharmony_ci  sanei_scsi_req_flush_all ();	/* flush SCSI queue */
2788141cc406Sopenharmony_ci#endif
2789141cc406Sopenharmony_ci
2790141cc406Sopenharmony_ci  _exit (SANE_STATUS_GOOD);
2791141cc406Sopenharmony_ci}
2792141cc406Sopenharmony_ci
2793141cc406Sopenharmony_ci
2794141cc406Sopenharmony_ci
2795141cc406Sopenharmony_ci/* ------------------------------ READER PROCESS ----------------------------- */
2796141cc406Sopenharmony_ci
2797141cc406Sopenharmony_ci
2798141cc406Sopenharmony_cistatic int
2799141cc406Sopenharmony_cireader_process ( void *data )	/* executed as a child process */
2800141cc406Sopenharmony_ci{
2801141cc406Sopenharmony_ci  int status;
2802141cc406Sopenharmony_ci  FILE *fp;
2803141cc406Sopenharmony_ci  Pie_Scanner * scanner;
2804141cc406Sopenharmony_ci  sigset_t ignore_set;
2805141cc406Sopenharmony_ci  struct SIGACTION act;
2806141cc406Sopenharmony_ci
2807141cc406Sopenharmony_ci  scanner = (Pie_Scanner *)data;
2808141cc406Sopenharmony_ci
2809141cc406Sopenharmony_ci  if (sanei_thread_is_forked ()) {
2810141cc406Sopenharmony_ci
2811141cc406Sopenharmony_ci      close ( scanner->pipe );
2812141cc406Sopenharmony_ci
2813141cc406Sopenharmony_ci      sigfillset (&ignore_set);
2814141cc406Sopenharmony_ci      sigdelset (&ignore_set, SIGTERM);
2815141cc406Sopenharmony_ci#if defined (__APPLE__) && defined (__MACH__)
2816141cc406Sopenharmony_ci      sigdelset (&ignore_set, SIGUSR2);
2817141cc406Sopenharmony_ci#endif
2818141cc406Sopenharmony_ci      sigprocmask (SIG_SETMASK, &ignore_set, 0);
2819141cc406Sopenharmony_ci
2820141cc406Sopenharmony_ci      memset (&act, 0, sizeof (act));
2821141cc406Sopenharmony_ci      sigaction (SIGTERM, &act, 0);
2822141cc406Sopenharmony_ci  }
2823141cc406Sopenharmony_ci
2824141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "reader_process started\n");
2825141cc406Sopenharmony_ci
2826141cc406Sopenharmony_ci  memset (&act, 0, sizeof (act));	/* define SIGTERM-handler */
2827141cc406Sopenharmony_ci  act.sa_handler = reader_process_sigterm_handler;
2828141cc406Sopenharmony_ci  sigaction (SIGTERM, &act, 0);
2829141cc406Sopenharmony_ci
2830141cc406Sopenharmony_ci  fp = fdopen (scanner->reader_fds, "w");
2831141cc406Sopenharmony_ci  if (!fp)
2832141cc406Sopenharmony_ci    {
2833141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
2834141cc406Sopenharmony_ci    }
2835141cc406Sopenharmony_ci
2836141cc406Sopenharmony_ci  DBG (DBG_sane_info, "reader_process: starting to READ data\n");
2837141cc406Sopenharmony_ci
2838141cc406Sopenharmony_ci  if (scanner->device->inquiry_color_format & INQ_COLOR_FORMAT_LINE)
2839141cc406Sopenharmony_ci    status = pie_reader_process (scanner, fp);
2840141cc406Sopenharmony_ci  else if (scanner->device->inquiry_color_format & INQ_COLOR_FORMAT_INDEX)
2841141cc406Sopenharmony_ci    status = pie_reader_process_indexed (scanner, fp);
2842141cc406Sopenharmony_ci  else
2843141cc406Sopenharmony_ci    status = SANE_STATUS_UNSUPPORTED;
2844141cc406Sopenharmony_ci
2845141cc406Sopenharmony_ci  fclose (fp);
2846141cc406Sopenharmony_ci
2847141cc406Sopenharmony_ci  DBG (DBG_sane_info, "reader_process: finished reading data\n");
2848141cc406Sopenharmony_ci
2849141cc406Sopenharmony_ci  return status;
2850141cc406Sopenharmony_ci}
2851141cc406Sopenharmony_ci
2852141cc406Sopenharmony_ci
2853141cc406Sopenharmony_ci/* -------------------------------- ATTACH_ONE ---------------------------------- */
2854141cc406Sopenharmony_ci
2855141cc406Sopenharmony_ci
2856141cc406Sopenharmony_ci/* callback function for sanei_config_attach_matching_devices(dev_name, attach_one) */
2857141cc406Sopenharmony_cistatic SANE_Status
2858141cc406Sopenharmony_ciattach_one (const char *name)
2859141cc406Sopenharmony_ci{
2860141cc406Sopenharmony_ci  attach_scanner (name, 0);
2861141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2862141cc406Sopenharmony_ci}
2863141cc406Sopenharmony_ci
2864141cc406Sopenharmony_ci
2865141cc406Sopenharmony_ci/* ----------------------------- CLOSE PIPE ---------------------------------- */
2866141cc406Sopenharmony_ci
2867141cc406Sopenharmony_ci
2868141cc406Sopenharmony_cistatic SANE_Status
2869141cc406Sopenharmony_ciclose_pipe (Pie_Scanner * scanner)
2870141cc406Sopenharmony_ci{
2871141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "close_pipe\n");
2872141cc406Sopenharmony_ci
2873141cc406Sopenharmony_ci  if (scanner->pipe >= 0)
2874141cc406Sopenharmony_ci    {
2875141cc406Sopenharmony_ci      close (scanner->pipe);
2876141cc406Sopenharmony_ci      scanner->pipe = -1;
2877141cc406Sopenharmony_ci    }
2878141cc406Sopenharmony_ci
2879141cc406Sopenharmony_ci  return SANE_STATUS_EOF;
2880141cc406Sopenharmony_ci}
2881141cc406Sopenharmony_ci
2882141cc406Sopenharmony_ci
2883141cc406Sopenharmony_ci
2884141cc406Sopenharmony_ci/* ---------------------------- DO CANCEL ---------------------------------- */
2885141cc406Sopenharmony_ci
2886141cc406Sopenharmony_ci
2887141cc406Sopenharmony_cistatic SANE_Status
2888141cc406Sopenharmony_cido_cancel (Pie_Scanner * scanner)
2889141cc406Sopenharmony_ci{
2890141cc406Sopenharmony_ci  DBG (DBG_sane_proc, "do_cancel\n");
2891141cc406Sopenharmony_ci
2892141cc406Sopenharmony_ci  scanner->scanning = SANE_FALSE;
2893141cc406Sopenharmony_ci
2894141cc406Sopenharmony_ci  if (sanei_thread_is_valid (scanner->reader_pid))
2895141cc406Sopenharmony_ci    {
2896141cc406Sopenharmony_ci      DBG (DBG_sane_info, "killing reader_process\n");
2897141cc406Sopenharmony_ci      sanei_thread_kill (scanner->reader_pid);
2898141cc406Sopenharmony_ci      sanei_thread_waitpid (scanner->reader_pid, 0);
2899141cc406Sopenharmony_ci      sanei_thread_invalidate (scanner->reader_pid);
2900141cc406Sopenharmony_ci      DBG (DBG_sane_info, "reader_process killed\n");
2901141cc406Sopenharmony_ci    }
2902141cc406Sopenharmony_ci
2903141cc406Sopenharmony_ci  if (scanner->sfd >= 0)
2904141cc406Sopenharmony_ci    {
2905141cc406Sopenharmony_ci      pie_scan (scanner, 0);
2906141cc406Sopenharmony_ci
2907141cc406Sopenharmony_ci      pie_power_save (scanner, 15);
2908141cc406Sopenharmony_ci
2909141cc406Sopenharmony_ci      pie_give_scanner (scanner);	/* reposition and release scanner */
2910141cc406Sopenharmony_ci
2911141cc406Sopenharmony_ci      DBG (DBG_sane_info, "closing scannerdevice filedescriptor\n");
2912141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
2913141cc406Sopenharmony_ci      scanner->sfd = -1;
2914141cc406Sopenharmony_ci    }
2915141cc406Sopenharmony_ci
2916141cc406Sopenharmony_ci  return SANE_STATUS_CANCELLED;
2917141cc406Sopenharmony_ci}
2918141cc406Sopenharmony_ci
2919141cc406Sopenharmony_ci
2920141cc406Sopenharmony_ci
2921141cc406Sopenharmony_ci/* --------------------------------------- SANE INIT ---------------------------------- */
2922141cc406Sopenharmony_ci
2923141cc406Sopenharmony_ci
2924141cc406Sopenharmony_ciSANE_Status
2925141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize)
2926141cc406Sopenharmony_ci{
2927141cc406Sopenharmony_ci  char dev_name[PATH_MAX];
2928141cc406Sopenharmony_ci  size_t len;
2929141cc406Sopenharmony_ci  FILE *fp;
2930141cc406Sopenharmony_ci
2931141cc406Sopenharmony_ci  DBG_INIT ();
2932141cc406Sopenharmony_ci
2933141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_init() build %d\n", BUILD);
2934141cc406Sopenharmony_ci
2935141cc406Sopenharmony_ci  if (version_code)
2936141cc406Sopenharmony_ci    *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
2937141cc406Sopenharmony_ci
2938141cc406Sopenharmony_ci  fp = sanei_config_open (PIE_CONFIG_FILE);
2939141cc406Sopenharmony_ci  if (!fp)
2940141cc406Sopenharmony_ci    {
2941141cc406Sopenharmony_ci      attach_scanner ("/dev/scanner", 0);	/* no config-file: /dev/scanner */
2942141cc406Sopenharmony_ci      return SANE_STATUS_GOOD;
2943141cc406Sopenharmony_ci    }
2944141cc406Sopenharmony_ci
2945141cc406Sopenharmony_ci  while (sanei_config_read (dev_name, sizeof (dev_name), fp))
2946141cc406Sopenharmony_ci    {
2947141cc406Sopenharmony_ci      if (dev_name[0] == '#')
2948141cc406Sopenharmony_ci	{
2949141cc406Sopenharmony_ci	  continue;
2950141cc406Sopenharmony_ci	}			/* ignore line comments */
2951141cc406Sopenharmony_ci
2952141cc406Sopenharmony_ci      len = strlen (dev_name);
2953141cc406Sopenharmony_ci
2954141cc406Sopenharmony_ci      if (!len)			/* ignore empty lines */
2955141cc406Sopenharmony_ci	{
2956141cc406Sopenharmony_ci	  continue;
2957141cc406Sopenharmony_ci	}
2958141cc406Sopenharmony_ci
2959141cc406Sopenharmony_ci      sanei_config_attach_matching_devices (dev_name, attach_one);
2960141cc406Sopenharmony_ci    }
2961141cc406Sopenharmony_ci
2962141cc406Sopenharmony_ci  fclose (fp);
2963141cc406Sopenharmony_ci
2964141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
2965141cc406Sopenharmony_ci}
2966141cc406Sopenharmony_ci
2967141cc406Sopenharmony_ci
2968141cc406Sopenharmony_ci/* ----------------------------------------- SANE EXIT ---------------------------------- */
2969141cc406Sopenharmony_ci
2970141cc406Sopenharmony_ci
2971141cc406Sopenharmony_civoid
2972141cc406Sopenharmony_cisane_exit (void)
2973141cc406Sopenharmony_ci{
2974141cc406Sopenharmony_ci  Pie_Device *dev, *next;
2975141cc406Sopenharmony_ci  int i;
2976141cc406Sopenharmony_ci
2977141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_exit()\n");
2978141cc406Sopenharmony_ci
2979141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = next)
2980141cc406Sopenharmony_ci    {
2981141cc406Sopenharmony_ci      next = dev->next;
2982141cc406Sopenharmony_ci      free (dev->devicename);
2983141cc406Sopenharmony_ci      free (dev->cal_info);
2984141cc406Sopenharmony_ci      i = 0;
2985141cc406Sopenharmony_ci      while (dev->halftone_list[i] != NULL)
2986141cc406Sopenharmony_ci	free (dev->halftone_list[i++]);
2987141cc406Sopenharmony_ci      i = 0;
2988141cc406Sopenharmony_ci      while (dev->speed_list[i] != NULL)
2989141cc406Sopenharmony_ci	free (dev->speed_list[i++]);
2990141cc406Sopenharmony_ci
2991141cc406Sopenharmony_ci      free (dev);
2992141cc406Sopenharmony_ci    }
2993141cc406Sopenharmony_ci
2994141cc406Sopenharmony_ci  first_dev = NULL;
2995141cc406Sopenharmony_ci
2996141cc406Sopenharmony_ci  if (devlist)
2997141cc406Sopenharmony_ci    {
2998141cc406Sopenharmony_ci      free (devlist);
2999141cc406Sopenharmony_ci      devlist = NULL;
3000141cc406Sopenharmony_ci    }
3001141cc406Sopenharmony_ci}
3002141cc406Sopenharmony_ci
3003141cc406Sopenharmony_ci
3004141cc406Sopenharmony_ci/* ------------------------------------------ SANE GET DEVICES --------------------------- */
3005141cc406Sopenharmony_ci
3006141cc406Sopenharmony_ci
3007141cc406Sopenharmony_ciSANE_Status
3008141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool __sane_unused__ local_only)
3009141cc406Sopenharmony_ci{
3010141cc406Sopenharmony_ci  Pie_Device *dev;
3011141cc406Sopenharmony_ci  int i;
3012141cc406Sopenharmony_ci
3013141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_get_devices\n");
3014141cc406Sopenharmony_ci
3015141cc406Sopenharmony_ci  i = 0;
3016141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
3017141cc406Sopenharmony_ci    i++;
3018141cc406Sopenharmony_ci
3019141cc406Sopenharmony_ci  if (devlist)
3020141cc406Sopenharmony_ci    {
3021141cc406Sopenharmony_ci      free (devlist);
3022141cc406Sopenharmony_ci    }
3023141cc406Sopenharmony_ci
3024141cc406Sopenharmony_ci  devlist = malloc ((i + 1) * sizeof (devlist[0]));
3025141cc406Sopenharmony_ci  if (!devlist)
3026141cc406Sopenharmony_ci    {
3027141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
3028141cc406Sopenharmony_ci    }
3029141cc406Sopenharmony_ci
3030141cc406Sopenharmony_ci  i = 0;
3031141cc406Sopenharmony_ci
3032141cc406Sopenharmony_ci  for (dev = first_dev; dev; dev = dev->next)
3033141cc406Sopenharmony_ci    {
3034141cc406Sopenharmony_ci      devlist[i++] = &dev->sane;
3035141cc406Sopenharmony_ci    }
3036141cc406Sopenharmony_ci
3037141cc406Sopenharmony_ci  devlist[i] = NULL;
3038141cc406Sopenharmony_ci
3039141cc406Sopenharmony_ci  *device_list = devlist;
3040141cc406Sopenharmony_ci
3041141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3042141cc406Sopenharmony_ci}
3043141cc406Sopenharmony_ci
3044141cc406Sopenharmony_ci
3045141cc406Sopenharmony_ci/* --------------------------------------- SANE OPEN ---------------------------------- */
3046141cc406Sopenharmony_ci
3047141cc406Sopenharmony_ciSANE_Status
3048141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
3049141cc406Sopenharmony_ci{
3050141cc406Sopenharmony_ci  Pie_Device *dev;
3051141cc406Sopenharmony_ci  SANE_Status status;
3052141cc406Sopenharmony_ci  Pie_Scanner *scanner;
3053141cc406Sopenharmony_ci  int i, j;
3054141cc406Sopenharmony_ci
3055141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_open(%s)\n", devicename);
3056141cc406Sopenharmony_ci
3057141cc406Sopenharmony_ci  if (devicename[0])		/* search for devicename */
3058141cc406Sopenharmony_ci    {
3059141cc406Sopenharmony_ci      for (dev = first_dev; dev; dev = dev->next)
3060141cc406Sopenharmony_ci	{
3061141cc406Sopenharmony_ci	  if (strcmp (dev->sane.name, devicename) == 0)
3062141cc406Sopenharmony_ci	    {
3063141cc406Sopenharmony_ci	      break;
3064141cc406Sopenharmony_ci	    }
3065141cc406Sopenharmony_ci	}
3066141cc406Sopenharmony_ci
3067141cc406Sopenharmony_ci      if (!dev)
3068141cc406Sopenharmony_ci	{
3069141cc406Sopenharmony_ci	  status = attach_scanner (devicename, &dev);
3070141cc406Sopenharmony_ci	  if (status != SANE_STATUS_GOOD)
3071141cc406Sopenharmony_ci	    {
3072141cc406Sopenharmony_ci	      return status;
3073141cc406Sopenharmony_ci	    }
3074141cc406Sopenharmony_ci	}
3075141cc406Sopenharmony_ci    }
3076141cc406Sopenharmony_ci  else
3077141cc406Sopenharmony_ci    {
3078141cc406Sopenharmony_ci      dev = first_dev;		/* empty devicename -> use first device */
3079141cc406Sopenharmony_ci    }
3080141cc406Sopenharmony_ci
3081141cc406Sopenharmony_ci
3082141cc406Sopenharmony_ci  if (!dev)
3083141cc406Sopenharmony_ci    {
3084141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3085141cc406Sopenharmony_ci    }
3086141cc406Sopenharmony_ci
3087141cc406Sopenharmony_ci  scanner = malloc (sizeof (*scanner));
3088141cc406Sopenharmony_ci  if (!scanner)
3089141cc406Sopenharmony_ci
3090141cc406Sopenharmony_ci    {
3091141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
3092141cc406Sopenharmony_ci    }
3093141cc406Sopenharmony_ci
3094141cc406Sopenharmony_ci  memset (scanner, 0, sizeof (*scanner));
3095141cc406Sopenharmony_ci
3096141cc406Sopenharmony_ci  scanner->device = dev;
3097141cc406Sopenharmony_ci  scanner->sfd = -1;
3098141cc406Sopenharmony_ci  scanner->pipe = -1;
3099141cc406Sopenharmony_ci
3100141cc406Sopenharmony_ci  scanner->gamma_length = 1 << (scanner->device->inquiry_gamma_bits);
3101141cc406Sopenharmony_ci
3102141cc406Sopenharmony_ci  DBG (DBG_sane_info, "Using %d bits for gamma input\n",
3103141cc406Sopenharmony_ci       scanner->device->inquiry_gamma_bits);
3104141cc406Sopenharmony_ci
3105141cc406Sopenharmony_ci  scanner->gamma_range.min = 0;
3106141cc406Sopenharmony_ci  scanner->gamma_range.max = scanner->gamma_length - 1;
3107141cc406Sopenharmony_ci  scanner->gamma_range.quant = 0;
3108141cc406Sopenharmony_ci
3109141cc406Sopenharmony_ci  scanner->gamma_table[0] =
3110141cc406Sopenharmony_ci    (SANE_Int *) malloc (scanner->gamma_length * sizeof (SANE_Int));
3111141cc406Sopenharmony_ci  scanner->gamma_table[1] =
3112141cc406Sopenharmony_ci    (SANE_Int *) malloc (scanner->gamma_length * sizeof (SANE_Int));
3113141cc406Sopenharmony_ci  scanner->gamma_table[2] =
3114141cc406Sopenharmony_ci    (SANE_Int *) malloc (scanner->gamma_length * sizeof (SANE_Int));
3115141cc406Sopenharmony_ci  scanner->gamma_table[3] =
3116141cc406Sopenharmony_ci    (SANE_Int *) malloc (scanner->gamma_length * sizeof (SANE_Int));
3117141cc406Sopenharmony_ci
3118141cc406Sopenharmony_ci  for (i = 0; i < 4; ++i)	/* gamma_table[0,1,2,3] */
3119141cc406Sopenharmony_ci    {
3120141cc406Sopenharmony_ci      for (j = 0; j < scanner->gamma_length; ++j)
3121141cc406Sopenharmony_ci	{
3122141cc406Sopenharmony_ci	  scanner->gamma_table[i][j] = j;
3123141cc406Sopenharmony_ci	}
3124141cc406Sopenharmony_ci    }
3125141cc406Sopenharmony_ci
3126141cc406Sopenharmony_ci  init_options (scanner);
3127141cc406Sopenharmony_ci
3128141cc406Sopenharmony_ci  scanner->next = first_handle;	/* insert newly opened handle into list of open handles: */
3129141cc406Sopenharmony_ci  first_handle = scanner;
3130141cc406Sopenharmony_ci
3131141cc406Sopenharmony_ci  *handle = scanner;
3132141cc406Sopenharmony_ci
3133141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3134141cc406Sopenharmony_ci}
3135141cc406Sopenharmony_ci
3136141cc406Sopenharmony_ci
3137141cc406Sopenharmony_ci/* ------------------------------------ SANE CLOSE --------------------------------- */
3138141cc406Sopenharmony_ci
3139141cc406Sopenharmony_ci
3140141cc406Sopenharmony_civoid
3141141cc406Sopenharmony_cisane_close (SANE_Handle handle)
3142141cc406Sopenharmony_ci{
3143141cc406Sopenharmony_ci  Pie_Scanner *prev, *scanner;
3144141cc406Sopenharmony_ci
3145141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_close\n");
3146141cc406Sopenharmony_ci
3147141cc406Sopenharmony_ci  /* remove handle from list of open handles: */
3148141cc406Sopenharmony_ci  prev = 0;
3149141cc406Sopenharmony_ci
3150141cc406Sopenharmony_ci  for (scanner = first_handle; scanner; scanner = scanner->next)
3151141cc406Sopenharmony_ci    {
3152141cc406Sopenharmony_ci      if (scanner == handle)
3153141cc406Sopenharmony_ci	{
3154141cc406Sopenharmony_ci	  break;
3155141cc406Sopenharmony_ci	}
3156141cc406Sopenharmony_ci
3157141cc406Sopenharmony_ci      prev = scanner;
3158141cc406Sopenharmony_ci    }
3159141cc406Sopenharmony_ci
3160141cc406Sopenharmony_ci  if (!scanner)
3161141cc406Sopenharmony_ci    {
3162141cc406Sopenharmony_ci      DBG (DBG_error, "close: invalid handle %p\n", handle);
3163141cc406Sopenharmony_ci      return;			/* oops, not a handle we know about */
3164141cc406Sopenharmony_ci    }
3165141cc406Sopenharmony_ci
3166141cc406Sopenharmony_ci  if (scanner->scanning)	/* stop scan if still scanning */
3167141cc406Sopenharmony_ci    {
3168141cc406Sopenharmony_ci      do_cancel (handle);
3169141cc406Sopenharmony_ci    }
3170141cc406Sopenharmony_ci
3171141cc406Sopenharmony_ci  if (prev)
3172141cc406Sopenharmony_ci    {
3173141cc406Sopenharmony_ci      prev->next = scanner->next;
3174141cc406Sopenharmony_ci    }
3175141cc406Sopenharmony_ci  else
3176141cc406Sopenharmony_ci    {
3177141cc406Sopenharmony_ci      first_handle = scanner->next;
3178141cc406Sopenharmony_ci    }
3179141cc406Sopenharmony_ci
3180141cc406Sopenharmony_ci  free (scanner->gamma_table[0]);	/* free custom gamma tables */
3181141cc406Sopenharmony_ci  free (scanner->gamma_table[1]);
3182141cc406Sopenharmony_ci  free (scanner->gamma_table[2]);
3183141cc406Sopenharmony_ci  free (scanner->gamma_table[3]);
3184141cc406Sopenharmony_ci  free (scanner->val[OPT_MODE].s);
3185141cc406Sopenharmony_ci  free (scanner->val[OPT_SPEED].s);
3186141cc406Sopenharmony_ci  free (scanner->val[OPT_HALFTONE_PATTERN].s);
3187141cc406Sopenharmony_ci
3188141cc406Sopenharmony_ci  scanner->bufsize = 0;
3189141cc406Sopenharmony_ci
3190141cc406Sopenharmony_ci  free (scanner);		/* free scanner */
3191141cc406Sopenharmony_ci}
3192141cc406Sopenharmony_ci
3193141cc406Sopenharmony_ci
3194141cc406Sopenharmony_ci/* ---------------------------------- SANE GET OPTION DESCRIPTOR ----------------- */
3195141cc406Sopenharmony_ci
3196141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
3197141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
3198141cc406Sopenharmony_ci{
3199141cc406Sopenharmony_ci  Pie_Scanner *scanner = handle;
3200141cc406Sopenharmony_ci
3201141cc406Sopenharmony_ci  DBG (DBG_sane_option, "sane_get_option_descriptor %d\n", option);
3202141cc406Sopenharmony_ci
3203141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
3204141cc406Sopenharmony_ci    {
3205141cc406Sopenharmony_ci      return 0;
3206141cc406Sopenharmony_ci    }
3207141cc406Sopenharmony_ci
3208141cc406Sopenharmony_ci  return scanner->opt + option;
3209141cc406Sopenharmony_ci}
3210141cc406Sopenharmony_ci
3211141cc406Sopenharmony_ci
3212141cc406Sopenharmony_ci/* ---------------------------------- SANE CONTROL OPTION ------------------------ */
3213141cc406Sopenharmony_ci
3214141cc406Sopenharmony_ci
3215141cc406Sopenharmony_ciSANE_Status
3216141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action,
3217141cc406Sopenharmony_ci		     void *val, SANE_Int * info)
3218141cc406Sopenharmony_ci{
3219141cc406Sopenharmony_ci  Pie_Scanner *scanner = handle;
3220141cc406Sopenharmony_ci  SANE_Status status;
3221141cc406Sopenharmony_ci  SANE_Word cap;
3222141cc406Sopenharmony_ci  SANE_String_Const name;
3223141cc406Sopenharmony_ci
3224141cc406Sopenharmony_ci  if (info)
3225141cc406Sopenharmony_ci    {
3226141cc406Sopenharmony_ci      *info = 0;
3227141cc406Sopenharmony_ci    }
3228141cc406Sopenharmony_ci
3229141cc406Sopenharmony_ci  if (scanner->scanning)
3230141cc406Sopenharmony_ci    {
3231141cc406Sopenharmony_ci      return SANE_STATUS_DEVICE_BUSY;
3232141cc406Sopenharmony_ci    }
3233141cc406Sopenharmony_ci
3234141cc406Sopenharmony_ci  if ((unsigned) option >= NUM_OPTIONS)
3235141cc406Sopenharmony_ci    {
3236141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3237141cc406Sopenharmony_ci    }
3238141cc406Sopenharmony_ci
3239141cc406Sopenharmony_ci  cap = scanner->opt[option].cap;
3240141cc406Sopenharmony_ci  if (!SANE_OPTION_IS_ACTIVE (cap))
3241141cc406Sopenharmony_ci    {
3242141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3243141cc406Sopenharmony_ci    }
3244141cc406Sopenharmony_ci
3245141cc406Sopenharmony_ci  name = scanner->opt[option].name;
3246141cc406Sopenharmony_ci  if (!name)
3247141cc406Sopenharmony_ci    {
3248141cc406Sopenharmony_ci      name = "(no name)";
3249141cc406Sopenharmony_ci    }
3250141cc406Sopenharmony_ci
3251141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE)
3252141cc406Sopenharmony_ci    {
3253141cc406Sopenharmony_ci
3254141cc406Sopenharmony_ci      DBG (DBG_sane_option, "get %s [#%d]\n", name, option);
3255141cc406Sopenharmony_ci
3256141cc406Sopenharmony_ci      switch (option)
3257141cc406Sopenharmony_ci	{
3258141cc406Sopenharmony_ci	  /* word options: */
3259141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
3260141cc406Sopenharmony_ci	case OPT_RESOLUTION:
3261141cc406Sopenharmony_ci	case OPT_TL_X:
3262141cc406Sopenharmony_ci	case OPT_TL_Y:
3263141cc406Sopenharmony_ci	case OPT_BR_X:
3264141cc406Sopenharmony_ci	case OPT_BR_Y:
3265141cc406Sopenharmony_ci	case OPT_PREVIEW:
3266141cc406Sopenharmony_ci	case OPT_THRESHOLD:
3267141cc406Sopenharmony_ci	  *(SANE_Word *) val = scanner->val[option].w;
3268141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3269141cc406Sopenharmony_ci
3270141cc406Sopenharmony_ci	  /* word-array options: */
3271141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
3272141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
3273141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
3274141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
3275141cc406Sopenharmony_ci	  memcpy (val, scanner->val[option].wa, scanner->opt[option].size);
3276141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3277141cc406Sopenharmony_ci
3278141cc406Sopenharmony_ci#if 0
3279141cc406Sopenharmony_ci	  /* string options: */
3280141cc406Sopenharmony_ci	case OPT_SOURCE:
3281141cc406Sopenharmony_ci#endif
3282141cc406Sopenharmony_ci	case OPT_MODE:
3283141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
3284141cc406Sopenharmony_ci	case OPT_SPEED:
3285141cc406Sopenharmony_ci	  strcpy (val, scanner->val[option].s);
3286141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3287141cc406Sopenharmony_ci	}
3288141cc406Sopenharmony_ci    }
3289141cc406Sopenharmony_ci  else if (action == SANE_ACTION_SET_VALUE)
3290141cc406Sopenharmony_ci    {
3291141cc406Sopenharmony_ci      switch (scanner->opt[option].type)
3292141cc406Sopenharmony_ci	{
3293141cc406Sopenharmony_ci	case SANE_TYPE_INT:
3294141cc406Sopenharmony_ci	  DBG (DBG_sane_option, "set %s [#%d] to %d\n", name, option,
3295141cc406Sopenharmony_ci	       *(SANE_Word *) val);
3296141cc406Sopenharmony_ci	  break;
3297141cc406Sopenharmony_ci
3298141cc406Sopenharmony_ci	case SANE_TYPE_FIXED:
3299141cc406Sopenharmony_ci	  DBG (DBG_sane_option, "set %s [#%d] to %f\n", name, option,
3300141cc406Sopenharmony_ci	       SANE_UNFIX (*(SANE_Word *) val));
3301141cc406Sopenharmony_ci	  break;
3302141cc406Sopenharmony_ci
3303141cc406Sopenharmony_ci	case SANE_TYPE_STRING:
3304141cc406Sopenharmony_ci	  DBG (DBG_sane_option, "set %s [#%d] to %s\n", name, option,
3305141cc406Sopenharmony_ci	       (char *) val);
3306141cc406Sopenharmony_ci	  break;
3307141cc406Sopenharmony_ci
3308141cc406Sopenharmony_ci	case SANE_TYPE_BOOL:
3309141cc406Sopenharmony_ci	  DBG (DBG_sane_option, "set %s [#%d] to %d\n", name, option,
3310141cc406Sopenharmony_ci	       *(SANE_Word *) val);
3311141cc406Sopenharmony_ci	  break;
3312141cc406Sopenharmony_ci
3313141cc406Sopenharmony_ci	default:
3314141cc406Sopenharmony_ci	  DBG (DBG_sane_option, "set %s [#%d]\n", name, option);
3315141cc406Sopenharmony_ci	}
3316141cc406Sopenharmony_ci
3317141cc406Sopenharmony_ci      if (!SANE_OPTION_IS_SETTABLE (cap))
3318141cc406Sopenharmony_ci	{
3319141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
3320141cc406Sopenharmony_ci	}
3321141cc406Sopenharmony_ci
3322141cc406Sopenharmony_ci      status = sanei_constrain_value (scanner->opt + option, val, info);
3323141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
3324141cc406Sopenharmony_ci	{
3325141cc406Sopenharmony_ci	  return status;
3326141cc406Sopenharmony_ci	}
3327141cc406Sopenharmony_ci
3328141cc406Sopenharmony_ci      switch (option)
3329141cc406Sopenharmony_ci	{
3330141cc406Sopenharmony_ci	  /* (mostly) side-effect-free word options: */
3331141cc406Sopenharmony_ci	case OPT_RESOLUTION:
3332141cc406Sopenharmony_ci	case OPT_TL_X:
3333141cc406Sopenharmony_ci	case OPT_TL_Y:
3334141cc406Sopenharmony_ci	case OPT_BR_X:
3335141cc406Sopenharmony_ci	case OPT_BR_Y:
3336141cc406Sopenharmony_ci	  if (info)
3337141cc406Sopenharmony_ci	    {
3338141cc406Sopenharmony_ci	      *info |= SANE_INFO_RELOAD_PARAMS;
3339141cc406Sopenharmony_ci	    }
3340141cc406Sopenharmony_ci	  /* fall through */
3341141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
3342141cc406Sopenharmony_ci	case OPT_PREVIEW:
3343141cc406Sopenharmony_ci	case OPT_THRESHOLD:
3344141cc406Sopenharmony_ci	  scanner->val[option].w = *(SANE_Word *) val;
3345141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3346141cc406Sopenharmony_ci
3347141cc406Sopenharmony_ci	  /* side-effect-free word-array options: */
3348141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR:
3349141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
3350141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
3351141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
3352141cc406Sopenharmony_ci	  memcpy (scanner->val[option].wa, val, scanner->opt[option].size);
3353141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3354141cc406Sopenharmony_ci
3355141cc406Sopenharmony_ci	  /* options with side-effects: */
3356141cc406Sopenharmony_ci
3357141cc406Sopenharmony_ci	case OPT_MODE:
3358141cc406Sopenharmony_ci	  {
3359141cc406Sopenharmony_ci	    int halftoning;
3360141cc406Sopenharmony_ci
3361141cc406Sopenharmony_ci	    if (scanner->val[option].s)
3362141cc406Sopenharmony_ci	      {
3363141cc406Sopenharmony_ci		free (scanner->val[option].s);
3364141cc406Sopenharmony_ci	      }
3365141cc406Sopenharmony_ci
3366141cc406Sopenharmony_ci	    scanner->val[option].s = (SANE_Char *) strdup (val);
3367141cc406Sopenharmony_ci
3368141cc406Sopenharmony_ci	    if (info)
3369141cc406Sopenharmony_ci	      {
3370141cc406Sopenharmony_ci		*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
3371141cc406Sopenharmony_ci	      }
3372141cc406Sopenharmony_ci
3373141cc406Sopenharmony_ci	    scanner->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE;
3374141cc406Sopenharmony_ci
3375141cc406Sopenharmony_ci
3376141cc406Sopenharmony_ci	    scanner->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
3377141cc406Sopenharmony_ci	    scanner->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
3378141cc406Sopenharmony_ci	    scanner->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
3379141cc406Sopenharmony_ci	    scanner->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
3380141cc406Sopenharmony_ci	    scanner->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
3381141cc406Sopenharmony_ci
3382141cc406Sopenharmony_ci	    halftoning = (strcmp (val, HALFTONE_STR) == 0);
3383141cc406Sopenharmony_ci
3384141cc406Sopenharmony_ci	    if (halftoning || strcmp (val, LINEART_STR) == 0)
3385141cc406Sopenharmony_ci	      {			/* one bit modes */
3386141cc406Sopenharmony_ci		if (halftoning)
3387141cc406Sopenharmony_ci		  {		/* halftoning modes */
3388141cc406Sopenharmony_ci		    scanner->opt[OPT_HALFTONE_PATTERN].cap &=
3389141cc406Sopenharmony_ci		      ~SANE_CAP_INACTIVE;
3390141cc406Sopenharmony_ci		  }
3391141cc406Sopenharmony_ci		else
3392141cc406Sopenharmony_ci		  {		/* lineart modes */
3393141cc406Sopenharmony_ci		  }
3394141cc406Sopenharmony_ci		scanner->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
3395141cc406Sopenharmony_ci	      }
3396141cc406Sopenharmony_ci	    else
3397141cc406Sopenharmony_ci	      {			/* multi-bit modes(gray or color) */
3398141cc406Sopenharmony_ci	      }
3399141cc406Sopenharmony_ci
3400141cc406Sopenharmony_ci	    if ((strcmp (val, LINEART_STR) == 0)
3401141cc406Sopenharmony_ci		|| (strcmp (val, HALFTONE_STR) == 0)
3402141cc406Sopenharmony_ci		|| (strcmp (val, GRAY_STR) == 0))
3403141cc406Sopenharmony_ci	      {
3404141cc406Sopenharmony_ci		scanner->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
3405141cc406Sopenharmony_ci	      }
3406141cc406Sopenharmony_ci	    else if (strcmp (val, COLOR_STR) == 0)
3407141cc406Sopenharmony_ci	      {
3408141cc406Sopenharmony_ci		/* scanner->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; */
3409141cc406Sopenharmony_ci		scanner->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
3410141cc406Sopenharmony_ci		scanner->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
3411141cc406Sopenharmony_ci		scanner->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
3412141cc406Sopenharmony_ci	      }
3413141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
3414141cc406Sopenharmony_ci	  }
3415141cc406Sopenharmony_ci
3416141cc406Sopenharmony_ci	case OPT_SPEED:
3417141cc406Sopenharmony_ci	case OPT_HALFTONE_PATTERN:
3418141cc406Sopenharmony_ci	  {
3419141cc406Sopenharmony_ci	    if (scanner->val[option].s)
3420141cc406Sopenharmony_ci	      {
3421141cc406Sopenharmony_ci		free (scanner->val[option].s);
3422141cc406Sopenharmony_ci	      }
3423141cc406Sopenharmony_ci
3424141cc406Sopenharmony_ci	    scanner->val[option].s = (SANE_Char *) strdup (val);
3425141cc406Sopenharmony_ci
3426141cc406Sopenharmony_ci	    return SANE_STATUS_GOOD;
3427141cc406Sopenharmony_ci	  }
3428141cc406Sopenharmony_ci	}
3429141cc406Sopenharmony_ci    }				/* else */
3430141cc406Sopenharmony_ci  return SANE_STATUS_INVAL;
3431141cc406Sopenharmony_ci}
3432141cc406Sopenharmony_ci
3433141cc406Sopenharmony_ci
3434141cc406Sopenharmony_ci/* ------------------------------------ SANE GET PARAMETERS ------------------------ */
3435141cc406Sopenharmony_ci
3436141cc406Sopenharmony_ci
3437141cc406Sopenharmony_ciSANE_Status
3438141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
3439141cc406Sopenharmony_ci{
3440141cc406Sopenharmony_ci  Pie_Scanner *scanner = handle;
3441141cc406Sopenharmony_ci  const char *mode;
3442141cc406Sopenharmony_ci
3443141cc406Sopenharmony_ci  DBG (DBG_sane_info, "sane_get_parameters\n");
3444141cc406Sopenharmony_ci
3445141cc406Sopenharmony_ci  if (!scanner->scanning)
3446141cc406Sopenharmony_ci    {				/* not scanning, so lets use recent values */
3447141cc406Sopenharmony_ci      double width, length, x_dpi, y_dpi;
3448141cc406Sopenharmony_ci
3449141cc406Sopenharmony_ci      memset (&scanner->params, 0, sizeof (scanner->params));
3450141cc406Sopenharmony_ci
3451141cc406Sopenharmony_ci      width =
3452141cc406Sopenharmony_ci	SANE_UNFIX (scanner->val[OPT_BR_X].w - scanner->val[OPT_TL_X].w);
3453141cc406Sopenharmony_ci      length =
3454141cc406Sopenharmony_ci	SANE_UNFIX (scanner->val[OPT_BR_Y].w - scanner->val[OPT_TL_Y].w);
3455141cc406Sopenharmony_ci      x_dpi = SANE_UNFIX (scanner->val[OPT_RESOLUTION].w);
3456141cc406Sopenharmony_ci      y_dpi = x_dpi;
3457141cc406Sopenharmony_ci
3458141cc406Sopenharmony_ci#if 0
3459141cc406Sopenharmony_ci      if ((scanner->val[OPT_RESOLUTION_BIND].w == SANE_TRUE)
3460141cc406Sopenharmony_ci	  || (scanner->val[OPT_PREVIEW].w == SANE_TRUE))
3461141cc406Sopenharmony_ci	{
3462141cc406Sopenharmony_ci	  y_dpi = x_dpi;
3463141cc406Sopenharmony_ci	}
3464141cc406Sopenharmony_ci#endif
3465141cc406Sopenharmony_ci      if (x_dpi > 0.0 && y_dpi > 0.0 && width > 0.0 && length > 0.0)
3466141cc406Sopenharmony_ci	{
3467141cc406Sopenharmony_ci	  double x_dots_per_mm = x_dpi / MM_PER_INCH;
3468141cc406Sopenharmony_ci	  double y_dots_per_mm = y_dpi / MM_PER_INCH;
3469141cc406Sopenharmony_ci
3470141cc406Sopenharmony_ci	  scanner->params.pixels_per_line = width * x_dots_per_mm;
3471141cc406Sopenharmony_ci	  scanner->params.lines = length * y_dots_per_mm;
3472141cc406Sopenharmony_ci	}
3473141cc406Sopenharmony_ci    }
3474141cc406Sopenharmony_ci
3475141cc406Sopenharmony_ci  mode = scanner->val[OPT_MODE].s;
3476141cc406Sopenharmony_ci
3477141cc406Sopenharmony_ci  if (strcmp (mode, LINEART_STR) == 0 || strcmp (mode, HALFTONE_STR) == 0)
3478141cc406Sopenharmony_ci    {
3479141cc406Sopenharmony_ci      scanner->params.format = SANE_FRAME_GRAY;
3480141cc406Sopenharmony_ci      scanner->params.bytes_per_line =
3481141cc406Sopenharmony_ci	(scanner->params.pixels_per_line + 7) / 8;
3482141cc406Sopenharmony_ci      scanner->params.depth = 1;
3483141cc406Sopenharmony_ci    }
3484141cc406Sopenharmony_ci  else if (strcmp (mode, GRAY_STR) == 0)
3485141cc406Sopenharmony_ci    {
3486141cc406Sopenharmony_ci      scanner->params.format = SANE_FRAME_GRAY;
3487141cc406Sopenharmony_ci      scanner->params.bytes_per_line = scanner->params.pixels_per_line;
3488141cc406Sopenharmony_ci      scanner->params.depth = 8;
3489141cc406Sopenharmony_ci    }
3490141cc406Sopenharmony_ci  else				/* RGB */
3491141cc406Sopenharmony_ci    {
3492141cc406Sopenharmony_ci      scanner->params.format = SANE_FRAME_RGB;
3493141cc406Sopenharmony_ci      scanner->params.bytes_per_line = 3 * scanner->params.pixels_per_line;
3494141cc406Sopenharmony_ci      scanner->params.depth = 8;
3495141cc406Sopenharmony_ci    }
3496141cc406Sopenharmony_ci
3497141cc406Sopenharmony_ci  scanner->params.last_frame = (scanner->params.format != SANE_FRAME_RED
3498141cc406Sopenharmony_ci				&& scanner->params.format !=
3499141cc406Sopenharmony_ci				SANE_FRAME_GREEN);
3500141cc406Sopenharmony_ci
3501141cc406Sopenharmony_ci  if (params)
3502141cc406Sopenharmony_ci    {
3503141cc406Sopenharmony_ci      *params = scanner->params;
3504141cc406Sopenharmony_ci    }
3505141cc406Sopenharmony_ci
3506141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3507141cc406Sopenharmony_ci}
3508141cc406Sopenharmony_ci
3509141cc406Sopenharmony_ci
3510141cc406Sopenharmony_ci/* ----------------------------------------- SANE START --------------------------------- */
3511141cc406Sopenharmony_ci
3512141cc406Sopenharmony_ci
3513141cc406Sopenharmony_ciSANE_Status
3514141cc406Sopenharmony_cisane_start (SANE_Handle handle)
3515141cc406Sopenharmony_ci{
3516141cc406Sopenharmony_ci  Pie_Scanner *scanner = handle;
3517141cc406Sopenharmony_ci  int fds[2];
3518141cc406Sopenharmony_ci  const char *mode;
3519141cc406Sopenharmony_ci  int status;
3520141cc406Sopenharmony_ci
3521141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_start\n");
3522141cc406Sopenharmony_ci
3523141cc406Sopenharmony_ci  /* Check for inconsistencies */
3524141cc406Sopenharmony_ci
3525141cc406Sopenharmony_ci  if (scanner->val[OPT_TL_X].w > scanner->val[OPT_BR_X].w)
3526141cc406Sopenharmony_ci    {
3527141cc406Sopenharmony_ci      DBG (0, "sane_start: %s (%.1f mm) is bigger than %s (%.1f mm) "
3528141cc406Sopenharmony_ci              "-- aborting\n",
3529141cc406Sopenharmony_ci              scanner->opt[OPT_TL_X].title, SANE_UNFIX (scanner->val[OPT_TL_X].w),
3530141cc406Sopenharmony_ci              scanner->opt[OPT_BR_X].title, SANE_UNFIX (scanner->val[OPT_BR_X].w));
3531141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3532141cc406Sopenharmony_ci    }
3533141cc406Sopenharmony_ci  if (scanner->val[OPT_TL_Y].w > scanner->val[OPT_BR_Y].w)
3534141cc406Sopenharmony_ci    {
3535141cc406Sopenharmony_ci      DBG (0, "sane_start: %s (%.1f mm) is bigger than %s (%.1f mm) "
3536141cc406Sopenharmony_ci	      "-- aborting\n",
3537141cc406Sopenharmony_ci	      scanner->opt[OPT_TL_Y].title, SANE_UNFIX (scanner->val[OPT_TL_Y].w),
3538141cc406Sopenharmony_ci	      scanner->opt[OPT_BR_Y].title, SANE_UNFIX (scanner->val[OPT_BR_Y].w));
3539141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3540141cc406Sopenharmony_ci    }
3541141cc406Sopenharmony_ci
3542141cc406Sopenharmony_ci  mode = scanner->val[OPT_MODE].s;
3543141cc406Sopenharmony_ci
3544141cc406Sopenharmony_ci  if (scanner->sfd < 0)		/* first call, don`t run this routine again on multi frame or multi image scan */
3545141cc406Sopenharmony_ci    {
3546141cc406Sopenharmony_ci#ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED
3547141cc406Sopenharmony_ci      int scsi_bufsize = 131072;	/* 128KB */
3548141cc406Sopenharmony_ci
3549141cc406Sopenharmony_ci      if (sanei_scsi_open_extended
3550141cc406Sopenharmony_ci	  (scanner->device->sane.name, &(scanner->sfd), sense_handler,
3551141cc406Sopenharmony_ci	   scanner->device, &scsi_bufsize) != 0)
3552141cc406Sopenharmony_ci
3553141cc406Sopenharmony_ci	{
3554141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_start: open failed\n");
3555141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
3556141cc406Sopenharmony_ci	}
3557141cc406Sopenharmony_ci
3558141cc406Sopenharmony_ci      if (scsi_bufsize < 32768)	/* < 32KB */
3559141cc406Sopenharmony_ci	{
3560141cc406Sopenharmony_ci	  DBG (DBG_error,
3561141cc406Sopenharmony_ci	       "sane_start: sanei_scsi_open_extended returned too small scsi buffer (%d)\n",
3562141cc406Sopenharmony_ci	       scsi_bufsize);
3563141cc406Sopenharmony_ci	  sanei_scsi_close ((scanner->sfd));
3564141cc406Sopenharmony_ci	  return SANE_STATUS_NO_MEM;
3565141cc406Sopenharmony_ci	}
3566141cc406Sopenharmony_ci      DBG (DBG_info,
3567141cc406Sopenharmony_ci	   "sane_start: sanei_scsi_open_extended returned scsi buffer size = %d\n",
3568141cc406Sopenharmony_ci	   scsi_bufsize);
3569141cc406Sopenharmony_ci
3570141cc406Sopenharmony_ci
3571141cc406Sopenharmony_ci      scanner->bufsize = scsi_bufsize;
3572141cc406Sopenharmony_ci#else
3573141cc406Sopenharmony_ci      if (sanei_scsi_open
3574141cc406Sopenharmony_ci	  (scanner->device->sane.name, &(scanner->sfd), sense_handler,
3575141cc406Sopenharmony_ci	   scanner->device) != SANE_STATUS_GOOD)
3576141cc406Sopenharmony_ci	{
3577141cc406Sopenharmony_ci	  DBG (DBG_error, "sane_start: open of %s failed:\n",
3578141cc406Sopenharmony_ci	       scanner->device->sane.name);
3579141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
3580141cc406Sopenharmony_ci	}
3581141cc406Sopenharmony_ci
3582141cc406Sopenharmony_ci      /* there is no need to reallocate the buffer because the size is fixed */
3583141cc406Sopenharmony_ci#endif
3584141cc406Sopenharmony_ci
3585141cc406Sopenharmony_ci#if 0
3586141cc406Sopenharmony_ci      if (pie_check_values (scanner->device) != 0)
3587141cc406Sopenharmony_ci	{
3588141cc406Sopenharmony_ci	  DBG (DBG_error, "ERROR: invalid scan-values\n");
3589141cc406Sopenharmony_ci	  scanner->scanning = SANE_FALSE;
3590141cc406Sopenharmony_ci	  pie_give_scanner (scanner);	/* reposition and release scanner */
3591141cc406Sopenharmony_ci	  sanei_scsi_close (scanner->sfd);
3592141cc406Sopenharmony_ci	  scanner->sfd = -1;
3593141cc406Sopenharmony_ci	  return SANE_STATUS_INVAL;
3594141cc406Sopenharmony_ci	}
3595141cc406Sopenharmony_ci#endif
3596141cc406Sopenharmony_ci#if 0
3597141cc406Sopenharmony_ci      scanner->params.bytes_per_line = scanner->device->row_len;
3598141cc406Sopenharmony_ci      scanner->params.pixels_per_line = scanner->device->width_in_pixels;
3599141cc406Sopenharmony_ci      scanner->params.lines = scanner->device->length_in_pixels;
3600141cc406Sopenharmony_ci
3601141cc406Sopenharmony_ci      sane_get_parameters (scanner, 0);
3602141cc406Sopenharmony_ci
3603141cc406Sopenharmony_ci      DBG (DBG_sane_info, "x_resolution (dpi)      = %u\n",
3604141cc406Sopenharmony_ci	   scanner->device->x_resolution);
3605141cc406Sopenharmony_ci      DBG (DBG_sane_info, "y_resolution (dpi)      = %u\n",
3606141cc406Sopenharmony_ci	   scanner->device->y_resolution);
3607141cc406Sopenharmony_ci      DBG (DBG_sane_info, "x_coordinate_base (dpi) = %u\n",
3608141cc406Sopenharmony_ci	   scanner->device->x_coordinate_base);
3609141cc406Sopenharmony_ci      DBG (DBG_sane_info, "y_coordinate_base (dpi) = %u\n",
3610141cc406Sopenharmony_ci	   scanner->device->y_coordinate_base);
3611141cc406Sopenharmony_ci      DBG (DBG_sane_info, "upper_left_x (xbase)    = %d\n",
3612141cc406Sopenharmony_ci	   scanner->device->upper_left_x);
3613141cc406Sopenharmony_ci      DBG (DBG_sane_info, "upper_left_y (ybase)    = %d\n",
3614141cc406Sopenharmony_ci	   scanner->device->upper_left_y);
3615141cc406Sopenharmony_ci      DBG (DBG_sane_info, "scanwidth    (xbase)    = %u\n",
3616141cc406Sopenharmony_ci	   scanner->device->scanwidth);
3617141cc406Sopenharmony_ci      DBG (DBG_sane_info, "scanlength   (ybase)    = %u\n",
3618141cc406Sopenharmony_ci	   scanner->device->scanlength);
3619141cc406Sopenharmony_ci      DBG (DBG_sane_info, "width in pixels         = %u\n",
3620141cc406Sopenharmony_ci	   scanner->device->width_in_pixels);
3621141cc406Sopenharmony_ci      DBG (DBG_sane_info, "length in pixels        = %u\n",
3622141cc406Sopenharmony_ci	   scanner->device->length_in_pixels);
3623141cc406Sopenharmony_ci      DBG (DBG_sane_info, "bits per pixel/color    = %u\n",
3624141cc406Sopenharmony_ci	   scanner->device->bits_per_pixel);
3625141cc406Sopenharmony_ci      DBG (DBG_sane_info, "bytes per line          = %d\n",
3626141cc406Sopenharmony_ci	   scanner->params.bytes_per_line);
3627141cc406Sopenharmony_ci      DBG (DBG_sane_info, "pixels_per_line         = %d\n",
3628141cc406Sopenharmony_ci	   scanner->params.pixels_per_line);
3629141cc406Sopenharmony_ci      DBG (DBG_sane_info, "lines                   = %d\n",
3630141cc406Sopenharmony_ci	   scanner->params.lines);
3631141cc406Sopenharmony_ci#endif
3632141cc406Sopenharmony_ci
3633141cc406Sopenharmony_ci      /* grab scanner */
3634141cc406Sopenharmony_ci      if (pie_grab_scanner (scanner))
3635141cc406Sopenharmony_ci	{
3636141cc406Sopenharmony_ci	  sanei_scsi_close (scanner->sfd);
3637141cc406Sopenharmony_ci	  scanner->sfd = -1;
3638141cc406Sopenharmony_ci	  DBG (DBG_warning,
3639141cc406Sopenharmony_ci	       "WARNING: unable to reserve scanner: device busy\n");
3640141cc406Sopenharmony_ci	  return SANE_STATUS_DEVICE_BUSY;
3641141cc406Sopenharmony_ci	}
3642141cc406Sopenharmony_ci
3643141cc406Sopenharmony_ci      scanner->scanning = SANE_TRUE;
3644141cc406Sopenharmony_ci
3645141cc406Sopenharmony_ci      pie_power_save (scanner, 0);
3646141cc406Sopenharmony_ci    }				/* ------------ end of first call -------------- */
3647141cc406Sopenharmony_ci
3648141cc406Sopenharmony_ci
3649141cc406Sopenharmony_ci  if (strcmp (mode, LINEART_STR) == 0)
3650141cc406Sopenharmony_ci    {
3651141cc406Sopenharmony_ci      scanner->colormode = LINEART;
3652141cc406Sopenharmony_ci    }
3653141cc406Sopenharmony_ci  else if (strcmp (mode, HALFTONE_STR) == 0)
3654141cc406Sopenharmony_ci    {
3655141cc406Sopenharmony_ci      scanner->colormode = HALFTONE;
3656141cc406Sopenharmony_ci    }
3657141cc406Sopenharmony_ci  else if (strcmp (mode, GRAY_STR) == 0)
3658141cc406Sopenharmony_ci    {
3659141cc406Sopenharmony_ci      scanner->colormode = GRAYSCALE;
3660141cc406Sopenharmony_ci    }
3661141cc406Sopenharmony_ci  else if (strcmp (mode, COLOR_STR) == 0)
3662141cc406Sopenharmony_ci    {
3663141cc406Sopenharmony_ci      scanner->colormode = RGB;
3664141cc406Sopenharmony_ci    }
3665141cc406Sopenharmony_ci
3666141cc406Sopenharmony_ci  /* get and set geometric values for scanning */
3667141cc406Sopenharmony_ci  scanner->resolution = SANE_UNFIX (scanner->val[OPT_RESOLUTION].w);
3668141cc406Sopenharmony_ci
3669141cc406Sopenharmony_ci  pie_set_window (scanner);
3670141cc406Sopenharmony_ci  pie_send_exposure (scanner);
3671141cc406Sopenharmony_ci  pie_mode_select (scanner);
3672141cc406Sopenharmony_ci  pie_send_highlight_shadow (scanner);
3673141cc406Sopenharmony_ci
3674141cc406Sopenharmony_ci  pie_scan (scanner, 1);
3675141cc406Sopenharmony_ci
3676141cc406Sopenharmony_ci  status = pie_do_cal (scanner);
3677141cc406Sopenharmony_ci  if (status)
3678141cc406Sopenharmony_ci    return status;
3679141cc406Sopenharmony_ci
3680141cc406Sopenharmony_ci  /* send gammacurves */
3681141cc406Sopenharmony_ci
3682141cc406Sopenharmony_ci  pie_dwnld_gamma (scanner);
3683141cc406Sopenharmony_ci
3684141cc406Sopenharmony_ci  pie_get_params (scanner);
3685141cc406Sopenharmony_ci
3686141cc406Sopenharmony_ci  if (pipe (fds) < 0)		/* create a pipe, fds[0]=read-fd, fds[1]=write-fd */
3687141cc406Sopenharmony_ci    {
3688141cc406Sopenharmony_ci      DBG (DBG_error, "ERROR: could not create pipe\n");
3689141cc406Sopenharmony_ci      scanner->scanning = SANE_FALSE;
3690141cc406Sopenharmony_ci      pie_scan (scanner, 0);
3691141cc406Sopenharmony_ci      pie_give_scanner (scanner);	/* reposition and release scanner */
3692141cc406Sopenharmony_ci      sanei_scsi_close (scanner->sfd);
3693141cc406Sopenharmony_ci      scanner->sfd = -1;
3694141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
3695141cc406Sopenharmony_ci    }
3696141cc406Sopenharmony_ci
3697141cc406Sopenharmony_ci  scanner->pipe       = fds[0];
3698141cc406Sopenharmony_ci  scanner->reader_fds = fds[1];
3699141cc406Sopenharmony_ci  scanner->reader_pid = sanei_thread_begin( reader_process, (void*)scanner );
3700141cc406Sopenharmony_ci
3701141cc406Sopenharmony_ci  if (!sanei_thread_is_valid (scanner->reader_pid))
3702141cc406Sopenharmony_ci    {
3703141cc406Sopenharmony_ci      DBG (1, "sane_start: sanei_thread_begin failed (%s)\n",
3704141cc406Sopenharmony_ci             strerror (errno));
3705141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
3706141cc406Sopenharmony_ci    }
3707141cc406Sopenharmony_ci
3708141cc406Sopenharmony_ci  if (sanei_thread_is_forked ())
3709141cc406Sopenharmony_ci    {
3710141cc406Sopenharmony_ci      close (scanner->reader_fds);
3711141cc406Sopenharmony_ci      scanner->reader_fds = -1;
3712141cc406Sopenharmony_ci    }
3713141cc406Sopenharmony_ci
3714141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3715141cc406Sopenharmony_ci}
3716141cc406Sopenharmony_ci
3717141cc406Sopenharmony_ci
3718141cc406Sopenharmony_ci/* -------------------------------------- SANE READ ---------------------------------- */
3719141cc406Sopenharmony_ci
3720141cc406Sopenharmony_ci
3721141cc406Sopenharmony_ciSANE_Status
3722141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
3723141cc406Sopenharmony_ci	   SANE_Int * len)
3724141cc406Sopenharmony_ci{
3725141cc406Sopenharmony_ci  Pie_Scanner *scanner = handle;
3726141cc406Sopenharmony_ci  ssize_t nread;
3727141cc406Sopenharmony_ci
3728141cc406Sopenharmony_ci  *len = 0;
3729141cc406Sopenharmony_ci
3730141cc406Sopenharmony_ci  nread = read (scanner->pipe, buf, max_len);
3731141cc406Sopenharmony_ci  DBG (DBG_sane_info, "sane_read: read %ld bytes\n", (long) nread);
3732141cc406Sopenharmony_ci
3733141cc406Sopenharmony_ci  if (!(scanner->scanning))	/* OOPS, not scanning */
3734141cc406Sopenharmony_ci    {
3735141cc406Sopenharmony_ci      return do_cancel (scanner);
3736141cc406Sopenharmony_ci    }
3737141cc406Sopenharmony_ci
3738141cc406Sopenharmony_ci  if (nread < 0)
3739141cc406Sopenharmony_ci    {
3740141cc406Sopenharmony_ci      if (errno == EAGAIN)
3741141cc406Sopenharmony_ci	{
3742141cc406Sopenharmony_ci	  DBG (DBG_sane_info, "sane_read: EAGAIN\n");
3743141cc406Sopenharmony_ci	  return SANE_STATUS_GOOD;
3744141cc406Sopenharmony_ci	}
3745141cc406Sopenharmony_ci      else
3746141cc406Sopenharmony_ci	{
3747141cc406Sopenharmony_ci	  do_cancel (scanner);	/* we had an error, stop scanner */
3748141cc406Sopenharmony_ci	  return SANE_STATUS_IO_ERROR;
3749141cc406Sopenharmony_ci	}
3750141cc406Sopenharmony_ci    }
3751141cc406Sopenharmony_ci
3752141cc406Sopenharmony_ci  *len = nread;
3753141cc406Sopenharmony_ci
3754141cc406Sopenharmony_ci  if (nread == 0)		/* EOF */
3755141cc406Sopenharmony_ci    {
3756141cc406Sopenharmony_ci      do_cancel (scanner);
3757141cc406Sopenharmony_ci
3758141cc406Sopenharmony_ci      return close_pipe (scanner);	/* close pipe */
3759141cc406Sopenharmony_ci    }
3760141cc406Sopenharmony_ci
3761141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3762141cc406Sopenharmony_ci}
3763141cc406Sopenharmony_ci
3764141cc406Sopenharmony_ci
3765141cc406Sopenharmony_ci/* ------------------------------------- SANE CANCEL -------------------------------- */
3766141cc406Sopenharmony_ci
3767141cc406Sopenharmony_ci
3768141cc406Sopenharmony_civoid
3769141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
3770141cc406Sopenharmony_ci{
3771141cc406Sopenharmony_ci  Pie_Scanner *scanner = handle;
3772141cc406Sopenharmony_ci
3773141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_cancel\n");
3774141cc406Sopenharmony_ci
3775141cc406Sopenharmony_ci  if (scanner->scanning)
3776141cc406Sopenharmony_ci    {
3777141cc406Sopenharmony_ci      do_cancel (scanner);
3778141cc406Sopenharmony_ci    }
3779141cc406Sopenharmony_ci}
3780141cc406Sopenharmony_ci
3781141cc406Sopenharmony_ci
3782141cc406Sopenharmony_ci/* -------------------------------------- SANE SET IO MODE --------------------------- */
3783141cc406Sopenharmony_ci
3784141cc406Sopenharmony_ci
3785141cc406Sopenharmony_ciSANE_Status
3786141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
3787141cc406Sopenharmony_ci{
3788141cc406Sopenharmony_ci  Pie_Scanner *scanner = handle;
3789141cc406Sopenharmony_ci
3790141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_set_io_mode: non_blocking=%d\n", non_blocking);
3791141cc406Sopenharmony_ci
3792141cc406Sopenharmony_ci  if (!scanner->scanning)
3793141cc406Sopenharmony_ci    {
3794141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3795141cc406Sopenharmony_ci    }
3796141cc406Sopenharmony_ci
3797141cc406Sopenharmony_ci  if (fcntl (scanner->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0)
3798141cc406Sopenharmony_ci    {
3799141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
3800141cc406Sopenharmony_ci    }
3801141cc406Sopenharmony_ci
3802141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3803141cc406Sopenharmony_ci}
3804141cc406Sopenharmony_ci
3805141cc406Sopenharmony_ci
3806141cc406Sopenharmony_ci/* --------------------------------------- SANE GET SELECT FD ------------------------- */
3807141cc406Sopenharmony_ci
3808141cc406Sopenharmony_ci
3809141cc406Sopenharmony_ciSANE_Status
3810141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
3811141cc406Sopenharmony_ci{
3812141cc406Sopenharmony_ci  Pie_Scanner *scanner = handle;
3813141cc406Sopenharmony_ci
3814141cc406Sopenharmony_ci  DBG (DBG_sane_init, "sane_get_select_fd\n");
3815141cc406Sopenharmony_ci
3816141cc406Sopenharmony_ci  if (!scanner->scanning)
3817141cc406Sopenharmony_ci    {
3818141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
3819141cc406Sopenharmony_ci    }
3820141cc406Sopenharmony_ci  *fd = scanner->pipe;
3821141cc406Sopenharmony_ci
3822141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
3823141cc406Sopenharmony_ci}
3824