1141cc406Sopenharmony_ci/*
2141cc406Sopenharmony_ci * epson2.c - SANE library for Epson scanners.
3141cc406Sopenharmony_ci *
4141cc406Sopenharmony_ci * Based on Kazuhiro Sasayama previous
5141cc406Sopenharmony_ci * Work on epson.[ch] file from the SANE package.
6141cc406Sopenharmony_ci * Please see those files for additional copyrights.
7141cc406Sopenharmony_ci *
8141cc406Sopenharmony_ci * Copyright (C) 2006-10 Tower Technologies
9141cc406Sopenharmony_ci * Author: Alessandro Zummo <a.zummo@towertech.it>
10141cc406Sopenharmony_ci *
11141cc406Sopenharmony_ci * This file is part of the SANE package.
12141cc406Sopenharmony_ci *
13141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or
14141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as
15141cc406Sopenharmony_ci * published by the Free Software Foundation, version 2.
16141cc406Sopenharmony_ci */
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci/* debugging levels:
19141cc406Sopenharmony_ci *
20141cc406Sopenharmony_ci *     127	e2_recv buffer
21141cc406Sopenharmony_ci *     125	e2_send buffer
22141cc406Sopenharmony_ci *	32	more network progression
23141cc406Sopenharmony_ci *	24	network header
24141cc406Sopenharmony_ci *	23	network info
25141cc406Sopenharmony_ci *	20	usb cmd counters
26141cc406Sopenharmony_ci *	18	sane_read
27141cc406Sopenharmony_ci *	17	setvalue, getvalue, control_option
28141cc406Sopenharmony_ci *	16	gamma table
29141cc406Sopenharmony_ci *	15	e2_send, e2_recv calls
30141cc406Sopenharmony_ci *	13	e2_cmd_info_block
31141cc406Sopenharmony_ci *	12	epson_cmd_simple
32141cc406Sopenharmony_ci *	11	even more
33141cc406Sopenharmony_ci *	10	more debug in ESC/I commands
34141cc406Sopenharmony_ci *	 9	ESC x/FS x in e2_send
35141cc406Sopenharmony_ci *	 8	ESC/I commands
36141cc406Sopenharmony_ci *	 7	open/close/attach
37141cc406Sopenharmony_ci *	 6	print_params
38141cc406Sopenharmony_ci *	 5	basic functions
39141cc406Sopenharmony_ci *	 3	status information
40141cc406Sopenharmony_ci *	 1	scanner info and capabilities
41141cc406Sopenharmony_ci *		warnings
42141cc406Sopenharmony_ci */
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci#include "sane/config.h"
45141cc406Sopenharmony_ci
46141cc406Sopenharmony_ci#include "epson2.h"
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci#include <limits.h>
49141cc406Sopenharmony_ci#include <stdio.h>
50141cc406Sopenharmony_ci#include <string.h>
51141cc406Sopenharmony_ci#include <stdlib.h>
52141cc406Sopenharmony_ci#include <ctype.h>
53141cc406Sopenharmony_ci#include <fcntl.h>
54141cc406Sopenharmony_ci#include <unistd.h>
55141cc406Sopenharmony_ci#include <errno.h>
56141cc406Sopenharmony_ci#include <sys/time.h>
57141cc406Sopenharmony_ci#include <sys/types.h>
58141cc406Sopenharmony_ci#ifdef HAVE_SYS_SOCKET_H
59141cc406Sopenharmony_ci#include <sys/socket.h>
60141cc406Sopenharmony_ci#endif
61141cc406Sopenharmony_ci
62141cc406Sopenharmony_ci#include "sane/saneopts.h"
63141cc406Sopenharmony_ci#include "sane/sanei_scsi.h"
64141cc406Sopenharmony_ci#include "sane/sanei_usb.h"
65141cc406Sopenharmony_ci#include "sane/sanei_pio.h"
66141cc406Sopenharmony_ci#include "sane/sanei_tcp.h"
67141cc406Sopenharmony_ci#include "sane/sanei_udp.h"
68141cc406Sopenharmony_ci#include "sane/sanei_backend.h"
69141cc406Sopenharmony_ci#include "sane/sanei_config.h"
70141cc406Sopenharmony_ci
71141cc406Sopenharmony_ci#include "epson2-io.h"
72141cc406Sopenharmony_ci#include "epson2-commands.h"
73141cc406Sopenharmony_ci#include "epson2-ops.h"
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci#include "epson2_scsi.h"
76141cc406Sopenharmony_ci#include "epson_usb.h"
77141cc406Sopenharmony_ci#include "epson2_net.h"
78141cc406Sopenharmony_ci
79141cc406Sopenharmony_ci/*
80141cc406Sopenharmony_ci * Definition of the mode_param struct, that is used to
81141cc406Sopenharmony_ci * specify the valid parameters for the different scan modes.
82141cc406Sopenharmony_ci *
83141cc406Sopenharmony_ci * The depth variable gets updated when the bit depth is modified.
84141cc406Sopenharmony_ci */
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_cistruct mode_param mode_params[] = {
87141cc406Sopenharmony_ci	{0, 0x00, 0x30, 1},
88141cc406Sopenharmony_ci	{0, 0x00, 0x30, 8},
89141cc406Sopenharmony_ci	{1, 0x02, 0x00, 8},
90141cc406Sopenharmony_ci	{0, 0x00, 0x30, 1}
91141cc406Sopenharmony_ci};
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_cistatic SANE_String_Const mode_list[] = {
94141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_LINEART,
95141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_GRAY,
96141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_COLOR,
97141cc406Sopenharmony_ci#ifdef SANE_FRAME_IR
98141cc406Sopenharmony_ci	SANE_I18N("Infrared"),
99141cc406Sopenharmony_ci#endif
100141cc406Sopenharmony_ci	NULL
101141cc406Sopenharmony_ci};
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_cistatic const SANE_String_Const adf_mode_list[] = {
104141cc406Sopenharmony_ci	SANE_I18N("Simplex"),
105141cc406Sopenharmony_ci	SANE_I18N("Duplex"),
106141cc406Sopenharmony_ci	NULL
107141cc406Sopenharmony_ci};
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci/* Define the different scan sources */
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_ci#define FBF_STR	SANE_I18N("Flatbed")
112141cc406Sopenharmony_ci#define TPU_STR	SANE_I18N("Transparency Unit")
113141cc406Sopenharmony_ci#define TPU_STR2 SANE_I18N("TPU8x10")
114141cc406Sopenharmony_ci#define ADF_STR	SANE_I18N("Automatic Document Feeder")
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_ci/*
117141cc406Sopenharmony_ci * source list need one dummy entry (save device settings is crashing).
118141cc406Sopenharmony_ci * NOTE: no const - this list gets created while exploring the capabilities
119141cc406Sopenharmony_ci * of the scanner.
120141cc406Sopenharmony_ci */
121141cc406Sopenharmony_ci
122141cc406Sopenharmony_ciSANE_String_Const source_list[] = {
123141cc406Sopenharmony_ci	FBF_STR,
124141cc406Sopenharmony_ci	NULL,
125141cc406Sopenharmony_ci	NULL,
126141cc406Sopenharmony_ci	NULL
127141cc406Sopenharmony_ci};
128141cc406Sopenharmony_ci
129141cc406Sopenharmony_cistatic const SANE_String_Const film_list[] = {
130141cc406Sopenharmony_ci	SANE_I18N("Positive Film"),
131141cc406Sopenharmony_ci	SANE_I18N("Negative Film"),
132141cc406Sopenharmony_ci	SANE_I18N("Positive Slide"),
133141cc406Sopenharmony_ci	SANE_I18N("Negative Slide"),
134141cc406Sopenharmony_ci	NULL
135141cc406Sopenharmony_ci};
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci#define HALFTONE_NONE 0x01
138141cc406Sopenharmony_ci#define HALFTONE_TET 0x03
139141cc406Sopenharmony_ci
140141cc406Sopenharmony_ciconst int halftone_params[] = {
141141cc406Sopenharmony_ci	HALFTONE_NONE,
142141cc406Sopenharmony_ci	0x00,
143141cc406Sopenharmony_ci	0x10,
144141cc406Sopenharmony_ci	0x20,
145141cc406Sopenharmony_ci	0x80,
146141cc406Sopenharmony_ci	0x90,
147141cc406Sopenharmony_ci	0xa0,
148141cc406Sopenharmony_ci	0xb0,
149141cc406Sopenharmony_ci	HALFTONE_TET,
150141cc406Sopenharmony_ci	0xc0,
151141cc406Sopenharmony_ci	0xd0
152141cc406Sopenharmony_ci};
153141cc406Sopenharmony_ci
154141cc406Sopenharmony_cistatic const SANE_String_Const halftone_list[] = {
155141cc406Sopenharmony_ci	SANE_I18N("None"),
156141cc406Sopenharmony_ci	SANE_I18N("Halftone A (Hard Tone)"),
157141cc406Sopenharmony_ci	SANE_I18N("Halftone B (Soft Tone)"),
158141cc406Sopenharmony_ci	SANE_I18N("Halftone C (Net Screen)"),
159141cc406Sopenharmony_ci	NULL
160141cc406Sopenharmony_ci};
161141cc406Sopenharmony_ci
162141cc406Sopenharmony_cistatic const SANE_String_Const halftone_list_4[] = {
163141cc406Sopenharmony_ci	SANE_I18N("None"),
164141cc406Sopenharmony_ci	SANE_I18N("Halftone A (Hard Tone)"),
165141cc406Sopenharmony_ci	SANE_I18N("Halftone B (Soft Tone)"),
166141cc406Sopenharmony_ci	SANE_I18N("Halftone C (Net Screen)"),
167141cc406Sopenharmony_ci	SANE_I18N("Dither A (4x4 Bayer)"),
168141cc406Sopenharmony_ci	SANE_I18N("Dither B (4x4 Spiral)"),
169141cc406Sopenharmony_ci	SANE_I18N("Dither C (4x4 Net Screen)"),
170141cc406Sopenharmony_ci	SANE_I18N("Dither D (8x4 Net Screen)"),
171141cc406Sopenharmony_ci	NULL
172141cc406Sopenharmony_ci};
173141cc406Sopenharmony_ci
174141cc406Sopenharmony_cistatic const SANE_String_Const halftone_list_7[] = {
175141cc406Sopenharmony_ci	SANE_I18N("None"),
176141cc406Sopenharmony_ci	SANE_I18N("Halftone A (Hard Tone)"),
177141cc406Sopenharmony_ci	SANE_I18N("Halftone B (Soft Tone)"),
178141cc406Sopenharmony_ci	SANE_I18N("Halftone C (Net Screen)"),
179141cc406Sopenharmony_ci	SANE_I18N("Dither A (4x4 Bayer)"),
180141cc406Sopenharmony_ci	SANE_I18N("Dither B (4x4 Spiral)"),
181141cc406Sopenharmony_ci	SANE_I18N("Dither C (4x4 Net Screen)"),
182141cc406Sopenharmony_ci	SANE_I18N("Dither D (8x4 Net Screen)"),
183141cc406Sopenharmony_ci	SANE_I18N("Text Enhanced Technology"),
184141cc406Sopenharmony_ci	SANE_I18N("Download pattern A"),
185141cc406Sopenharmony_ci	SANE_I18N("Download pattern B"),
186141cc406Sopenharmony_ci	NULL
187141cc406Sopenharmony_ci};
188141cc406Sopenharmony_ci
189141cc406Sopenharmony_cistatic const SANE_String_Const dropout_list[] = {
190141cc406Sopenharmony_ci	SANE_I18N("None"),
191141cc406Sopenharmony_ci	SANE_I18N("Red"),
192141cc406Sopenharmony_ci	SANE_I18N("Green"),
193141cc406Sopenharmony_ci	SANE_I18N("Blue"),
194141cc406Sopenharmony_ci	NULL
195141cc406Sopenharmony_ci};
196141cc406Sopenharmony_ci
197141cc406Sopenharmony_cistatic const SANE_Bool correction_userdefined[] = {
198141cc406Sopenharmony_ci	SANE_FALSE,
199141cc406Sopenharmony_ci	SANE_TRUE,
200141cc406Sopenharmony_ci	SANE_TRUE,
201141cc406Sopenharmony_ci};
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_cistatic const SANE_String_Const correction_list[] = {
204141cc406Sopenharmony_ci	SANE_I18N("None"),
205141cc406Sopenharmony_ci	SANE_I18N("Built in CCT profile"),
206141cc406Sopenharmony_ci	SANE_I18N("User defined CCT profile"),
207141cc406Sopenharmony_ci	NULL
208141cc406Sopenharmony_ci};
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_cienum {
211141cc406Sopenharmony_ci	CORR_NONE, CORR_AUTO, CORR_USER
212141cc406Sopenharmony_ci};
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_cistatic const SANE_String_Const cct_mode_list[] = {
215141cc406Sopenharmony_ci        "Automatic",
216141cc406Sopenharmony_ci        "Reflective",
217141cc406Sopenharmony_ci        "Colour negatives",
218141cc406Sopenharmony_ci        "Monochrome negatives",
219141cc406Sopenharmony_ci        "Colour positives",
220141cc406Sopenharmony_ci        NULL
221141cc406Sopenharmony_ci};
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_cienum {
224141cc406Sopenharmony_ci	CCT_AUTO, CCT_REFLECTIVE, CCT_COLORNEG, CCT_MONONEG,
225141cc406Sopenharmony_ci	CCT_COLORPOS
226141cc406Sopenharmony_ci};
227141cc406Sopenharmony_ci
228141cc406Sopenharmony_ci/*
229141cc406Sopenharmony_ci * Gamma correction:
230141cc406Sopenharmony_ci * The A and B level scanners work differently than the D level scanners,
231141cc406Sopenharmony_ci * therefore I define two different sets of arrays, plus one set of
232141cc406Sopenharmony_ci * variables that get set to the actually used params and list arrays at runtime.
233141cc406Sopenharmony_ci */
234141cc406Sopenharmony_ci
235141cc406Sopenharmony_cistatic int gamma_params_ab[] = {
236141cc406Sopenharmony_ci	0x01,
237141cc406Sopenharmony_ci	0x03,
238141cc406Sopenharmony_ci	0x00,
239141cc406Sopenharmony_ci	0x10,
240141cc406Sopenharmony_ci	0x20
241141cc406Sopenharmony_ci};
242141cc406Sopenharmony_ci
243141cc406Sopenharmony_cistatic const SANE_String_Const gamma_list_ab[] = {
244141cc406Sopenharmony_ci	SANE_I18N("Default"),
245141cc406Sopenharmony_ci	SANE_I18N("User defined"),
246141cc406Sopenharmony_ci	SANE_I18N("High density printing"),
247141cc406Sopenharmony_ci	SANE_I18N("Low density printing"),
248141cc406Sopenharmony_ci	SANE_I18N("High contrast printing"),
249141cc406Sopenharmony_ci	NULL
250141cc406Sopenharmony_ci};
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_cistatic SANE_Bool gamma_userdefined_ab[] = {
253141cc406Sopenharmony_ci	SANE_FALSE,
254141cc406Sopenharmony_ci	SANE_TRUE,
255141cc406Sopenharmony_ci	SANE_FALSE,
256141cc406Sopenharmony_ci	SANE_FALSE,
257141cc406Sopenharmony_ci	SANE_FALSE,
258141cc406Sopenharmony_ci};
259141cc406Sopenharmony_ci
260141cc406Sopenharmony_cistatic int gamma_params_d[] = {
261141cc406Sopenharmony_ci	0x03,
262141cc406Sopenharmony_ci	0x04
263141cc406Sopenharmony_ci};
264141cc406Sopenharmony_ci
265141cc406Sopenharmony_cistatic const SANE_String_Const gamma_list_d[] = {
266141cc406Sopenharmony_ci	SANE_I18N("User defined (Gamma=1.0)"),
267141cc406Sopenharmony_ci	SANE_I18N("User defined (Gamma=1.8)"),
268141cc406Sopenharmony_ci	NULL
269141cc406Sopenharmony_ci};
270141cc406Sopenharmony_ci
271141cc406Sopenharmony_cistatic SANE_Bool gamma_userdefined_d[] = {
272141cc406Sopenharmony_ci	SANE_TRUE,
273141cc406Sopenharmony_ci	SANE_TRUE
274141cc406Sopenharmony_ci};
275141cc406Sopenharmony_ci
276141cc406Sopenharmony_cistatic SANE_Bool *gamma_userdefined;
277141cc406Sopenharmony_ciint *gamma_params;
278141cc406Sopenharmony_ci
279141cc406Sopenharmony_ci/* Bay list:
280141cc406Sopenharmony_ci * this is used for the FilmScan
281141cc406Sopenharmony_ci * XXX Add APS loader support
282141cc406Sopenharmony_ci */
283141cc406Sopenharmony_ci
284141cc406Sopenharmony_cistatic const SANE_String_Const bay_list[] = {
285141cc406Sopenharmony_ci	"1",
286141cc406Sopenharmony_ci	"2",
287141cc406Sopenharmony_ci	"3",
288141cc406Sopenharmony_ci	"4",
289141cc406Sopenharmony_ci	"5",
290141cc406Sopenharmony_ci	"6",
291141cc406Sopenharmony_ci	NULL
292141cc406Sopenharmony_ci};
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci/* minimum, maximum, quantization */
295141cc406Sopenharmony_cistatic const SANE_Range focus_range = { 0, 254, 0 };
296141cc406Sopenharmony_cistatic const SANE_Range u8_range = { 0, 255, 0 };
297141cc406Sopenharmony_cistatic const SANE_Range fx_range = { SANE_FIX(-2.0), SANE_FIX(2.0), 0 };
298141cc406Sopenharmony_cistatic const SANE_Range outline_emphasis_range = { -2, 2, 0 };
299141cc406Sopenharmony_ci
300141cc406Sopenharmony_ci/*
301141cc406Sopenharmony_ci * List of pointers to devices - will be dynamically allocated depending
302141cc406Sopenharmony_ci * on the number of devices found.
303141cc406Sopenharmony_ci */
304141cc406Sopenharmony_cistatic const SANE_Device **devlist;
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci/* Some utility functions */
308141cc406Sopenharmony_ci
309141cc406Sopenharmony_cistatic size_t
310141cc406Sopenharmony_cimax_string_size(const SANE_String_Const strings[])
311141cc406Sopenharmony_ci{
312141cc406Sopenharmony_ci	size_t size, max_size = 0;
313141cc406Sopenharmony_ci	int i;
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_ci	for (i = 0; strings[i]; i++) {
316141cc406Sopenharmony_ci		size = strlen(strings[i]) + 1;
317141cc406Sopenharmony_ci		if (size > max_size)
318141cc406Sopenharmony_ci			max_size = size;
319141cc406Sopenharmony_ci	}
320141cc406Sopenharmony_ci	return max_size;
321141cc406Sopenharmony_ci}
322141cc406Sopenharmony_ci
323141cc406Sopenharmony_cistatic SANE_Status attach_one_usb(SANE_String_Const devname);
324141cc406Sopenharmony_cistatic SANE_Status attach_one_net(SANE_String_Const devname);
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_cistatic void
327141cc406Sopenharmony_ciprint_params(const SANE_Parameters params)
328141cc406Sopenharmony_ci{
329141cc406Sopenharmony_ci	DBG(6, "params.format          = %d\n", params.format);
330141cc406Sopenharmony_ci	DBG(6, "params.last_frame      = %d\n", params.last_frame);
331141cc406Sopenharmony_ci	DBG(6, "params.bytes_per_line  = %d\n", params.bytes_per_line);
332141cc406Sopenharmony_ci	DBG(6, "params.pixels_per_line = %d\n", params.pixels_per_line);
333141cc406Sopenharmony_ci	DBG(6, "params.lines           = %d\n", params.lines);
334141cc406Sopenharmony_ci	DBG(6, "params.depth           = %d\n", params.depth);
335141cc406Sopenharmony_ci}
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_ci/*
338141cc406Sopenharmony_ci * close_scanner()
339141cc406Sopenharmony_ci *
340141cc406Sopenharmony_ci * Close the open scanner. Depending on the connection method, a different
341141cc406Sopenharmony_ci * close function is called.
342141cc406Sopenharmony_ci */
343141cc406Sopenharmony_ci
344141cc406Sopenharmony_cistatic void
345141cc406Sopenharmony_ciclose_scanner(Epson_Scanner *s)
346141cc406Sopenharmony_ci{
347141cc406Sopenharmony_ci	int i;
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci	DBG(7, "%s: fd = %d\n", __func__, s->fd);
350141cc406Sopenharmony_ci
351141cc406Sopenharmony_ci	if (s->fd == -1)
352141cc406Sopenharmony_ci		goto free;
353141cc406Sopenharmony_ci
354141cc406Sopenharmony_ci	/* send a request_status. This toggles w_cmd_count and r_cmd_count */
355141cc406Sopenharmony_ci	if (r_cmd_count % 2)
356141cc406Sopenharmony_ci		esci_request_status(s, NULL);
357141cc406Sopenharmony_ci
358141cc406Sopenharmony_ci	/* request extended status. This toggles w_cmd_count only */
359141cc406Sopenharmony_ci	if (w_cmd_count % 2)
360141cc406Sopenharmony_ci		esci_request_extended_status(s, NULL, NULL);
361141cc406Sopenharmony_ci
362141cc406Sopenharmony_ci	if (s->hw->connection == SANE_EPSON_NET) {
363141cc406Sopenharmony_ci		sanei_epson_net_unlock(s);
364141cc406Sopenharmony_ci		sanei_tcp_close(s->fd);
365141cc406Sopenharmony_ci	} else if (s->hw->connection == SANE_EPSON_SCSI) {
366141cc406Sopenharmony_ci		sanei_scsi_close(s->fd);
367141cc406Sopenharmony_ci	} else if (s->hw->connection == SANE_EPSON_PIO) {
368141cc406Sopenharmony_ci		sanei_pio_close(s->fd);
369141cc406Sopenharmony_ci	} else if (s->hw->connection == SANE_EPSON_USB) {
370141cc406Sopenharmony_ci		sanei_usb_close(s->fd);
371141cc406Sopenharmony_ci	}
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci	s->fd = -1;
374141cc406Sopenharmony_ci
375141cc406Sopenharmony_cifree:
376141cc406Sopenharmony_ci	for (i = 0; i < LINES_SHUFFLE_MAX; i++) {
377141cc406Sopenharmony_ci		if (s->line_buffer[i] != NULL)
378141cc406Sopenharmony_ci			free(s->line_buffer[i]);
379141cc406Sopenharmony_ci	}
380141cc406Sopenharmony_ci
381141cc406Sopenharmony_ci	free(s);
382141cc406Sopenharmony_ci}
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_cistatic void
385141cc406Sopenharmony_cie2_network_discovery(void)
386141cc406Sopenharmony_ci{
387141cc406Sopenharmony_ci	fd_set rfds;
388141cc406Sopenharmony_ci	int fd, len;
389141cc406Sopenharmony_ci	SANE_Status status;
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci	char *ip, *query = "EPSONP\x00\xff\x00\x00\x00\x00\x00\x00\x00";
392141cc406Sopenharmony_ci	unsigned char buf[76];
393141cc406Sopenharmony_ci
394141cc406Sopenharmony_ci	struct timeval to;
395141cc406Sopenharmony_ci
396141cc406Sopenharmony_ci	status = sanei_udp_open_broadcast(&fd);
397141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
398141cc406Sopenharmony_ci		return;
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci	sanei_udp_write_broadcast(fd, 3289, (unsigned char *) query, 15);
401141cc406Sopenharmony_ci
402141cc406Sopenharmony_ci	DBG(5, "%s, sent discovery packet\n", __func__);
403141cc406Sopenharmony_ci
404141cc406Sopenharmony_ci	to.tv_sec = 1;
405141cc406Sopenharmony_ci	to.tv_usec = 0;
406141cc406Sopenharmony_ci
407141cc406Sopenharmony_ci	FD_ZERO(&rfds);
408141cc406Sopenharmony_ci	FD_SET(fd, &rfds);
409141cc406Sopenharmony_ci
410141cc406Sopenharmony_ci	sanei_udp_set_nonblock(fd, SANE_TRUE);
411141cc406Sopenharmony_ci	while (select(fd + 1, &rfds, NULL, NULL, &to) > 0) {
412141cc406Sopenharmony_ci		if ((len = sanei_udp_recvfrom(fd, buf, 76, &ip)) == 76) {
413141cc406Sopenharmony_ci			DBG(5, " response from %s\n", ip);
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci			/* minimal check, protocol unknown */
416141cc406Sopenharmony_ci			if (strncmp((char *) buf, "EPSON", 5) == 0)
417141cc406Sopenharmony_ci				attach_one_net(ip);
418141cc406Sopenharmony_ci		}
419141cc406Sopenharmony_ci	}
420141cc406Sopenharmony_ci
421141cc406Sopenharmony_ci	DBG(5, "%s, end\n", __func__);
422141cc406Sopenharmony_ci
423141cc406Sopenharmony_ci	sanei_udp_close(fd);
424141cc406Sopenharmony_ci}
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci/*
427141cc406Sopenharmony_ci * open_scanner()
428141cc406Sopenharmony_ci *
429141cc406Sopenharmony_ci * Open the scanner device. Depending on the connection method,
430141cc406Sopenharmony_ci * different open functions are called.
431141cc406Sopenharmony_ci */
432141cc406Sopenharmony_ci
433141cc406Sopenharmony_cistatic SANE_Status
434141cc406Sopenharmony_ciopen_scanner(Epson_Scanner *s)
435141cc406Sopenharmony_ci{
436141cc406Sopenharmony_ci	SANE_Status status = 0;
437141cc406Sopenharmony_ci
438141cc406Sopenharmony_ci	DBG(7, "%s: %s\n", __func__, s->hw->sane.name);
439141cc406Sopenharmony_ci
440141cc406Sopenharmony_ci	if (s->fd != -1) {
441141cc406Sopenharmony_ci		DBG(5, "scanner is already open: fd = %d\n", s->fd);
442141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;	/* no need to open the scanner */
443141cc406Sopenharmony_ci	}
444141cc406Sopenharmony_ci
445141cc406Sopenharmony_ci	if (s->hw->connection == SANE_EPSON_NET) {
446141cc406Sopenharmony_ci		unsigned char buf[5];
447141cc406Sopenharmony_ci
448141cc406Sopenharmony_ci		/* device name has the form net:ipaddr */
449141cc406Sopenharmony_ci		status = sanei_tcp_open(&s->hw->sane.name[4], 1865, &s->fd);
450141cc406Sopenharmony_ci		if (status == SANE_STATUS_GOOD) {
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci			ssize_t read;
453141cc406Sopenharmony_ci			struct timeval tv;
454141cc406Sopenharmony_ci
455141cc406Sopenharmony_ci			tv.tv_sec = 5;
456141cc406Sopenharmony_ci			tv.tv_usec = 0;
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_ci			setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,  sizeof(tv));
459141cc406Sopenharmony_ci
460141cc406Sopenharmony_ci			s->netlen = 0;
461141cc406Sopenharmony_ci
462141cc406Sopenharmony_ci			DBG(32, "awaiting welcome message\n");
463141cc406Sopenharmony_ci
464141cc406Sopenharmony_ci			/* the scanner sends a kind of welcome msg */
465141cc406Sopenharmony_ci			read = e2_recv(s, buf, 5, &status);
466141cc406Sopenharmony_ci			if (read != 5) {
467141cc406Sopenharmony_ci				sanei_tcp_close(s->fd);
468141cc406Sopenharmony_ci				s->fd = -1;
469141cc406Sopenharmony_ci				return SANE_STATUS_IO_ERROR;
470141cc406Sopenharmony_ci			}
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci			DBG(32, "welcome message received, locking the scanner...\n");
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci			/* lock the scanner for use by sane */
475141cc406Sopenharmony_ci			status = sanei_epson_net_lock(s);
476141cc406Sopenharmony_ci			if (status != SANE_STATUS_GOOD) {
477141cc406Sopenharmony_ci				DBG(1, "%s cannot lock scanner: %s\n", s->hw->sane.name,
478141cc406Sopenharmony_ci					sane_strstatus(status));
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci				sanei_tcp_close(s->fd);
481141cc406Sopenharmony_ci				s->fd = -1;
482141cc406Sopenharmony_ci
483141cc406Sopenharmony_ci				return status;
484141cc406Sopenharmony_ci			}
485141cc406Sopenharmony_ci
486141cc406Sopenharmony_ci			DBG(32, "scanner locked\n");
487141cc406Sopenharmony_ci		}
488141cc406Sopenharmony_ci
489141cc406Sopenharmony_ci	} else if (s->hw->connection == SANE_EPSON_SCSI)
490141cc406Sopenharmony_ci		status = sanei_scsi_open(s->hw->sane.name, &s->fd,
491141cc406Sopenharmony_ci					 sanei_epson2_scsi_sense_handler,
492141cc406Sopenharmony_ci					 NULL);
493141cc406Sopenharmony_ci	else if (s->hw->connection == SANE_EPSON_PIO)
494141cc406Sopenharmony_ci		/* device name has the form pio:0xnnn */
495141cc406Sopenharmony_ci		status = sanei_pio_open(&s->hw->sane.name[4], &s->fd);
496141cc406Sopenharmony_ci
497141cc406Sopenharmony_ci	else if (s->hw->connection == SANE_EPSON_USB)
498141cc406Sopenharmony_ci		status = sanei_usb_open(s->hw->sane.name, &s->fd);
499141cc406Sopenharmony_ci
500141cc406Sopenharmony_ci	if (status == SANE_STATUS_ACCESS_DENIED) {
501141cc406Sopenharmony_ci		DBG(1, "please check that you have permissions on the device.\n");
502141cc406Sopenharmony_ci		DBG(1, "if this is a multi-function device with a printer,\n");
503141cc406Sopenharmony_ci		DBG(1, "disable any conflicting driver (like usblp).\n");
504141cc406Sopenharmony_ci	}
505141cc406Sopenharmony_ci
506141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
507141cc406Sopenharmony_ci		DBG(1, "%s open failed: %s\n", s->hw->sane.name,
508141cc406Sopenharmony_ci			sane_strstatus(status));
509141cc406Sopenharmony_ci	else
510141cc406Sopenharmony_ci		DBG(5, "scanner opened\n");
511141cc406Sopenharmony_ci
512141cc406Sopenharmony_ci	return status;
513141cc406Sopenharmony_ci}
514141cc406Sopenharmony_ci
515141cc406Sopenharmony_cistatic SANE_Status detect_scsi(struct Epson_Scanner *s)
516141cc406Sopenharmony_ci{
517141cc406Sopenharmony_ci	SANE_Status status;
518141cc406Sopenharmony_ci	struct Epson_Device *dev = s->hw;
519141cc406Sopenharmony_ci
520141cc406Sopenharmony_ci	char buf[INQUIRY_BUF_SIZE + 1];
521141cc406Sopenharmony_ci	size_t buf_size = INQUIRY_BUF_SIZE;
522141cc406Sopenharmony_ci
523141cc406Sopenharmony_ci	char *vendor = buf + 8;
524141cc406Sopenharmony_ci	char *model = buf + 16;
525141cc406Sopenharmony_ci	char *rev = buf + 32;
526141cc406Sopenharmony_ci
527141cc406Sopenharmony_ci	status = sanei_epson2_scsi_inquiry(s->fd, buf, &buf_size);
528141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
529141cc406Sopenharmony_ci		DBG(1, "%s: inquiry failed: %s\n", __func__,
530141cc406Sopenharmony_ci		    sane_strstatus(status));
531141cc406Sopenharmony_ci		return status;
532141cc406Sopenharmony_ci	}
533141cc406Sopenharmony_ci
534141cc406Sopenharmony_ci	buf[INQUIRY_BUF_SIZE] = 0;
535141cc406Sopenharmony_ci	DBG(1, "inquiry data:\n");
536141cc406Sopenharmony_ci	DBG(1, " vendor  : %.8s\n", vendor);
537141cc406Sopenharmony_ci	DBG(1, " model   : %.16s\n", model);
538141cc406Sopenharmony_ci	DBG(1, " revision: %.4s\n", rev);
539141cc406Sopenharmony_ci
540141cc406Sopenharmony_ci	if (buf[0] != TYPE_PROCESSOR) {
541141cc406Sopenharmony_ci		DBG(1, "%s: device is not of processor type (%d)\n",
542141cc406Sopenharmony_ci		    __func__, buf[0]);
543141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
544141cc406Sopenharmony_ci	}
545141cc406Sopenharmony_ci
546141cc406Sopenharmony_ci	if (strncmp(vendor, "EPSON", 5) != 0) {
547141cc406Sopenharmony_ci		DBG(1,
548141cc406Sopenharmony_ci		    "%s: device doesn't look like an EPSON scanner\n",
549141cc406Sopenharmony_ci		    __func__);
550141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
551141cc406Sopenharmony_ci	}
552141cc406Sopenharmony_ci
553141cc406Sopenharmony_ci	if (strncmp(model, "SCANNER ", 8) != 0
554141cc406Sopenharmony_ci	    && strncmp(model, "FilmScan 200", 12) != 0
555141cc406Sopenharmony_ci	    && strncmp(model, "Perfection", 10) != 0
556141cc406Sopenharmony_ci	    && strncmp(model, "Expression", 10) != 0
557141cc406Sopenharmony_ci	    && strncmp(model, "GT", 2) != 0) {
558141cc406Sopenharmony_ci		DBG(1, "%s: this EPSON scanner is not supported\n",
559141cc406Sopenharmony_ci		    __func__);
560141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
561141cc406Sopenharmony_ci	}
562141cc406Sopenharmony_ci
563141cc406Sopenharmony_ci	if (strncmp(model, "FilmScan 200", 12) == 0) {
564141cc406Sopenharmony_ci		dev->sane.type = "film scanner";
565141cc406Sopenharmony_ci		e2_set_model(s, (unsigned char *) model, 12);
566141cc406Sopenharmony_ci	}
567141cc406Sopenharmony_ci
568141cc406Sopenharmony_ci	/* Issue a test unit ready SCSI command. The FilmScan 200
569141cc406Sopenharmony_ci	 * requires it for a sort of "wake up". We might eventually
570141cc406Sopenharmony_ci	 * get the return code and reissue it in case of failure.
571141cc406Sopenharmony_ci	 */
572141cc406Sopenharmony_ci	sanei_epson2_scsi_test_unit_ready(s->fd);
573141cc406Sopenharmony_ci
574141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
575141cc406Sopenharmony_ci}
576141cc406Sopenharmony_ci
577141cc406Sopenharmony_cistatic SANE_Status
578141cc406Sopenharmony_cidetect_usb(struct Epson_Scanner *s, SANE_Bool assume_valid)
579141cc406Sopenharmony_ci{
580141cc406Sopenharmony_ci	SANE_Status status;
581141cc406Sopenharmony_ci	int vendor, product;
582141cc406Sopenharmony_ci	int i, numIds;
583141cc406Sopenharmony_ci	SANE_Bool is_valid = assume_valid;
584141cc406Sopenharmony_ci
585141cc406Sopenharmony_ci	/* if the sanei_usb_get_vendor_product call is not supported,
586141cc406Sopenharmony_ci	 * then we just ignore this and rely on the user to config
587141cc406Sopenharmony_ci	 * the correct device.
588141cc406Sopenharmony_ci	 */
589141cc406Sopenharmony_ci
590141cc406Sopenharmony_ci	status = sanei_usb_get_vendor_product(s->fd, &vendor, &product);
591141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
592141cc406Sopenharmony_ci		DBG(1, "the device cannot be verified - will continue\n");
593141cc406Sopenharmony_ci	 	return SANE_STATUS_GOOD;
594141cc406Sopenharmony_ci	}
595141cc406Sopenharmony_ci
596141cc406Sopenharmony_ci	/* check the vendor ID to see if we are dealing with an EPSON device */
597141cc406Sopenharmony_ci	if (vendor != SANE_EPSON_VENDOR_ID) {
598141cc406Sopenharmony_ci		/* this is not a supported vendor ID */
599141cc406Sopenharmony_ci		DBG(1, "not an Epson device at %s (vendor id=0x%x)\n",
600141cc406Sopenharmony_ci			s->hw->sane.name, vendor);
601141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
602141cc406Sopenharmony_ci	}
603141cc406Sopenharmony_ci
604141cc406Sopenharmony_ci	numIds = sanei_epson_getNumberOfUSBProductIds();
605141cc406Sopenharmony_ci	i = 0;
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci	/* check all known product IDs to verify that we know
608141cc406Sopenharmony_ci	   about the device */
609141cc406Sopenharmony_ci	while (i != numIds) {
610141cc406Sopenharmony_ci		if (product == sanei_epson_usb_product_ids[i]) {
611141cc406Sopenharmony_ci			is_valid = SANE_TRUE;
612141cc406Sopenharmony_ci			break;
613141cc406Sopenharmony_ci		}
614141cc406Sopenharmony_ci		i++;
615141cc406Sopenharmony_ci	}
616141cc406Sopenharmony_ci
617141cc406Sopenharmony_ci	if (is_valid == SANE_FALSE) {
618141cc406Sopenharmony_ci		DBG(1, "the device at %s is not supported (product id=0x%x)\n",
619141cc406Sopenharmony_ci			s->hw->sane.name, product);
620141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
621141cc406Sopenharmony_ci	}
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci	DBG(1, "found valid Epson scanner: 0x%x/0x%x (vendorID/productID)\n",
624141cc406Sopenharmony_ci		vendor, product);
625141cc406Sopenharmony_ci
626141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
627141cc406Sopenharmony_ci}
628141cc406Sopenharmony_ci
629141cc406Sopenharmony_cistatic int num_devices;		/* number of scanners attached to backend */
630141cc406Sopenharmony_cistatic Epson_Device *first_dev;	/* first EPSON scanner in list */
631141cc406Sopenharmony_ci
632141cc406Sopenharmony_cistatic struct Epson_Scanner *
633141cc406Sopenharmony_ciscanner_create(struct Epson_Device *dev, SANE_Status *status)
634141cc406Sopenharmony_ci{
635141cc406Sopenharmony_ci	struct Epson_Scanner *s;
636141cc406Sopenharmony_ci
637141cc406Sopenharmony_ci	s = malloc(sizeof(struct Epson_Scanner));
638141cc406Sopenharmony_ci	if (s == NULL) {
639141cc406Sopenharmony_ci		*status = SANE_STATUS_NO_MEM;
640141cc406Sopenharmony_ci		return NULL;
641141cc406Sopenharmony_ci	}
642141cc406Sopenharmony_ci
643141cc406Sopenharmony_ci	memset(s, 0x00, sizeof(struct Epson_Scanner));
644141cc406Sopenharmony_ci
645141cc406Sopenharmony_ci	s->fd = -1;
646141cc406Sopenharmony_ci	s->hw = dev;
647141cc406Sopenharmony_ci
648141cc406Sopenharmony_ci	return s;
649141cc406Sopenharmony_ci}
650141cc406Sopenharmony_ci
651141cc406Sopenharmony_cistatic struct Epson_Scanner *
652141cc406Sopenharmony_cidevice_detect(const char *name, int type, SANE_Bool assume_valid, SANE_Status *status)
653141cc406Sopenharmony_ci{
654141cc406Sopenharmony_ci	struct Epson_Scanner *s;
655141cc406Sopenharmony_ci	struct Epson_Device *dev;
656141cc406Sopenharmony_ci
657141cc406Sopenharmony_ci	/* try to find the device in our list */
658141cc406Sopenharmony_ci	for (dev = first_dev; dev; dev = dev->next) {
659141cc406Sopenharmony_ci		if (strcmp(dev->sane.name, name) == 0) {
660141cc406Sopenharmony_ci
661141cc406Sopenharmony_ci			/* the device might have been just probed,
662141cc406Sopenharmony_ci			 * sleep a bit.
663141cc406Sopenharmony_ci			 */
664141cc406Sopenharmony_ci			if (dev->connection == SANE_EPSON_NET)
665141cc406Sopenharmony_ci				sleep(1);
666141cc406Sopenharmony_ci
667141cc406Sopenharmony_ci			return scanner_create(dev, status);
668141cc406Sopenharmony_ci		}
669141cc406Sopenharmony_ci	}
670141cc406Sopenharmony_ci
671141cc406Sopenharmony_ci	if (type == SANE_EPSON_NODEV) {
672141cc406Sopenharmony_ci		*status = SANE_STATUS_INVAL;
673141cc406Sopenharmony_ci		return NULL;
674141cc406Sopenharmony_ci	}
675141cc406Sopenharmony_ci
676141cc406Sopenharmony_ci	/* alloc and clear our device structure */
677141cc406Sopenharmony_ci	dev = malloc(sizeof(*dev));
678141cc406Sopenharmony_ci	if (!dev) {
679141cc406Sopenharmony_ci		*status = SANE_STATUS_NO_MEM;
680141cc406Sopenharmony_ci		return NULL;
681141cc406Sopenharmony_ci	}
682141cc406Sopenharmony_ci	memset(dev, 0x00, sizeof(struct Epson_Device));
683141cc406Sopenharmony_ci
684141cc406Sopenharmony_ci	s = scanner_create(dev, status);
685141cc406Sopenharmony_ci	if (s == NULL)
686141cc406Sopenharmony_ci		return NULL;
687141cc406Sopenharmony_ci
688141cc406Sopenharmony_ci	e2_dev_init(dev, name, type);
689141cc406Sopenharmony_ci
690141cc406Sopenharmony_ci	*status = open_scanner(s);
691141cc406Sopenharmony_ci	if (*status != SANE_STATUS_GOOD) {
692141cc406Sopenharmony_ci		free(s);
693141cc406Sopenharmony_ci		return NULL;
694141cc406Sopenharmony_ci	}
695141cc406Sopenharmony_ci
696141cc406Sopenharmony_ci	/* from now on, close_scanner() must be called */
697141cc406Sopenharmony_ci
698141cc406Sopenharmony_ci	/* SCSI and USB requires special care */
699141cc406Sopenharmony_ci	if (dev->connection == SANE_EPSON_SCSI) {
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci		*status = detect_scsi(s);
702141cc406Sopenharmony_ci
703141cc406Sopenharmony_ci	} else if (dev->connection == SANE_EPSON_USB) {
704141cc406Sopenharmony_ci
705141cc406Sopenharmony_ci		*status = detect_usb(s, assume_valid);
706141cc406Sopenharmony_ci	}
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci	if (*status != SANE_STATUS_GOOD)
709141cc406Sopenharmony_ci		goto close;
710141cc406Sopenharmony_ci
711141cc406Sopenharmony_ci	/* set name and model (if not already set) */
712141cc406Sopenharmony_ci	if (dev->model == NULL)
713141cc406Sopenharmony_ci		e2_set_model(s, (unsigned char *) "generic", 7);
714141cc406Sopenharmony_ci
715141cc406Sopenharmony_ci	dev->name = strdup(name);
716141cc406Sopenharmony_ci	dev->sane.name = dev->name;
717141cc406Sopenharmony_ci
718141cc406Sopenharmony_ci	/* ESC @, reset */
719141cc406Sopenharmony_ci	*status = esci_reset(s);
720141cc406Sopenharmony_ci	if (*status != SANE_STATUS_GOOD)
721141cc406Sopenharmony_ci		goto close;
722141cc406Sopenharmony_ci
723141cc406Sopenharmony_ci	*status = e2_discover_capabilities(s);
724141cc406Sopenharmony_ci	if (*status != SANE_STATUS_GOOD)
725141cc406Sopenharmony_ci		goto close;
726141cc406Sopenharmony_ci
727141cc406Sopenharmony_ci	if (source_list[0] == NULL || dev->dpi_range.min == 0) {
728141cc406Sopenharmony_ci		DBG(1, "something is wrong in the discovery process, aborting.\n");
729141cc406Sopenharmony_ci		*status = SANE_STATUS_IO_ERROR;
730141cc406Sopenharmony_ci		goto close;
731141cc406Sopenharmony_ci	}
732141cc406Sopenharmony_ci
733141cc406Sopenharmony_ci	e2_dev_post_init(dev);
734141cc406Sopenharmony_ci
735141cc406Sopenharmony_ci	*status = esci_reset(s);
736141cc406Sopenharmony_ci	if (*status != SANE_STATUS_GOOD)
737141cc406Sopenharmony_ci		goto close;
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_ci	DBG(1, "scanner model: %s\n", dev->model);
740141cc406Sopenharmony_ci
741141cc406Sopenharmony_ci	/* add this scanner to the device list */
742141cc406Sopenharmony_ci
743141cc406Sopenharmony_ci	num_devices++;
744141cc406Sopenharmony_ci	dev->next = first_dev;
745141cc406Sopenharmony_ci	first_dev = dev;
746141cc406Sopenharmony_ci
747141cc406Sopenharmony_ci	return s;
748141cc406Sopenharmony_ci
749141cc406Sopenharmony_ciclose:
750141cc406Sopenharmony_ci      	close_scanner(s);
751141cc406Sopenharmony_ci	return NULL;
752141cc406Sopenharmony_ci}
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci
755141cc406Sopenharmony_cistatic SANE_Status
756141cc406Sopenharmony_ciattach(const char *name, int type)
757141cc406Sopenharmony_ci{
758141cc406Sopenharmony_ci	SANE_Status status;
759141cc406Sopenharmony_ci	Epson_Scanner *s;
760141cc406Sopenharmony_ci
761141cc406Sopenharmony_ci	DBG(7, "%s: devname = %s, type = %d\n", __func__, name, type);
762141cc406Sopenharmony_ci
763141cc406Sopenharmony_ci	s = device_detect(name, type, 0, &status);
764141cc406Sopenharmony_ci	if(s == NULL)
765141cc406Sopenharmony_ci		return status;
766141cc406Sopenharmony_ci
767141cc406Sopenharmony_ci      	close_scanner(s);
768141cc406Sopenharmony_ci	return status;
769141cc406Sopenharmony_ci}
770141cc406Sopenharmony_ci
771141cc406Sopenharmony_cistatic SANE_Status
772141cc406Sopenharmony_ciattach_one_scsi(const char *dev)
773141cc406Sopenharmony_ci{
774141cc406Sopenharmony_ci	DBG(7, "%s: dev = %s\n", __func__, dev);
775141cc406Sopenharmony_ci	return attach(dev, SANE_EPSON_SCSI);
776141cc406Sopenharmony_ci}
777141cc406Sopenharmony_ci
778141cc406Sopenharmony_ciSANE_Status
779141cc406Sopenharmony_ciattach_one_usb(const char *dev)
780141cc406Sopenharmony_ci{
781141cc406Sopenharmony_ci	DBG(7, "%s: dev = %s\n", __func__, dev);
782141cc406Sopenharmony_ci	return attach(dev, SANE_EPSON_USB);
783141cc406Sopenharmony_ci}
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_cistatic SANE_Status
786141cc406Sopenharmony_ciattach_one_net(const char *dev)
787141cc406Sopenharmony_ci{
788141cc406Sopenharmony_ci        char name[39+4];
789141cc406Sopenharmony_ci
790141cc406Sopenharmony_ci	DBG(7, "%s: dev = %s\n", __func__, dev);
791141cc406Sopenharmony_ci
792141cc406Sopenharmony_ci	strcpy(name, "net:");
793141cc406Sopenharmony_ci	strcat(name, dev);
794141cc406Sopenharmony_ci	return attach(name, SANE_EPSON_NET);
795141cc406Sopenharmony_ci}
796141cc406Sopenharmony_ci
797141cc406Sopenharmony_cistatic SANE_Status
798141cc406Sopenharmony_ciattach_one_pio(const char *dev)
799141cc406Sopenharmony_ci{
800141cc406Sopenharmony_ci	DBG(7, "%s: dev = %s\n", __func__, dev);
801141cc406Sopenharmony_ci	return attach(dev, SANE_EPSON_PIO);
802141cc406Sopenharmony_ci}
803141cc406Sopenharmony_ci
804141cc406Sopenharmony_cistatic SANE_Status
805141cc406Sopenharmony_ciattach_one_config(SANEI_Config __sane_unused__ *config, const char *line,
806141cc406Sopenharmony_ci		  void *data)
807141cc406Sopenharmony_ci{
808141cc406Sopenharmony_ci	int vendor, product;
809141cc406Sopenharmony_ci	SANE_Bool local_only = *(SANE_Bool*) data;
810141cc406Sopenharmony_ci	int len = strlen(line);
811141cc406Sopenharmony_ci
812141cc406Sopenharmony_ci	DBG(7, "%s: len = %d, line = %s\n", __func__, len, line);
813141cc406Sopenharmony_ci
814141cc406Sopenharmony_ci	if (sscanf(line, "usb %i %i", &vendor, &product) == 2) {
815141cc406Sopenharmony_ci
816141cc406Sopenharmony_ci		/* add the vendor and product IDs to the list of
817141cc406Sopenharmony_ci		   known devices before we call the attach function */
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_ci		int numIds = sanei_epson_getNumberOfUSBProductIds();
820141cc406Sopenharmony_ci
821141cc406Sopenharmony_ci		if (vendor != 0x4b8)
822141cc406Sopenharmony_ci			return SANE_STATUS_INVAL; /* this is not an EPSON device */
823141cc406Sopenharmony_ci
824141cc406Sopenharmony_ci		sanei_epson_usb_product_ids[numIds - 1] = product;
825141cc406Sopenharmony_ci		sanei_usb_attach_matching_devices(line, attach_one_usb);
826141cc406Sopenharmony_ci
827141cc406Sopenharmony_ci	} else if (strncmp(line, "usb", 3) == 0 && len == 3) {
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci		int i, numIds;
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci		numIds = sanei_epson_getNumberOfUSBProductIds();
832141cc406Sopenharmony_ci
833141cc406Sopenharmony_ci		for (i = 0; i < numIds; i++) {
834141cc406Sopenharmony_ci			sanei_usb_find_devices(0x4b8,
835141cc406Sopenharmony_ci					sanei_epson_usb_product_ids[i], attach_one_usb);
836141cc406Sopenharmony_ci		}
837141cc406Sopenharmony_ci
838141cc406Sopenharmony_ci	} else if (strncmp(line, "net", 3) == 0) {
839141cc406Sopenharmony_ci
840141cc406Sopenharmony_ci		if (!local_only) {
841141cc406Sopenharmony_ci			/* remove the "net" sub string */
842141cc406Sopenharmony_ci			const char *name =
843141cc406Sopenharmony_ci				sanei_config_skip_whitespace(line + 3);
844141cc406Sopenharmony_ci
845141cc406Sopenharmony_ci			if (strncmp(name, "autodiscovery", 13) == 0)
846141cc406Sopenharmony_ci				e2_network_discovery();
847141cc406Sopenharmony_ci			else
848141cc406Sopenharmony_ci				attach_one_net(name);
849141cc406Sopenharmony_ci		}
850141cc406Sopenharmony_ci
851141cc406Sopenharmony_ci	} else if (strncmp(line, "pio", 3) == 0) {
852141cc406Sopenharmony_ci
853141cc406Sopenharmony_ci		/* remove the "pio" sub string */
854141cc406Sopenharmony_ci		const char *name = sanei_config_skip_whitespace(line + 3);
855141cc406Sopenharmony_ci
856141cc406Sopenharmony_ci		attach_one_pio(name);
857141cc406Sopenharmony_ci
858141cc406Sopenharmony_ci	} else {
859141cc406Sopenharmony_ci		sanei_config_attach_matching_devices(line, attach_one_scsi);
860141cc406Sopenharmony_ci	}
861141cc406Sopenharmony_ci
862141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
863141cc406Sopenharmony_ci}
864141cc406Sopenharmony_ci
865141cc406Sopenharmony_cistatic void
866141cc406Sopenharmony_cifree_devices(void)
867141cc406Sopenharmony_ci{
868141cc406Sopenharmony_ci	Epson_Device *dev, *next;
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_ci	DBG(5, "%s\n", __func__);
871141cc406Sopenharmony_ci
872141cc406Sopenharmony_ci	for (dev = first_dev; dev; dev = next) {
873141cc406Sopenharmony_ci		next = dev->next;
874141cc406Sopenharmony_ci		free(dev->name);
875141cc406Sopenharmony_ci		free(dev->model);
876141cc406Sopenharmony_ci		free(dev);
877141cc406Sopenharmony_ci	}
878141cc406Sopenharmony_ci
879141cc406Sopenharmony_ci	free(devlist);
880141cc406Sopenharmony_ci
881141cc406Sopenharmony_ci	first_dev = NULL;
882141cc406Sopenharmony_ci}
883141cc406Sopenharmony_ci
884141cc406Sopenharmony_cistatic void
885141cc406Sopenharmony_ciprobe_devices(SANE_Bool local_only)
886141cc406Sopenharmony_ci{
887141cc406Sopenharmony_ci	DBG(5, "%s\n", __func__);
888141cc406Sopenharmony_ci
889141cc406Sopenharmony_ci	free_devices();
890141cc406Sopenharmony_ci
891141cc406Sopenharmony_ci	sanei_configure_attach(EPSON2_CONFIG_FILE, NULL,
892141cc406Sopenharmony_ci		attach_one_config, &local_only);
893141cc406Sopenharmony_ci}
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ciSANE_Status
896141cc406Sopenharmony_cisane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize)
897141cc406Sopenharmony_ci{
898141cc406Sopenharmony_ci	DBG_INIT();
899141cc406Sopenharmony_ci	DBG(1, "%s: version " VERSION "\n", __func__);
900141cc406Sopenharmony_ci
901141cc406Sopenharmony_ci	/* Keep '124' as our build version. The arg is obsolete by now */
902141cc406Sopenharmony_ci	if (version_code)
903141cc406Sopenharmony_ci		*version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 124);
904141cc406Sopenharmony_ci
905141cc406Sopenharmony_ci	sanei_usb_init();
906141cc406Sopenharmony_ci	sanei_usb_set_timeout(60 * 1000);
907141cc406Sopenharmony_ci
908141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
909141cc406Sopenharmony_ci}
910141cc406Sopenharmony_ci
911141cc406Sopenharmony_ci/* Clean up the list of attached scanners. */
912141cc406Sopenharmony_civoid
913141cc406Sopenharmony_cisane_exit(void)
914141cc406Sopenharmony_ci{
915141cc406Sopenharmony_ci	DBG(5, "%s\n", __func__);
916141cc406Sopenharmony_ci	free_devices();
917141cc406Sopenharmony_ci}
918141cc406Sopenharmony_ci
919141cc406Sopenharmony_ciSANE_Status
920141cc406Sopenharmony_cisane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
921141cc406Sopenharmony_ci{
922141cc406Sopenharmony_ci	Epson_Device *dev;
923141cc406Sopenharmony_ci	int i;
924141cc406Sopenharmony_ci
925141cc406Sopenharmony_ci	DBG(5, "%s\n", __func__);
926141cc406Sopenharmony_ci
927141cc406Sopenharmony_ci	probe_devices(local_only);
928141cc406Sopenharmony_ci
929141cc406Sopenharmony_ci	devlist = malloc((num_devices + 1) * sizeof(devlist[0]));
930141cc406Sopenharmony_ci	if (!devlist) {
931141cc406Sopenharmony_ci		DBG(1, "out of memory (line %d)\n", __LINE__);
932141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
933141cc406Sopenharmony_ci	}
934141cc406Sopenharmony_ci
935141cc406Sopenharmony_ci	DBG(5, "%s - results:\n", __func__);
936141cc406Sopenharmony_ci
937141cc406Sopenharmony_ci	for (i = 0, dev = first_dev; i < num_devices && dev; dev = dev->next, i++) {
938141cc406Sopenharmony_ci		DBG(1, " %d (%d): %s\n", i, dev->connection, dev->model);
939141cc406Sopenharmony_ci		devlist[i] = &dev->sane;
940141cc406Sopenharmony_ci	}
941141cc406Sopenharmony_ci
942141cc406Sopenharmony_ci	devlist[i] = NULL;
943141cc406Sopenharmony_ci
944141cc406Sopenharmony_ci	*device_list = devlist;
945141cc406Sopenharmony_ci
946141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
947141cc406Sopenharmony_ci}
948141cc406Sopenharmony_ci
949141cc406Sopenharmony_cistatic SANE_Status
950141cc406Sopenharmony_ciinit_options(Epson_Scanner *s)
951141cc406Sopenharmony_ci{
952141cc406Sopenharmony_ci	int i;
953141cc406Sopenharmony_ci
954141cc406Sopenharmony_ci	for (i = 0; i < NUM_OPTIONS; i++) {
955141cc406Sopenharmony_ci		s->opt[i].size = sizeof(SANE_Word);
956141cc406Sopenharmony_ci		s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
957141cc406Sopenharmony_ci	}
958141cc406Sopenharmony_ci
959141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
960141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
961141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
962141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
963141cc406Sopenharmony_ci	s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
964141cc406Sopenharmony_ci
965141cc406Sopenharmony_ci	/* "Scan Mode" group: */
966141cc406Sopenharmony_ci
967141cc406Sopenharmony_ci	s->opt[OPT_MODE_GROUP].title = SANE_I18N("Scan Mode");
968141cc406Sopenharmony_ci	s->opt[OPT_MODE_GROUP].desc = "";
969141cc406Sopenharmony_ci	s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
970141cc406Sopenharmony_ci	s->opt[OPT_MODE_GROUP].cap = 0;
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_ci	/* scan mode */
973141cc406Sopenharmony_ci	s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
974141cc406Sopenharmony_ci	s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
975141cc406Sopenharmony_ci	s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
976141cc406Sopenharmony_ci	s->opt[OPT_MODE].type = SANE_TYPE_STRING;
977141cc406Sopenharmony_ci	s->opt[OPT_MODE].size = max_string_size(mode_list);
978141cc406Sopenharmony_ci	s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
979141cc406Sopenharmony_ci	s->opt[OPT_MODE].constraint.string_list = mode_list;
980141cc406Sopenharmony_ci	s->val[OPT_MODE].w = 0;	/* Lineart */
981141cc406Sopenharmony_ci
982141cc406Sopenharmony_ci	/* disable infrared on unsupported scanners */
983141cc406Sopenharmony_ci	if (!e2_model(s, "GT-X800") && !e2_model(s, "GT-X700") && !e2_model(s, "GT-X900") && !e2_model(s, "GT-X980"))
984141cc406Sopenharmony_ci		mode_list[MODE_INFRARED] = NULL;
985141cc406Sopenharmony_ci
986141cc406Sopenharmony_ci	/* bit depth */
987141cc406Sopenharmony_ci	s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH;
988141cc406Sopenharmony_ci	s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
989141cc406Sopenharmony_ci	s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH;
990141cc406Sopenharmony_ci	s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT;
991141cc406Sopenharmony_ci	s->opt[OPT_BIT_DEPTH].unit = SANE_UNIT_BIT;
992141cc406Sopenharmony_ci	s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
993141cc406Sopenharmony_ci	s->opt[OPT_BIT_DEPTH].constraint.word_list = s->hw->depth_list;
994141cc406Sopenharmony_ci	s->val[OPT_BIT_DEPTH].w = 8; /* default to 8 bit */
995141cc406Sopenharmony_ci
996141cc406Sopenharmony_ci	/* default is Lineart, disable depth selection */
997141cc406Sopenharmony_ci	s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
998141cc406Sopenharmony_ci
999141cc406Sopenharmony_ci	/* halftone */
1000141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].name = SANE_NAME_HALFTONE;
1001141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].title = SANE_TITLE_HALFTONE;
1002141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].desc = SANE_I18N("Selects the halftone.");
1003141cc406Sopenharmony_ci
1004141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].type = SANE_TYPE_STRING;
1005141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].size = max_string_size(halftone_list_7);
1006141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1007141cc406Sopenharmony_ci
1008141cc406Sopenharmony_ci	/* XXX use defines */
1009141cc406Sopenharmony_ci	if (s->hw->level >= 7)
1010141cc406Sopenharmony_ci		s->opt[OPT_HALFTONE].constraint.string_list = halftone_list_7;
1011141cc406Sopenharmony_ci	else if (s->hw->level >= 4)
1012141cc406Sopenharmony_ci		s->opt[OPT_HALFTONE].constraint.string_list = halftone_list_4;
1013141cc406Sopenharmony_ci	else
1014141cc406Sopenharmony_ci		s->opt[OPT_HALFTONE].constraint.string_list = halftone_list;
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci	s->val[OPT_HALFTONE].w = 1;	/* Halftone A */
1017141cc406Sopenharmony_ci
1018141cc406Sopenharmony_ci	if (!s->hw->cmd->set_halftoning)
1019141cc406Sopenharmony_ci		s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
1020141cc406Sopenharmony_ci
1021141cc406Sopenharmony_ci	/* dropout */
1022141cc406Sopenharmony_ci	s->opt[OPT_DROPOUT].name = "dropout";
1023141cc406Sopenharmony_ci	s->opt[OPT_DROPOUT].title = SANE_I18N("Dropout");
1024141cc406Sopenharmony_ci	s->opt[OPT_DROPOUT].desc = SANE_I18N("Selects the dropout.");
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci	s->opt[OPT_DROPOUT].type = SANE_TYPE_STRING;
1027141cc406Sopenharmony_ci	s->opt[OPT_DROPOUT].size = max_string_size(dropout_list);
1028141cc406Sopenharmony_ci	s->opt[OPT_DROPOUT].cap |= SANE_CAP_ADVANCED;
1029141cc406Sopenharmony_ci	s->opt[OPT_DROPOUT].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1030141cc406Sopenharmony_ci	s->opt[OPT_DROPOUT].constraint.string_list = dropout_list;
1031141cc406Sopenharmony_ci	s->val[OPT_DROPOUT].w = 0;	/* None */
1032141cc406Sopenharmony_ci
1033141cc406Sopenharmony_ci	/* brightness */
1034141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
1035141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
1036141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].desc = SANE_I18N("Selects the brightness.");
1037141cc406Sopenharmony_ci
1038141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
1039141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
1040141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
1041141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].constraint.range = &s->hw->cmd->bright_range;
1042141cc406Sopenharmony_ci	s->val[OPT_BRIGHTNESS].w = 0;	/* Normal */
1043141cc406Sopenharmony_ci
1044141cc406Sopenharmony_ci	if (!s->hw->cmd->set_bright)
1045141cc406Sopenharmony_ci		s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
1046141cc406Sopenharmony_ci
1047141cc406Sopenharmony_ci	/* sharpness */
1048141cc406Sopenharmony_ci	s->opt[OPT_SHARPNESS].name = "sharpness";
1049141cc406Sopenharmony_ci	s->opt[OPT_SHARPNESS].title = SANE_I18N("Sharpness");
1050141cc406Sopenharmony_ci	s->opt[OPT_SHARPNESS].desc = "";
1051141cc406Sopenharmony_ci
1052141cc406Sopenharmony_ci	s->opt[OPT_SHARPNESS].type = SANE_TYPE_INT;
1053141cc406Sopenharmony_ci	s->opt[OPT_SHARPNESS].unit = SANE_UNIT_NONE;
1054141cc406Sopenharmony_ci	s->opt[OPT_SHARPNESS].constraint_type = SANE_CONSTRAINT_RANGE;
1055141cc406Sopenharmony_ci	s->opt[OPT_SHARPNESS].constraint.range = &outline_emphasis_range;
1056141cc406Sopenharmony_ci	s->val[OPT_SHARPNESS].w = 0;	/* Normal */
1057141cc406Sopenharmony_ci
1058141cc406Sopenharmony_ci	if (!s->hw->cmd->set_outline_emphasis)
1059141cc406Sopenharmony_ci		s->opt[OPT_SHARPNESS].cap |= SANE_CAP_INACTIVE;
1060141cc406Sopenharmony_ci
1061141cc406Sopenharmony_ci	/* gamma */
1062141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_CORRECTION].name = SANE_NAME_GAMMA_CORRECTION;
1063141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_CORRECTION].title = SANE_TITLE_GAMMA_CORRECTION;
1064141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_CORRECTION].desc = SANE_DESC_GAMMA_CORRECTION;
1065141cc406Sopenharmony_ci
1066141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_CORRECTION].type = SANE_TYPE_STRING;
1067141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_CORRECTION].constraint_type =
1068141cc406Sopenharmony_ci		SANE_CONSTRAINT_STRING_LIST;
1069141cc406Sopenharmony_ci
1070141cc406Sopenharmony_ci	/*
1071141cc406Sopenharmony_ci	 * special handling for D1 function level - at this time I'm not
1072141cc406Sopenharmony_ci	 * testing for D1, I'm just assuming that all D level scanners will
1073141cc406Sopenharmony_ci	 * behave the same way. This has to be confirmed with the next D-level
1074141cc406Sopenharmony_ci	 * scanner
1075141cc406Sopenharmony_ci	 */
1076141cc406Sopenharmony_ci	if (s->hw->cmd->level[0] == 'D') {
1077141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_CORRECTION].size =
1078141cc406Sopenharmony_ci			max_string_size(gamma_list_d);
1079141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_CORRECTION].constraint.string_list =
1080141cc406Sopenharmony_ci			gamma_list_d;
1081141cc406Sopenharmony_ci		s->val[OPT_GAMMA_CORRECTION].w = 1;	/* Default */
1082141cc406Sopenharmony_ci		gamma_userdefined = gamma_userdefined_d;
1083141cc406Sopenharmony_ci		gamma_params = gamma_params_d;
1084141cc406Sopenharmony_ci	} else {
1085141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_CORRECTION].size =
1086141cc406Sopenharmony_ci			max_string_size(gamma_list_ab);
1087141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_CORRECTION].constraint.string_list =
1088141cc406Sopenharmony_ci			gamma_list_ab;
1089141cc406Sopenharmony_ci		s->val[OPT_GAMMA_CORRECTION].w = 0;	/* Default */
1090141cc406Sopenharmony_ci		gamma_userdefined = gamma_userdefined_ab;
1091141cc406Sopenharmony_ci		gamma_params = gamma_params_ab;
1092141cc406Sopenharmony_ci	}
1093141cc406Sopenharmony_ci
1094141cc406Sopenharmony_ci	if (!s->hw->cmd->set_gamma)
1095141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_CORRECTION].cap |= SANE_CAP_INACTIVE;
1096141cc406Sopenharmony_ci
1097141cc406Sopenharmony_ci	/* red gamma vector */
1098141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R;
1099141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
1100141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R;
1101141cc406Sopenharmony_ci
1102141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_R].type = SANE_TYPE_INT;
1103141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_R].unit = SANE_UNIT_NONE;
1104141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_R].size = 256 * sizeof(SANE_Word);
1105141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
1106141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &u8_range;
1107141cc406Sopenharmony_ci	s->val[OPT_GAMMA_VECTOR_R].wa = &s->gamma_table[0][0];
1108141cc406Sopenharmony_ci
1109141cc406Sopenharmony_ci	/* green gamma vector */
1110141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G;
1111141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
1112141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G;
1113141cc406Sopenharmony_ci
1114141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_G].type = SANE_TYPE_INT;
1115141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_G].unit = SANE_UNIT_NONE;
1116141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_G].size = 256 * sizeof(SANE_Word);
1117141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
1118141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &u8_range;
1119141cc406Sopenharmony_ci	s->val[OPT_GAMMA_VECTOR_G].wa = &s->gamma_table[1][0];
1120141cc406Sopenharmony_ci
1121141cc406Sopenharmony_ci
1122141cc406Sopenharmony_ci	/* red gamma vector */
1123141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B;
1124141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
1125141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B;
1126141cc406Sopenharmony_ci
1127141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_B].type = SANE_TYPE_INT;
1128141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_B].unit = SANE_UNIT_NONE;
1129141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_B].size = 256 * sizeof(SANE_Word);
1130141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
1131141cc406Sopenharmony_ci	s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range;
1132141cc406Sopenharmony_ci	s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[2][0];
1133141cc406Sopenharmony_ci
1134141cc406Sopenharmony_ci	if (s->hw->cmd->set_gamma_table
1135141cc406Sopenharmony_ci	    && gamma_userdefined[s->val[OPT_GAMMA_CORRECTION].w] ==
1136141cc406Sopenharmony_ci	    SANE_TRUE) {
1137141cc406Sopenharmony_ci
1138141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1139141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1140141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1141141cc406Sopenharmony_ci	} else {
1142141cc406Sopenharmony_ci
1143141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1144141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1145141cc406Sopenharmony_ci		s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1146141cc406Sopenharmony_ci	}
1147141cc406Sopenharmony_ci
1148141cc406Sopenharmony_ci	/* initialize the Gamma tables */
1149141cc406Sopenharmony_ci	memset(&s->gamma_table[0], 0, 256 * sizeof(SANE_Word));
1150141cc406Sopenharmony_ci	memset(&s->gamma_table[1], 0, 256 * sizeof(SANE_Word));
1151141cc406Sopenharmony_ci	memset(&s->gamma_table[2], 0, 256 * sizeof(SANE_Word));
1152141cc406Sopenharmony_ci
1153141cc406Sopenharmony_ci/*	memset(&s->gamma_table[3], 0, 256 * sizeof(SANE_Word)); */
1154141cc406Sopenharmony_ci	for (i = 0; i < 256; i++) {
1155141cc406Sopenharmony_ci		s->gamma_table[0][i] = i;
1156141cc406Sopenharmony_ci		s->gamma_table[1][i] = i;
1157141cc406Sopenharmony_ci		s->gamma_table[2][i] = i;
1158141cc406Sopenharmony_ci
1159141cc406Sopenharmony_ci/*		s->gamma_table[3][i] = i; */
1160141cc406Sopenharmony_ci	}
1161141cc406Sopenharmony_ci
1162141cc406Sopenharmony_ci
1163141cc406Sopenharmony_ci	/* color correction */
1164141cc406Sopenharmony_ci	s->opt[OPT_COLOR_CORRECTION].name = "color-correction";
1165141cc406Sopenharmony_ci	s->opt[OPT_COLOR_CORRECTION].title = SANE_I18N("Color correction");
1166141cc406Sopenharmony_ci	s->opt[OPT_COLOR_CORRECTION].desc =
1167141cc406Sopenharmony_ci		SANE_I18N("Sets the color correction table for the selected output device.");
1168141cc406Sopenharmony_ci
1169141cc406Sopenharmony_ci	s->opt[OPT_COLOR_CORRECTION].type = SANE_TYPE_STRING;
1170141cc406Sopenharmony_ci	s->opt[OPT_COLOR_CORRECTION].size = max_string_size(correction_list);
1171141cc406Sopenharmony_ci	s->opt[OPT_COLOR_CORRECTION].cap |= SANE_CAP_ADVANCED;
1172141cc406Sopenharmony_ci	s->opt[OPT_COLOR_CORRECTION].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1173141cc406Sopenharmony_ci	s->opt[OPT_COLOR_CORRECTION].constraint.string_list = correction_list;
1174141cc406Sopenharmony_ci	s->val[OPT_COLOR_CORRECTION].w = CORR_AUTO;
1175141cc406Sopenharmony_ci
1176141cc406Sopenharmony_ci	if (!s->hw->cmd->set_color_correction)
1177141cc406Sopenharmony_ci		s->opt[OPT_COLOR_CORRECTION].cap |= SANE_CAP_INACTIVE;
1178141cc406Sopenharmony_ci
1179141cc406Sopenharmony_ci	/* resolution */
1180141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
1181141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
1182141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
1183141cc406Sopenharmony_ci
1184141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
1185141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
1186141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
1187141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].constraint.word_list = s->hw->resolution_list;
1188141cc406Sopenharmony_ci	s->val[OPT_RESOLUTION].w = s->hw->dpi_range.min;
1189141cc406Sopenharmony_ci
1190141cc406Sopenharmony_ci	/* threshold */
1191141cc406Sopenharmony_ci	s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
1192141cc406Sopenharmony_ci	s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
1193141cc406Sopenharmony_ci	s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
1194141cc406Sopenharmony_ci
1195141cc406Sopenharmony_ci	s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
1196141cc406Sopenharmony_ci	s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
1197141cc406Sopenharmony_ci	s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
1198141cc406Sopenharmony_ci	s->opt[OPT_THRESHOLD].constraint.range = &u8_range;
1199141cc406Sopenharmony_ci	s->val[OPT_THRESHOLD].w = 0x80;
1200141cc406Sopenharmony_ci
1201141cc406Sopenharmony_ci	if (!s->hw->cmd->set_threshold)
1202141cc406Sopenharmony_ci		s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1203141cc406Sopenharmony_ci
1204141cc406Sopenharmony_ci
1205141cc406Sopenharmony_ci	/* "Advanced" group: */
1206141cc406Sopenharmony_ci	s->opt[OPT_ADVANCED_GROUP].title = SANE_I18N("Advanced");
1207141cc406Sopenharmony_ci	s->opt[OPT_ADVANCED_GROUP].desc = "";
1208141cc406Sopenharmony_ci	s->opt[OPT_ADVANCED_GROUP].type = SANE_TYPE_GROUP;
1209141cc406Sopenharmony_ci	s->opt[OPT_ADVANCED_GROUP].cap = SANE_CAP_ADVANCED;
1210141cc406Sopenharmony_ci
1211141cc406Sopenharmony_ci	/* "Color correction" group: */
1212141cc406Sopenharmony_ci	s->opt[OPT_CCT_GROUP].title = SANE_I18N("Color correction");
1213141cc406Sopenharmony_ci	s->opt[OPT_CCT_GROUP].desc = "";
1214141cc406Sopenharmony_ci	s->opt[OPT_CCT_GROUP].type = SANE_TYPE_GROUP;
1215141cc406Sopenharmony_ci	s->opt[OPT_CCT_GROUP].cap = SANE_CAP_ADVANCED;
1216141cc406Sopenharmony_ci
1217141cc406Sopenharmony_ci	/* XXX disabled for now */
1218141cc406Sopenharmony_ci	s->opt[OPT_CCT_MODE].name = "cct-type";
1219141cc406Sopenharmony_ci	s->opt[OPT_CCT_MODE].title = "CCT Profile Type";
1220141cc406Sopenharmony_ci	s->opt[OPT_CCT_MODE].desc = "Color correction profile type";
1221141cc406Sopenharmony_ci	s->opt[OPT_CCT_MODE].type = SANE_TYPE_STRING;
1222141cc406Sopenharmony_ci	s->opt[OPT_CCT_MODE].cap  |= SANE_CAP_ADVANCED | SANE_CAP_INACTIVE;
1223141cc406Sopenharmony_ci	s->opt[OPT_CCT_MODE].size = max_string_size(cct_mode_list);
1224141cc406Sopenharmony_ci	s->opt[OPT_CCT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1225141cc406Sopenharmony_ci	s->opt[OPT_CCT_MODE].constraint.string_list = cct_mode_list;
1226141cc406Sopenharmony_ci	s->val[OPT_CCT_MODE].w = CCT_AUTO;
1227141cc406Sopenharmony_ci
1228141cc406Sopenharmony_ci	s->opt[OPT_CCT_PROFILE].name = "cct-profile";
1229141cc406Sopenharmony_ci	s->opt[OPT_CCT_PROFILE].title = "CCT Profile";
1230141cc406Sopenharmony_ci	s->opt[OPT_CCT_PROFILE].desc = "Color correction profile data";
1231141cc406Sopenharmony_ci	s->opt[OPT_CCT_PROFILE].type = SANE_TYPE_FIXED;
1232141cc406Sopenharmony_ci	s->opt[OPT_CCT_PROFILE].cap  |= SANE_CAP_ADVANCED;
1233141cc406Sopenharmony_ci	s->opt[OPT_CCT_PROFILE].unit = SANE_UNIT_NONE;
1234141cc406Sopenharmony_ci	s->opt[OPT_CCT_PROFILE].constraint_type = SANE_CONSTRAINT_RANGE;
1235141cc406Sopenharmony_ci	s->opt[OPT_CCT_PROFILE].constraint.range = &fx_range;
1236141cc406Sopenharmony_ci	s->opt[OPT_CCT_PROFILE].size = 9 * sizeof(SANE_Word);
1237141cc406Sopenharmony_ci	s->val[OPT_CCT_PROFILE].wa = s->cct_table;
1238141cc406Sopenharmony_ci
1239141cc406Sopenharmony_ci/*	if (!s->hw->cmd->set_color_correction)
1240141cc406Sopenharmony_ci		s->opt[OPT_FILM_TYPE].cap |= SANE_CAP_INACTIVE;
1241141cc406Sopenharmony_ci*/
1242141cc406Sopenharmony_ci
1243141cc406Sopenharmony_ci	/* mirror */
1244141cc406Sopenharmony_ci	s->opt[OPT_MIRROR].name = "mirror";
1245141cc406Sopenharmony_ci	s->opt[OPT_MIRROR].title = SANE_I18N("Mirror image");
1246141cc406Sopenharmony_ci	s->opt[OPT_MIRROR].desc = SANE_I18N("Mirror the image.");
1247141cc406Sopenharmony_ci
1248141cc406Sopenharmony_ci	s->opt[OPT_MIRROR].type = SANE_TYPE_BOOL;
1249141cc406Sopenharmony_ci	s->val[OPT_MIRROR].w = SANE_FALSE;
1250141cc406Sopenharmony_ci
1251141cc406Sopenharmony_ci	if (!s->hw->cmd->mirror_image)
1252141cc406Sopenharmony_ci		s->opt[OPT_MIRROR].cap |= SANE_CAP_INACTIVE;
1253141cc406Sopenharmony_ci
1254141cc406Sopenharmony_ci	/* auto area segmentation */
1255141cc406Sopenharmony_ci	s->opt[OPT_AAS].name = "auto-area-segmentation";
1256141cc406Sopenharmony_ci	s->opt[OPT_AAS].title = SANE_I18N("Auto area segmentation");
1257141cc406Sopenharmony_ci	s->opt[OPT_AAS].desc =
1258141cc406Sopenharmony_ci		"Enables different dithering modes in image and text areas";
1259141cc406Sopenharmony_ci
1260141cc406Sopenharmony_ci	s->opt[OPT_AAS].type = SANE_TYPE_BOOL;
1261141cc406Sopenharmony_ci	s->val[OPT_AAS].w = SANE_TRUE;
1262141cc406Sopenharmony_ci
1263141cc406Sopenharmony_ci	if (!s->hw->cmd->control_auto_area_segmentation)
1264141cc406Sopenharmony_ci		s->opt[OPT_AAS].cap |= SANE_CAP_INACTIVE;
1265141cc406Sopenharmony_ci
1266141cc406Sopenharmony_ci	/* "Preview settings" group: */
1267141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW_GROUP].title = SANE_TITLE_PREVIEW;
1268141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW_GROUP].desc = "";
1269141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW_GROUP].type = SANE_TYPE_GROUP;
1270141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW_GROUP].cap = SANE_CAP_ADVANCED;
1271141cc406Sopenharmony_ci
1272141cc406Sopenharmony_ci	/* preview */
1273141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
1274141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
1275141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
1276141cc406Sopenharmony_ci
1277141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
1278141cc406Sopenharmony_ci	s->val[OPT_PREVIEW].w = SANE_FALSE;
1279141cc406Sopenharmony_ci
1280141cc406Sopenharmony_ci	/* "Geometry" group: */
1281141cc406Sopenharmony_ci	s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N("Geometry");
1282141cc406Sopenharmony_ci	s->opt[OPT_GEOMETRY_GROUP].desc = "";
1283141cc406Sopenharmony_ci	s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
1284141cc406Sopenharmony_ci	s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
1285141cc406Sopenharmony_ci
1286141cc406Sopenharmony_ci	/* top-left x */
1287141cc406Sopenharmony_ci	s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
1288141cc406Sopenharmony_ci	s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
1289141cc406Sopenharmony_ci	s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
1290141cc406Sopenharmony_ci
1291141cc406Sopenharmony_ci	s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
1292141cc406Sopenharmony_ci	s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
1293141cc406Sopenharmony_ci	s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
1294141cc406Sopenharmony_ci	s->opt[OPT_TL_X].constraint.range = s->hw->x_range;
1295141cc406Sopenharmony_ci	s->val[OPT_TL_X].w = 0;
1296141cc406Sopenharmony_ci
1297141cc406Sopenharmony_ci	/* top-left y */
1298141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
1299141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
1300141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
1301141cc406Sopenharmony_ci
1302141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
1303141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
1304141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1305141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].constraint.range = s->hw->y_range;
1306141cc406Sopenharmony_ci	s->val[OPT_TL_Y].w = 0;
1307141cc406Sopenharmony_ci
1308141cc406Sopenharmony_ci	/* bottom-right x */
1309141cc406Sopenharmony_ci	s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
1310141cc406Sopenharmony_ci	s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
1311141cc406Sopenharmony_ci	s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
1312141cc406Sopenharmony_ci
1313141cc406Sopenharmony_ci	s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
1314141cc406Sopenharmony_ci	s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
1315141cc406Sopenharmony_ci	s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1316141cc406Sopenharmony_ci	s->opt[OPT_BR_X].constraint.range = s->hw->x_range;
1317141cc406Sopenharmony_ci	s->val[OPT_BR_X].w = s->hw->x_range->max;
1318141cc406Sopenharmony_ci
1319141cc406Sopenharmony_ci	/* bottom-right y */
1320141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
1321141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
1322141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
1323141cc406Sopenharmony_ci
1324141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
1325141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
1326141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1327141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].constraint.range = s->hw->y_range;
1328141cc406Sopenharmony_ci	s->val[OPT_BR_Y].w = s->hw->y_range->max;
1329141cc406Sopenharmony_ci
1330141cc406Sopenharmony_ci	/* "Focus" group: */
1331141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_GROUP].title = SANE_I18N("Focus");
1332141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_GROUP].desc = "";
1333141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_GROUP].type = SANE_TYPE_GROUP;
1334141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_GROUP].cap = SANE_CAP_ADVANCED;
1335141cc406Sopenharmony_ci
1336141cc406Sopenharmony_ci	/* autofocus */
1337141cc406Sopenharmony_ci	s->opt[OPT_AUTOFOCUS].name = SANE_NAME_AUTOFOCUS;
1338141cc406Sopenharmony_ci	s->opt[OPT_AUTOFOCUS].title = SANE_TITLE_AUTOFOCUS;
1339141cc406Sopenharmony_ci	s->opt[OPT_AUTOFOCUS].desc = SANE_DESC_AUTOFOCUS;
1340141cc406Sopenharmony_ci	s->opt[OPT_AUTOFOCUS].type = SANE_TYPE_BOOL;
1341141cc406Sopenharmony_ci	s->val[OPT_AUTOFOCUS].w = SANE_FALSE;
1342141cc406Sopenharmony_ci	s->opt[OPT_AUTOFOCUS].cap |= SANE_CAP_ADVANCED;
1343141cc406Sopenharmony_ci
1344141cc406Sopenharmony_ci	/* focus position */
1345141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_POS].name = SANE_NAME_FOCUS;
1346141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_POS].title = SANE_TITLE_FOCUS;
1347141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_POS].desc = SANE_DESC_FOCUS;
1348141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_POS].type = SANE_TYPE_INT;
1349141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_POS].unit = SANE_UNIT_NONE;
1350141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_POS].constraint_type = SANE_CONSTRAINT_RANGE;
1351141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_POS].constraint.range = &focus_range;
1352141cc406Sopenharmony_ci	s->val[OPT_FOCUS_POS].w = FOCUS_ON_GLASS;
1353141cc406Sopenharmony_ci	s->opt[OPT_FOCUS_POS].cap |= SANE_CAP_ADVANCED;
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_ci	if (s->hw->focusSupport == SANE_TRUE) {
1356141cc406Sopenharmony_ci		s->opt[OPT_FOCUS_POS].cap &= ~SANE_CAP_INACTIVE;
1357141cc406Sopenharmony_ci		s->opt[OPT_AUTOFOCUS].cap &= ~SANE_CAP_INACTIVE;
1358141cc406Sopenharmony_ci	} else {
1359141cc406Sopenharmony_ci		s->opt[OPT_FOCUS_POS].cap |= SANE_CAP_INACTIVE;
1360141cc406Sopenharmony_ci		s->opt[OPT_AUTOFOCUS].cap |= SANE_CAP_INACTIVE;
1361141cc406Sopenharmony_ci	}
1362141cc406Sopenharmony_ci
1363141cc406Sopenharmony_ci	/* "Optional equipment" group: */
1364141cc406Sopenharmony_ci	s->opt[OPT_EQU_GROUP].title = SANE_I18N("Optional equipment");
1365141cc406Sopenharmony_ci	s->opt[OPT_EQU_GROUP].desc = "";
1366141cc406Sopenharmony_ci	s->opt[OPT_EQU_GROUP].type = SANE_TYPE_GROUP;
1367141cc406Sopenharmony_ci	s->opt[OPT_EQU_GROUP].cap = SANE_CAP_ADVANCED;
1368141cc406Sopenharmony_ci
1369141cc406Sopenharmony_ci	/* source */
1370141cc406Sopenharmony_ci	s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
1371141cc406Sopenharmony_ci	s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
1372141cc406Sopenharmony_ci	s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
1373141cc406Sopenharmony_ci
1374141cc406Sopenharmony_ci	s->opt[OPT_SOURCE].type = SANE_TYPE_STRING;
1375141cc406Sopenharmony_ci	s->opt[OPT_SOURCE].size = max_string_size(source_list);
1376141cc406Sopenharmony_ci
1377141cc406Sopenharmony_ci	s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1378141cc406Sopenharmony_ci	s->opt[OPT_SOURCE].constraint.string_list = source_list;
1379141cc406Sopenharmony_ci
1380141cc406Sopenharmony_ci	if (!s->hw->extension)
1381141cc406Sopenharmony_ci		s->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
1382141cc406Sopenharmony_ci
1383141cc406Sopenharmony_ci	s->val[OPT_SOURCE].w = 0;	/* always use Flatbed as default */
1384141cc406Sopenharmony_ci
1385141cc406Sopenharmony_ci
1386141cc406Sopenharmony_ci	/* film type */
1387141cc406Sopenharmony_ci	s->opt[OPT_FILM_TYPE].name = "film-type";
1388141cc406Sopenharmony_ci	s->opt[OPT_FILM_TYPE].title = SANE_I18N("Film type");
1389141cc406Sopenharmony_ci	s->opt[OPT_FILM_TYPE].desc = "";
1390141cc406Sopenharmony_ci	s->opt[OPT_FILM_TYPE].type = SANE_TYPE_STRING;
1391141cc406Sopenharmony_ci	s->opt[OPT_FILM_TYPE].size = max_string_size(film_list);
1392141cc406Sopenharmony_ci	s->opt[OPT_FILM_TYPE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1393141cc406Sopenharmony_ci	s->opt[OPT_FILM_TYPE].constraint.string_list = film_list;
1394141cc406Sopenharmony_ci	s->val[OPT_FILM_TYPE].w = 0;
1395141cc406Sopenharmony_ci
1396141cc406Sopenharmony_ci	if (!s->hw->cmd->set_bay)
1397141cc406Sopenharmony_ci		s->opt[OPT_FILM_TYPE].cap |= SANE_CAP_INACTIVE;
1398141cc406Sopenharmony_ci
1399141cc406Sopenharmony_ci	/* forward feed / eject */
1400141cc406Sopenharmony_ci	s->opt[OPT_EJECT].name = "eject";
1401141cc406Sopenharmony_ci	s->opt[OPT_EJECT].title = SANE_I18N("Eject");
1402141cc406Sopenharmony_ci	s->opt[OPT_EJECT].desc = SANE_I18N("Eject the sheet in the ADF");
1403141cc406Sopenharmony_ci	s->opt[OPT_EJECT].type = SANE_TYPE_BUTTON;
1404141cc406Sopenharmony_ci
1405141cc406Sopenharmony_ci	if ((!s->hw->ADF) && (!s->hw->cmd->set_bay)) {	/* Hack: Using set_bay to indicate. */
1406141cc406Sopenharmony_ci		s->opt[OPT_EJECT].cap |= SANE_CAP_INACTIVE;
1407141cc406Sopenharmony_ci	}
1408141cc406Sopenharmony_ci
1409141cc406Sopenharmony_ci
1410141cc406Sopenharmony_ci	/* auto forward feed / eject */
1411141cc406Sopenharmony_ci	s->opt[OPT_AUTO_EJECT].name = "auto-eject";
1412141cc406Sopenharmony_ci	s->opt[OPT_AUTO_EJECT].title = SANE_I18N("Auto eject");
1413141cc406Sopenharmony_ci	s->opt[OPT_AUTO_EJECT].desc =
1414141cc406Sopenharmony_ci		SANE_I18N("Eject document after scanning");
1415141cc406Sopenharmony_ci
1416141cc406Sopenharmony_ci	s->opt[OPT_AUTO_EJECT].type = SANE_TYPE_BOOL;
1417141cc406Sopenharmony_ci	s->val[OPT_AUTO_EJECT].w = SANE_FALSE;
1418141cc406Sopenharmony_ci
1419141cc406Sopenharmony_ci	if (!s->hw->ADF)
1420141cc406Sopenharmony_ci		s->opt[OPT_AUTO_EJECT].cap |= SANE_CAP_INACTIVE;
1421141cc406Sopenharmony_ci
1422141cc406Sopenharmony_ci
1423141cc406Sopenharmony_ci	s->opt[OPT_ADF_MODE].name = "adf-mode";
1424141cc406Sopenharmony_ci	s->opt[OPT_ADF_MODE].title = SANE_I18N("ADF Mode");
1425141cc406Sopenharmony_ci	s->opt[OPT_ADF_MODE].desc =
1426141cc406Sopenharmony_ci		SANE_I18N("Selects the ADF mode (simplex/duplex)");
1427141cc406Sopenharmony_ci	s->opt[OPT_ADF_MODE].type = SANE_TYPE_STRING;
1428141cc406Sopenharmony_ci	s->opt[OPT_ADF_MODE].size = max_string_size(adf_mode_list);
1429141cc406Sopenharmony_ci	s->opt[OPT_ADF_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1430141cc406Sopenharmony_ci	s->opt[OPT_ADF_MODE].constraint.string_list = adf_mode_list;
1431141cc406Sopenharmony_ci	s->val[OPT_ADF_MODE].w = 0;	/* simplex */
1432141cc406Sopenharmony_ci
1433141cc406Sopenharmony_ci	if ((!s->hw->ADF) || (s->hw->duplex == SANE_FALSE))
1434141cc406Sopenharmony_ci		s->opt[OPT_ADF_MODE].cap |= SANE_CAP_INACTIVE;
1435141cc406Sopenharmony_ci
1436141cc406Sopenharmony_ci	/* select bay */
1437141cc406Sopenharmony_ci	s->opt[OPT_BAY].name = "bay";
1438141cc406Sopenharmony_ci	s->opt[OPT_BAY].title = SANE_I18N("Bay");
1439141cc406Sopenharmony_ci	s->opt[OPT_BAY].desc = SANE_I18N("Select bay to scan");
1440141cc406Sopenharmony_ci	s->opt[OPT_BAY].type = SANE_TYPE_STRING;
1441141cc406Sopenharmony_ci	s->opt[OPT_BAY].size = max_string_size(bay_list);
1442141cc406Sopenharmony_ci	s->opt[OPT_BAY].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1443141cc406Sopenharmony_ci	s->opt[OPT_BAY].constraint.string_list = bay_list;
1444141cc406Sopenharmony_ci	s->val[OPT_BAY].w = 0;	/* Bay 1 */
1445141cc406Sopenharmony_ci
1446141cc406Sopenharmony_ci	if (!s->hw->cmd->set_bay)
1447141cc406Sopenharmony_ci		s->opt[OPT_BAY].cap |= SANE_CAP_INACTIVE;
1448141cc406Sopenharmony_ci
1449141cc406Sopenharmony_ci
1450141cc406Sopenharmony_ci	s->opt[OPT_WAIT_FOR_BUTTON].name = SANE_EPSON_WAIT_FOR_BUTTON_NAME;
1451141cc406Sopenharmony_ci	s->opt[OPT_WAIT_FOR_BUTTON].title = SANE_EPSON_WAIT_FOR_BUTTON_TITLE;
1452141cc406Sopenharmony_ci	s->opt[OPT_WAIT_FOR_BUTTON].desc = SANE_EPSON_WAIT_FOR_BUTTON_DESC;
1453141cc406Sopenharmony_ci
1454141cc406Sopenharmony_ci	s->opt[OPT_WAIT_FOR_BUTTON].type = SANE_TYPE_BOOL;
1455141cc406Sopenharmony_ci	s->opt[OPT_WAIT_FOR_BUTTON].unit = SANE_UNIT_NONE;
1456141cc406Sopenharmony_ci	s->opt[OPT_WAIT_FOR_BUTTON].constraint_type = SANE_CONSTRAINT_NONE;
1457141cc406Sopenharmony_ci	s->opt[OPT_WAIT_FOR_BUTTON].constraint.range = NULL;
1458141cc406Sopenharmony_ci	s->opt[OPT_WAIT_FOR_BUTTON].cap |= SANE_CAP_ADVANCED;
1459141cc406Sopenharmony_ci
1460141cc406Sopenharmony_ci	if (!s->hw->cmd->request_push_button_status)
1461141cc406Sopenharmony_ci		s->opt[OPT_WAIT_FOR_BUTTON].cap |= SANE_CAP_INACTIVE;
1462141cc406Sopenharmony_ci
1463141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1464141cc406Sopenharmony_ci}
1465141cc406Sopenharmony_ci
1466141cc406Sopenharmony_ciSANE_Status
1467141cc406Sopenharmony_cisane_open(SANE_String_Const name, SANE_Handle *handle)
1468141cc406Sopenharmony_ci{
1469141cc406Sopenharmony_ci	SANE_Status status;
1470141cc406Sopenharmony_ci	Epson_Scanner *s = NULL;
1471141cc406Sopenharmony_ci
1472141cc406Sopenharmony_ci	int l = strlen(name);
1473141cc406Sopenharmony_ci
1474141cc406Sopenharmony_ci	DBG(7, "%s: name = %s\n", __func__, name);
1475141cc406Sopenharmony_ci
1476141cc406Sopenharmony_ci	*handle = NULL;
1477141cc406Sopenharmony_ci
1478141cc406Sopenharmony_ci	/* probe if empty device name provided */
1479141cc406Sopenharmony_ci	if (l == 0) {
1480141cc406Sopenharmony_ci
1481141cc406Sopenharmony_ci		probe_devices(SANE_FALSE);
1482141cc406Sopenharmony_ci
1483141cc406Sopenharmony_ci		if (first_dev == NULL) {
1484141cc406Sopenharmony_ci			DBG(1, "no device detected\n");
1485141cc406Sopenharmony_ci			return SANE_STATUS_INVAL;
1486141cc406Sopenharmony_ci		}
1487141cc406Sopenharmony_ci
1488141cc406Sopenharmony_ci		s = device_detect(first_dev->sane.name, first_dev->connection,
1489141cc406Sopenharmony_ci					0, &status);
1490141cc406Sopenharmony_ci		if (s == NULL) {
1491141cc406Sopenharmony_ci			DBG(1, "cannot open a perfectly valid device (%s),"
1492141cc406Sopenharmony_ci				" please report to the authors\n", name);
1493141cc406Sopenharmony_ci			return SANE_STATUS_INVAL;
1494141cc406Sopenharmony_ci		}
1495141cc406Sopenharmony_ci
1496141cc406Sopenharmony_ci	} else {
1497141cc406Sopenharmony_ci
1498141cc406Sopenharmony_ci		if (strncmp(name, "net:", 4) == 0) {
1499141cc406Sopenharmony_ci			s = device_detect(name, SANE_EPSON_NET, 0, &status);
1500141cc406Sopenharmony_ci			if (s == NULL)
1501141cc406Sopenharmony_ci				return status;
1502141cc406Sopenharmony_ci		} else if (strncmp(name, "libusb:", 7) == 0) {
1503141cc406Sopenharmony_ci			s = device_detect(name, SANE_EPSON_USB, 1, &status);
1504141cc406Sopenharmony_ci			if (s == NULL)
1505141cc406Sopenharmony_ci				return status;
1506141cc406Sopenharmony_ci		} else if (strncmp(name, "pio:", 4) == 0) {
1507141cc406Sopenharmony_ci			s = device_detect(name, SANE_EPSON_PIO, 0, &status);
1508141cc406Sopenharmony_ci			if (s == NULL)
1509141cc406Sopenharmony_ci				return status;
1510141cc406Sopenharmony_ci		} else {
1511141cc406Sopenharmony_ci
1512141cc406Sopenharmony_ci			/* as a last resort, check for a match
1513141cc406Sopenharmony_ci			 * in the device list. This should handle SCSI
1514141cc406Sopenharmony_ci			 * devices and platforms without libusb.
1515141cc406Sopenharmony_ci			 */
1516141cc406Sopenharmony_ci
1517141cc406Sopenharmony_ci			if (first_dev == NULL)
1518141cc406Sopenharmony_ci				probe_devices(SANE_FALSE);
1519141cc406Sopenharmony_ci
1520141cc406Sopenharmony_ci			s = device_detect(name, SANE_EPSON_NODEV, 0, &status);
1521141cc406Sopenharmony_ci			if (s == NULL) {
1522141cc406Sopenharmony_ci				DBG(1, "invalid device name: %s\n", name);
1523141cc406Sopenharmony_ci				return SANE_STATUS_INVAL;
1524141cc406Sopenharmony_ci			}
1525141cc406Sopenharmony_ci		}
1526141cc406Sopenharmony_ci	}
1527141cc406Sopenharmony_ci
1528141cc406Sopenharmony_ci
1529141cc406Sopenharmony_ci	/* s is always valid here */
1530141cc406Sopenharmony_ci
1531141cc406Sopenharmony_ci	DBG(1, "handle obtained\n");
1532141cc406Sopenharmony_ci
1533141cc406Sopenharmony_ci	init_options(s);
1534141cc406Sopenharmony_ci
1535141cc406Sopenharmony_ci	status = open_scanner(s);
1536141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
1537141cc406Sopenharmony_ci		free(s);
1538141cc406Sopenharmony_ci		return status;
1539141cc406Sopenharmony_ci	}
1540141cc406Sopenharmony_ci
1541141cc406Sopenharmony_ci	status = esci_reset(s);
1542141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
1543141cc406Sopenharmony_ci		close_scanner(s);
1544141cc406Sopenharmony_ci		return status;
1545141cc406Sopenharmony_ci	}
1546141cc406Sopenharmony_ci
1547141cc406Sopenharmony_ci	*handle = (SANE_Handle)s;
1548141cc406Sopenharmony_ci
1549141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1550141cc406Sopenharmony_ci}
1551141cc406Sopenharmony_ci
1552141cc406Sopenharmony_civoid
1553141cc406Sopenharmony_cisane_close(SANE_Handle handle)
1554141cc406Sopenharmony_ci{
1555141cc406Sopenharmony_ci	Epson_Scanner *s;
1556141cc406Sopenharmony_ci
1557141cc406Sopenharmony_ci	DBG(1, "* %s\n", __func__);
1558141cc406Sopenharmony_ci
1559141cc406Sopenharmony_ci	/*
1560141cc406Sopenharmony_ci	 * XXX Test if there is still data pending from
1561141cc406Sopenharmony_ci	 * the scanner. If so, then do a cancel
1562141cc406Sopenharmony_ci	 */
1563141cc406Sopenharmony_ci
1564141cc406Sopenharmony_ci	s = (Epson_Scanner *) handle;
1565141cc406Sopenharmony_ci
1566141cc406Sopenharmony_ci	close_scanner(s);
1567141cc406Sopenharmony_ci}
1568141cc406Sopenharmony_ci
1569141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
1570141cc406Sopenharmony_cisane_get_option_descriptor(SANE_Handle handle, SANE_Int option)
1571141cc406Sopenharmony_ci{
1572141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
1573141cc406Sopenharmony_ci
1574141cc406Sopenharmony_ci	if (option < 0 || option >= NUM_OPTIONS)
1575141cc406Sopenharmony_ci		return NULL;
1576141cc406Sopenharmony_ci
1577141cc406Sopenharmony_ci	return s->opt + option;
1578141cc406Sopenharmony_ci}
1579141cc406Sopenharmony_ci
1580141cc406Sopenharmony_cistatic const SANE_String_Const *
1581141cc406Sopenharmony_cisearch_string_list(const SANE_String_Const *list, SANE_String value)
1582141cc406Sopenharmony_ci{
1583141cc406Sopenharmony_ci	while (*list != NULL && strcmp(value, *list) != 0)
1584141cc406Sopenharmony_ci		list++;
1585141cc406Sopenharmony_ci
1586141cc406Sopenharmony_ci	return ((*list == NULL) ? NULL : list);
1587141cc406Sopenharmony_ci}
1588141cc406Sopenharmony_ci
1589141cc406Sopenharmony_ci/*
1590141cc406Sopenharmony_ci    Activate, deactivate an option. Subroutines so we can add
1591141cc406Sopenharmony_ci    debugging info if we want. The change flag is set to TRUE
1592141cc406Sopenharmony_ci    if we changed an option. If we did not change an option,
1593141cc406Sopenharmony_ci    then the value of the changed flag is not modified.
1594141cc406Sopenharmony_ci*/
1595141cc406Sopenharmony_ci
1596141cc406Sopenharmony_cistatic void
1597141cc406Sopenharmony_ciactivateOption(Epson_Scanner *s, SANE_Int option, SANE_Bool *change)
1598141cc406Sopenharmony_ci{
1599141cc406Sopenharmony_ci	if (!SANE_OPTION_IS_ACTIVE(s->opt[option].cap)) {
1600141cc406Sopenharmony_ci		s->opt[option].cap &= ~SANE_CAP_INACTIVE;
1601141cc406Sopenharmony_ci		*change = SANE_TRUE;
1602141cc406Sopenharmony_ci	}
1603141cc406Sopenharmony_ci}
1604141cc406Sopenharmony_ci
1605141cc406Sopenharmony_cistatic void
1606141cc406Sopenharmony_cideactivateOption(Epson_Scanner *s, SANE_Int option, SANE_Bool *change)
1607141cc406Sopenharmony_ci{
1608141cc406Sopenharmony_ci	if (SANE_OPTION_IS_ACTIVE(s->opt[option].cap)) {
1609141cc406Sopenharmony_ci		s->opt[option].cap |= SANE_CAP_INACTIVE;
1610141cc406Sopenharmony_ci		*change = SANE_TRUE;
1611141cc406Sopenharmony_ci	}
1612141cc406Sopenharmony_ci}
1613141cc406Sopenharmony_ci
1614141cc406Sopenharmony_cistatic void
1615141cc406Sopenharmony_cisetOptionState(Epson_Scanner *s, SANE_Bool state, SANE_Int option,
1616141cc406Sopenharmony_ci	       SANE_Bool *change)
1617141cc406Sopenharmony_ci{
1618141cc406Sopenharmony_ci	if (state)
1619141cc406Sopenharmony_ci		activateOption(s, option, change);
1620141cc406Sopenharmony_ci	else
1621141cc406Sopenharmony_ci		deactivateOption(s, option, change);
1622141cc406Sopenharmony_ci}
1623141cc406Sopenharmony_ci
1624141cc406Sopenharmony_cistatic SANE_Status
1625141cc406Sopenharmony_cigetvalue(SANE_Handle handle, SANE_Int option, void *value)
1626141cc406Sopenharmony_ci{
1627141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
1628141cc406Sopenharmony_ci	SANE_Option_Descriptor *sopt = &(s->opt[option]);
1629141cc406Sopenharmony_ci	Option_Value *sval = &(s->val[option]);
1630141cc406Sopenharmony_ci
1631141cc406Sopenharmony_ci	DBG(17, "%s: option = %d\n", __func__, option);
1632141cc406Sopenharmony_ci
1633141cc406Sopenharmony_ci	switch (option) {
1634141cc406Sopenharmony_ci
1635141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
1636141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
1637141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
1638141cc406Sopenharmony_ci	case OPT_CCT_PROFILE:
1639141cc406Sopenharmony_ci		memcpy(value, sval->wa, sopt->size);
1640141cc406Sopenharmony_ci		break;
1641141cc406Sopenharmony_ci
1642141cc406Sopenharmony_ci	case OPT_NUM_OPTS:
1643141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1644141cc406Sopenharmony_ci	case OPT_TL_X:
1645141cc406Sopenharmony_ci	case OPT_TL_Y:
1646141cc406Sopenharmony_ci	case OPT_BR_X:
1647141cc406Sopenharmony_ci	case OPT_BR_Y:
1648141cc406Sopenharmony_ci	case OPT_MIRROR:
1649141cc406Sopenharmony_ci	case OPT_AAS:
1650141cc406Sopenharmony_ci	case OPT_PREVIEW:
1651141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
1652141cc406Sopenharmony_ci	case OPT_SHARPNESS:
1653141cc406Sopenharmony_ci	case OPT_AUTO_EJECT:
1654141cc406Sopenharmony_ci	case OPT_THRESHOLD:
1655141cc406Sopenharmony_ci	case OPT_BIT_DEPTH:
1656141cc406Sopenharmony_ci	case OPT_WAIT_FOR_BUTTON:
1657141cc406Sopenharmony_ci	case OPT_AUTOFOCUS:
1658141cc406Sopenharmony_ci	case OPT_FOCUS_POS:
1659141cc406Sopenharmony_ci		*((SANE_Word *) value) = sval->w;
1660141cc406Sopenharmony_ci		break;
1661141cc406Sopenharmony_ci
1662141cc406Sopenharmony_ci	case OPT_MODE:
1663141cc406Sopenharmony_ci	case OPT_CCT_MODE:
1664141cc406Sopenharmony_ci	case OPT_ADF_MODE:
1665141cc406Sopenharmony_ci	case OPT_HALFTONE:
1666141cc406Sopenharmony_ci	case OPT_DROPOUT:
1667141cc406Sopenharmony_ci	case OPT_SOURCE:
1668141cc406Sopenharmony_ci	case OPT_FILM_TYPE:
1669141cc406Sopenharmony_ci	case OPT_GAMMA_CORRECTION:
1670141cc406Sopenharmony_ci	case OPT_COLOR_CORRECTION:
1671141cc406Sopenharmony_ci	case OPT_BAY:
1672141cc406Sopenharmony_ci		strcpy((char *) value, sopt->constraint.string_list[sval->w]);
1673141cc406Sopenharmony_ci		break;
1674141cc406Sopenharmony_ci
1675141cc406Sopenharmony_ci	default:
1676141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1677141cc406Sopenharmony_ci	}
1678141cc406Sopenharmony_ci
1679141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1680141cc406Sopenharmony_ci}
1681141cc406Sopenharmony_ci
1682141cc406Sopenharmony_ci/*
1683141cc406Sopenharmony_ci * This routine handles common options between OPT_MODE and
1684141cc406Sopenharmony_ci * OPT_HALFTONE.  These options are TET (a HALFTONE mode), AAS
1685141cc406Sopenharmony_ci * - auto area segmentation, and threshold.  Apparently AAS
1686141cc406Sopenharmony_ci * is some method to differentiate between text and photos.
1687141cc406Sopenharmony_ci * Or something like that.
1688141cc406Sopenharmony_ci *
1689141cc406Sopenharmony_ci * AAS is available when the scan color depth is 1 and the
1690141cc406Sopenharmony_ci * halftone method is not TET.
1691141cc406Sopenharmony_ci *
1692141cc406Sopenharmony_ci * Threshold is available when halftone is NONE, and depth is 1.
1693141cc406Sopenharmony_ci */
1694141cc406Sopenharmony_cistatic void
1695141cc406Sopenharmony_cihandle_depth_halftone(Epson_Scanner *s, SANE_Bool *reload)
1696141cc406Sopenharmony_ci{
1697141cc406Sopenharmony_ci	int hti = s->val[OPT_HALFTONE].w;
1698141cc406Sopenharmony_ci	int mdi = s->val[OPT_MODE].w;
1699141cc406Sopenharmony_ci	SANE_Bool aas = SANE_FALSE;
1700141cc406Sopenharmony_ci	SANE_Bool thresh = SANE_FALSE;
1701141cc406Sopenharmony_ci
1702141cc406Sopenharmony_ci	/* this defaults to false */
1703141cc406Sopenharmony_ci	setOptionState(s, thresh, OPT_THRESHOLD, reload);
1704141cc406Sopenharmony_ci
1705141cc406Sopenharmony_ci	if (!s->hw->cmd->control_auto_area_segmentation)
1706141cc406Sopenharmony_ci		return;
1707141cc406Sopenharmony_ci
1708141cc406Sopenharmony_ci	if (mode_params[mdi].depth == 1) {
1709141cc406Sopenharmony_ci
1710141cc406Sopenharmony_ci		if (halftone_params[hti] != HALFTONE_TET)
1711141cc406Sopenharmony_ci			aas = SANE_TRUE;
1712141cc406Sopenharmony_ci
1713141cc406Sopenharmony_ci		if (halftone_params[hti] == HALFTONE_NONE)
1714141cc406Sopenharmony_ci			thresh = SANE_TRUE;
1715141cc406Sopenharmony_ci	}
1716141cc406Sopenharmony_ci	setOptionState(s, aas, OPT_AAS, reload);
1717141cc406Sopenharmony_ci	setOptionState(s, thresh, OPT_THRESHOLD, reload);
1718141cc406Sopenharmony_ci}
1719141cc406Sopenharmony_ci
1720141cc406Sopenharmony_ci/*
1721141cc406Sopenharmony_ci * Handles setting the source (flatbed, transparency adapter (TPU),
1722141cc406Sopenharmony_ci * or auto document feeder (ADF)).
1723141cc406Sopenharmony_ci *
1724141cc406Sopenharmony_ci * For newer scanners it also sets the focus according to the
1725141cc406Sopenharmony_ci * glass / TPU settings.
1726141cc406Sopenharmony_ci */
1727141cc406Sopenharmony_ci
1728141cc406Sopenharmony_cistatic void
1729141cc406Sopenharmony_cichange_source(Epson_Scanner *s, SANE_Int optindex, char *value)
1730141cc406Sopenharmony_ci{
1731141cc406Sopenharmony_ci	int force_max = SANE_FALSE;
1732141cc406Sopenharmony_ci	SANE_Bool dummy;
1733141cc406Sopenharmony_ci
1734141cc406Sopenharmony_ci	DBG(1, "%s: optindex = %d, source = '%s'\n", __func__, optindex,
1735141cc406Sopenharmony_ci	    value);
1736141cc406Sopenharmony_ci
1737141cc406Sopenharmony_ci	/* reset the scanner when we are changing the source setting -
1738141cc406Sopenharmony_ci	   this is necessary for the Perfection 1650 */
1739141cc406Sopenharmony_ci	if (s->hw->need_reset_on_source_change)
1740141cc406Sopenharmony_ci		esci_reset(s);
1741141cc406Sopenharmony_ci
1742141cc406Sopenharmony_ci	if (s->val[OPT_SOURCE].w == optindex)
1743141cc406Sopenharmony_ci		return;
1744141cc406Sopenharmony_ci
1745141cc406Sopenharmony_ci	s->val[OPT_SOURCE].w = optindex;
1746141cc406Sopenharmony_ci
1747141cc406Sopenharmony_ci	if (s->val[OPT_TL_X].w == s->hw->x_range->min
1748141cc406Sopenharmony_ci	    && s->val[OPT_TL_Y].w == s->hw->y_range->min
1749141cc406Sopenharmony_ci	    && s->val[OPT_BR_X].w == s->hw->x_range->max
1750141cc406Sopenharmony_ci	    && s->val[OPT_BR_Y].w == s->hw->y_range->max) {
1751141cc406Sopenharmony_ci		force_max = SANE_TRUE;
1752141cc406Sopenharmony_ci	}
1753141cc406Sopenharmony_ci
1754141cc406Sopenharmony_ci	if (strcmp(ADF_STR, value) == 0) {
1755141cc406Sopenharmony_ci		s->hw->x_range = &s->hw->adf_x_range;
1756141cc406Sopenharmony_ci		s->hw->y_range = &s->hw->adf_y_range;
1757141cc406Sopenharmony_ci		s->hw->use_extension = SANE_TRUE;
1758141cc406Sopenharmony_ci		/* disable film type option */
1759141cc406Sopenharmony_ci		deactivateOption(s, OPT_FILM_TYPE, &dummy);
1760141cc406Sopenharmony_ci		s->val[OPT_FOCUS_POS].w = FOCUS_ON_GLASS;
1761141cc406Sopenharmony_ci		if (s->hw->duplex) {
1762141cc406Sopenharmony_ci			activateOption(s, OPT_ADF_MODE, &dummy);
1763141cc406Sopenharmony_ci		} else {
1764141cc406Sopenharmony_ci			deactivateOption(s, OPT_ADF_MODE, &dummy);
1765141cc406Sopenharmony_ci			s->val[OPT_ADF_MODE].w = 0;
1766141cc406Sopenharmony_ci		}
1767141cc406Sopenharmony_ci
1768141cc406Sopenharmony_ci		DBG(1, "adf activated (ext: %d, duplex: %d)\n",
1769141cc406Sopenharmony_ci			s->hw->use_extension,
1770141cc406Sopenharmony_ci			s->hw->duplex);
1771141cc406Sopenharmony_ci
1772141cc406Sopenharmony_ci	} else if (strcmp(TPU_STR, value) == 0 || strcmp(TPU_STR2, value) == 0) {
1773141cc406Sopenharmony_ci	        if (strcmp(TPU_STR, value) == 0) {
1774141cc406Sopenharmony_ci	  	        s->hw->x_range = &s->hw->tpu_x_range;
1775141cc406Sopenharmony_ci		        s->hw->y_range = &s->hw->tpu_y_range;
1776141cc406Sopenharmony_ci			s->hw->TPU2 = SANE_FALSE;
1777141cc406Sopenharmony_ci                }
1778141cc406Sopenharmony_ci	        if (strcmp(TPU_STR2, value) == 0) {
1779141cc406Sopenharmony_ci	  	        s->hw->x_range = &s->hw->tpu2_x_range;
1780141cc406Sopenharmony_ci		        s->hw->y_range = &s->hw->tpu2_y_range;
1781141cc406Sopenharmony_ci			s->hw->TPU2 = SANE_TRUE;
1782141cc406Sopenharmony_ci                }
1783141cc406Sopenharmony_ci		s->hw->use_extension = SANE_TRUE;
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci		/* enable film type option only if the scanner supports it */
1786141cc406Sopenharmony_ci		if (s->hw->cmd->set_film_type != 0)
1787141cc406Sopenharmony_ci			activateOption(s, OPT_FILM_TYPE, &dummy);
1788141cc406Sopenharmony_ci		else
1789141cc406Sopenharmony_ci			deactivateOption(s, OPT_FILM_TYPE, &dummy);
1790141cc406Sopenharmony_ci
1791141cc406Sopenharmony_ci		/* enable focus position if the scanner supports it */
1792141cc406Sopenharmony_ci		if (s->hw->focusSupport)
1793141cc406Sopenharmony_ci			s->val[OPT_FOCUS_POS].w = FOCUS_ABOVE_25MM;
1794141cc406Sopenharmony_ci
1795141cc406Sopenharmony_ci		deactivateOption(s, OPT_ADF_MODE, &dummy);
1796141cc406Sopenharmony_ci		deactivateOption(s, OPT_EJECT, &dummy);
1797141cc406Sopenharmony_ci		deactivateOption(s, OPT_AUTO_EJECT, &dummy);
1798141cc406Sopenharmony_ci	} else {
1799141cc406Sopenharmony_ci		/* neither ADF nor TPU active */
1800141cc406Sopenharmony_ci		s->hw->x_range = &s->hw->fbf_x_range;
1801141cc406Sopenharmony_ci		s->hw->y_range = &s->hw->fbf_y_range;
1802141cc406Sopenharmony_ci		s->hw->use_extension = SANE_FALSE;
1803141cc406Sopenharmony_ci
1804141cc406Sopenharmony_ci		/* disable film type option */
1805141cc406Sopenharmony_ci		deactivateOption(s, OPT_FILM_TYPE, &dummy);
1806141cc406Sopenharmony_ci		s->val[OPT_FOCUS_POS].w = FOCUS_ON_GLASS;
1807141cc406Sopenharmony_ci		deactivateOption(s, OPT_ADF_MODE, &dummy);
1808141cc406Sopenharmony_ci	}
1809141cc406Sopenharmony_ci
1810141cc406Sopenharmony_ci	/* special handling for FilmScan 200 */
1811141cc406Sopenharmony_ci	if (s->hw->cmd->level[0] == 'F')
1812141cc406Sopenharmony_ci		activateOption(s, OPT_FILM_TYPE, &dummy);
1813141cc406Sopenharmony_ci
1814141cc406Sopenharmony_ci	s->opt[OPT_BR_X].constraint.range = s->hw->x_range;
1815141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].constraint.range = s->hw->y_range;
1816141cc406Sopenharmony_ci
1817141cc406Sopenharmony_ci	if (s->val[OPT_TL_X].w < s->hw->x_range->min || force_max)
1818141cc406Sopenharmony_ci		s->val[OPT_TL_X].w = s->hw->x_range->min;
1819141cc406Sopenharmony_ci
1820141cc406Sopenharmony_ci	if (s->val[OPT_TL_Y].w < s->hw->y_range->min || force_max)
1821141cc406Sopenharmony_ci		s->val[OPT_TL_Y].w = s->hw->y_range->min;
1822141cc406Sopenharmony_ci
1823141cc406Sopenharmony_ci	if (s->val[OPT_BR_X].w > s->hw->x_range->max || force_max)
1824141cc406Sopenharmony_ci		s->val[OPT_BR_X].w = s->hw->x_range->max;
1825141cc406Sopenharmony_ci
1826141cc406Sopenharmony_ci	if (s->val[OPT_BR_Y].w > s->hw->y_range->max || force_max)
1827141cc406Sopenharmony_ci		s->val[OPT_BR_Y].w = s->hw->y_range->max;
1828141cc406Sopenharmony_ci
1829141cc406Sopenharmony_ci	setOptionState(s, s->hw->ADF
1830141cc406Sopenharmony_ci		       && s->hw->use_extension, OPT_AUTO_EJECT, &dummy);
1831141cc406Sopenharmony_ci	setOptionState(s, s->hw->ADF
1832141cc406Sopenharmony_ci		       && s->hw->use_extension, OPT_EJECT, &dummy);
1833141cc406Sopenharmony_ci}
1834141cc406Sopenharmony_ci
1835141cc406Sopenharmony_cistatic SANE_Status
1836141cc406Sopenharmony_cisetvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info)
1837141cc406Sopenharmony_ci{
1838141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
1839141cc406Sopenharmony_ci	SANE_Option_Descriptor *sopt = &(s->opt[option]);
1840141cc406Sopenharmony_ci	Option_Value *sval = &(s->val[option]);
1841141cc406Sopenharmony_ci
1842141cc406Sopenharmony_ci	SANE_Status status;
1843141cc406Sopenharmony_ci	const SANE_String_Const *optval = NULL;
1844141cc406Sopenharmony_ci	int optindex = 0;
1845141cc406Sopenharmony_ci	SANE_Bool reload = SANE_FALSE;
1846141cc406Sopenharmony_ci
1847141cc406Sopenharmony_ci	DBG(17, "%s: option = %d, value = %p\n", __func__, option, value);
1848141cc406Sopenharmony_ci
1849141cc406Sopenharmony_ci	status = sanei_constrain_value(sopt, value, info);
1850141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
1851141cc406Sopenharmony_ci		return status;
1852141cc406Sopenharmony_ci
1853141cc406Sopenharmony_ci	if (info && value && (*info & SANE_INFO_INEXACT)
1854141cc406Sopenharmony_ci	    && sopt->type == SANE_TYPE_INT)
1855141cc406Sopenharmony_ci		DBG(17, "%s: constrained val = %d\n", __func__,
1856141cc406Sopenharmony_ci		    *(SANE_Word *) value);
1857141cc406Sopenharmony_ci
1858141cc406Sopenharmony_ci	if (sopt->constraint_type == SANE_CONSTRAINT_STRING_LIST) {
1859141cc406Sopenharmony_ci		optval = search_string_list(sopt->constraint.string_list,
1860141cc406Sopenharmony_ci					    (char *) value);
1861141cc406Sopenharmony_ci		if (optval == NULL)
1862141cc406Sopenharmony_ci			return SANE_STATUS_INVAL;
1863141cc406Sopenharmony_ci		optindex = optval - sopt->constraint.string_list;
1864141cc406Sopenharmony_ci	}
1865141cc406Sopenharmony_ci
1866141cc406Sopenharmony_ci	switch (option) {
1867141cc406Sopenharmony_ci
1868141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_R:
1869141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_G:
1870141cc406Sopenharmony_ci	case OPT_GAMMA_VECTOR_B:
1871141cc406Sopenharmony_ci	case OPT_CCT_PROFILE:
1872141cc406Sopenharmony_ci		memcpy(sval->wa, value, sopt->size);	/* Word arrays */
1873141cc406Sopenharmony_ci		break;
1874141cc406Sopenharmony_ci
1875141cc406Sopenharmony_ci	case OPT_CCT_MODE:
1876141cc406Sopenharmony_ci	case OPT_ADF_MODE:
1877141cc406Sopenharmony_ci	case OPT_DROPOUT:
1878141cc406Sopenharmony_ci	case OPT_FILM_TYPE:
1879141cc406Sopenharmony_ci	case OPT_BAY:
1880141cc406Sopenharmony_ci		sval->w = optindex;	/* Simple lists */
1881141cc406Sopenharmony_ci		break;
1882141cc406Sopenharmony_ci
1883141cc406Sopenharmony_ci	case OPT_EJECT:
1884141cc406Sopenharmony_ci		/* XXX required?  control_extension(s, 1); */
1885141cc406Sopenharmony_ci		esci_eject(s);
1886141cc406Sopenharmony_ci		break;
1887141cc406Sopenharmony_ci
1888141cc406Sopenharmony_ci	case OPT_RESOLUTION:
1889141cc406Sopenharmony_ci		sval->w = *((SANE_Word *) value);
1890141cc406Sopenharmony_ci		DBG(17, "setting resolution to %d\n", sval->w);
1891141cc406Sopenharmony_ci		reload = SANE_TRUE;
1892141cc406Sopenharmony_ci		break;
1893141cc406Sopenharmony_ci
1894141cc406Sopenharmony_ci	case OPT_BR_X:
1895141cc406Sopenharmony_ci	case OPT_BR_Y:
1896141cc406Sopenharmony_ci		if (SANE_UNFIX(*((SANE_Word *) value)) == 0) {
1897141cc406Sopenharmony_ci			DBG(17, "invalid br-x or br-y\n");
1898141cc406Sopenharmony_ci			return SANE_STATUS_INVAL;
1899141cc406Sopenharmony_ci		}
1900141cc406Sopenharmony_ci		// fall through
1901141cc406Sopenharmony_ci	case OPT_TL_X:
1902141cc406Sopenharmony_ci	case OPT_TL_Y:
1903141cc406Sopenharmony_ci		sval->w = *((SANE_Word *) value);
1904141cc406Sopenharmony_ci		DBG(17, "setting size to %f\n", SANE_UNFIX(sval->w));
1905141cc406Sopenharmony_ci		if (NULL != info)
1906141cc406Sopenharmony_ci			*info |= SANE_INFO_RELOAD_PARAMS;
1907141cc406Sopenharmony_ci		break;
1908141cc406Sopenharmony_ci
1909141cc406Sopenharmony_ci	case OPT_SOURCE:
1910141cc406Sopenharmony_ci		change_source(s, optindex, (char *) value);
1911141cc406Sopenharmony_ci		reload = SANE_TRUE;
1912141cc406Sopenharmony_ci		break;
1913141cc406Sopenharmony_ci
1914141cc406Sopenharmony_ci	case OPT_MODE:
1915141cc406Sopenharmony_ci	{
1916141cc406Sopenharmony_ci		SANE_Bool isColor = mode_params[optindex].color;
1917141cc406Sopenharmony_ci
1918141cc406Sopenharmony_ci		sval->w = optindex;
1919141cc406Sopenharmony_ci
1920141cc406Sopenharmony_ci		DBG(17, "%s: setting mode to %d\n", __func__, optindex);
1921141cc406Sopenharmony_ci
1922141cc406Sopenharmony_ci		/* halftoning available only on bw scans */
1923141cc406Sopenharmony_ci		if (s->hw->cmd->set_halftoning != 0)
1924141cc406Sopenharmony_ci			setOptionState(s, mode_params[optindex].depth == 1,
1925141cc406Sopenharmony_ci				       OPT_HALFTONE, &reload);
1926141cc406Sopenharmony_ci
1927141cc406Sopenharmony_ci		/* disable dropout on non-color scans */
1928141cc406Sopenharmony_ci		setOptionState(s, !isColor, OPT_DROPOUT, &reload);
1929141cc406Sopenharmony_ci
1930141cc406Sopenharmony_ci		if (s->hw->cmd->set_color_correction)
1931141cc406Sopenharmony_ci			setOptionState(s, isColor,
1932141cc406Sopenharmony_ci				       OPT_COLOR_CORRECTION, &reload);
1933141cc406Sopenharmony_ci
1934141cc406Sopenharmony_ci		/* if binary, then disable the bit depth selection */
1935141cc406Sopenharmony_ci		if (optindex == 0) {
1936141cc406Sopenharmony_ci			DBG(17, "%s: disabling bit depth selection\n", __func__);
1937141cc406Sopenharmony_ci			s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
1938141cc406Sopenharmony_ci		} else {
1939141cc406Sopenharmony_ci			if (s->hw->depth_list[0] == 1) {
1940141cc406Sopenharmony_ci				DBG(17, "%s: only one depth is available\n", __func__);
1941141cc406Sopenharmony_ci				s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE;
1942141cc406Sopenharmony_ci			} else {
1943141cc406Sopenharmony_ci
1944141cc406Sopenharmony_ci				DBG(17, "%s: enabling bit depth selection\n", __func__);
1945141cc406Sopenharmony_ci
1946141cc406Sopenharmony_ci				s->opt[OPT_BIT_DEPTH].cap &= ~SANE_CAP_INACTIVE;
1947141cc406Sopenharmony_ci				s->val[OPT_BIT_DEPTH].w = mode_params[optindex].depth;
1948141cc406Sopenharmony_ci			}
1949141cc406Sopenharmony_ci		}
1950141cc406Sopenharmony_ci
1951141cc406Sopenharmony_ci		handle_depth_halftone(s, &reload);
1952141cc406Sopenharmony_ci		reload = SANE_TRUE;
1953141cc406Sopenharmony_ci
1954141cc406Sopenharmony_ci		break;
1955141cc406Sopenharmony_ci	}
1956141cc406Sopenharmony_ci
1957141cc406Sopenharmony_ci	case OPT_BIT_DEPTH:
1958141cc406Sopenharmony_ci		sval->w = *((SANE_Word *) value);
1959141cc406Sopenharmony_ci		mode_params[s->val[OPT_MODE].w].depth = sval->w;
1960141cc406Sopenharmony_ci		reload = SANE_TRUE;
1961141cc406Sopenharmony_ci		break;
1962141cc406Sopenharmony_ci
1963141cc406Sopenharmony_ci	case OPT_HALFTONE:
1964141cc406Sopenharmony_ci		sval->w = optindex;
1965141cc406Sopenharmony_ci		handle_depth_halftone(s, &reload);
1966141cc406Sopenharmony_ci		break;
1967141cc406Sopenharmony_ci
1968141cc406Sopenharmony_ci	case OPT_COLOR_CORRECTION:
1969141cc406Sopenharmony_ci	{
1970141cc406Sopenharmony_ci		sval->w = optindex;
1971141cc406Sopenharmony_ci		break;
1972141cc406Sopenharmony_ci	}
1973141cc406Sopenharmony_ci
1974141cc406Sopenharmony_ci	case OPT_GAMMA_CORRECTION:
1975141cc406Sopenharmony_ci	{
1976141cc406Sopenharmony_ci		SANE_Bool f = gamma_userdefined[optindex];
1977141cc406Sopenharmony_ci
1978141cc406Sopenharmony_ci		sval->w = optindex;
1979141cc406Sopenharmony_ci
1980141cc406Sopenharmony_ci		setOptionState(s, f, OPT_GAMMA_VECTOR_R, &reload);
1981141cc406Sopenharmony_ci		setOptionState(s, f, OPT_GAMMA_VECTOR_G, &reload);
1982141cc406Sopenharmony_ci		setOptionState(s, f, OPT_GAMMA_VECTOR_B, &reload);
1983141cc406Sopenharmony_ci		setOptionState(s, !f, OPT_BRIGHTNESS, &reload);	/* Note... */
1984141cc406Sopenharmony_ci
1985141cc406Sopenharmony_ci		break;
1986141cc406Sopenharmony_ci	}
1987141cc406Sopenharmony_ci
1988141cc406Sopenharmony_ci	case OPT_AUTOFOCUS:
1989141cc406Sopenharmony_ci		sval->w = *((SANE_Word *) value);
1990141cc406Sopenharmony_ci		setOptionState(s, !sval->w, OPT_FOCUS_POS, &reload);
1991141cc406Sopenharmony_ci		break;
1992141cc406Sopenharmony_ci
1993141cc406Sopenharmony_ci	case OPT_MIRROR:
1994141cc406Sopenharmony_ci	case OPT_AAS:
1995141cc406Sopenharmony_ci	case OPT_PREVIEW:	/* needed? */
1996141cc406Sopenharmony_ci	case OPT_BRIGHTNESS:
1997141cc406Sopenharmony_ci	case OPT_SHARPNESS:
1998141cc406Sopenharmony_ci	case OPT_AUTO_EJECT:
1999141cc406Sopenharmony_ci	case OPT_THRESHOLD:
2000141cc406Sopenharmony_ci	case OPT_WAIT_FOR_BUTTON:
2001141cc406Sopenharmony_ci	case OPT_FOCUS_POS:
2002141cc406Sopenharmony_ci		sval->w = *((SANE_Word *) value);
2003141cc406Sopenharmony_ci		break;
2004141cc406Sopenharmony_ci
2005141cc406Sopenharmony_ci	default:
2006141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
2007141cc406Sopenharmony_ci	}
2008141cc406Sopenharmony_ci
2009141cc406Sopenharmony_ci	if (reload && info != NULL)
2010141cc406Sopenharmony_ci		*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2011141cc406Sopenharmony_ci
2012141cc406Sopenharmony_ci	DBG(17, "%s: end\n", __func__);
2013141cc406Sopenharmony_ci
2014141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
2015141cc406Sopenharmony_ci}
2016141cc406Sopenharmony_ci
2017141cc406Sopenharmony_ciSANE_Status
2018141cc406Sopenharmony_cisane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action,
2019141cc406Sopenharmony_ci		    void *value, SANE_Int *info)
2020141cc406Sopenharmony_ci{
2021141cc406Sopenharmony_ci	DBG(17, "%s: action = %x, option = %d\n", __func__, action, option);
2022141cc406Sopenharmony_ci
2023141cc406Sopenharmony_ci	if (option < 0 || option >= NUM_OPTIONS)
2024141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
2025141cc406Sopenharmony_ci
2026141cc406Sopenharmony_ci	if (info != NULL)
2027141cc406Sopenharmony_ci		*info = 0;
2028141cc406Sopenharmony_ci
2029141cc406Sopenharmony_ci	switch (action) {
2030141cc406Sopenharmony_ci	case SANE_ACTION_GET_VALUE:
2031141cc406Sopenharmony_ci		return getvalue(handle, option, value);
2032141cc406Sopenharmony_ci
2033141cc406Sopenharmony_ci	case SANE_ACTION_SET_VALUE:
2034141cc406Sopenharmony_ci		return setvalue(handle, option, value, info);
2035141cc406Sopenharmony_ci
2036141cc406Sopenharmony_ci	default:
2037141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
2038141cc406Sopenharmony_ci	}
2039141cc406Sopenharmony_ci
2040141cc406Sopenharmony_ci	return SANE_STATUS_INVAL;
2041141cc406Sopenharmony_ci}
2042141cc406Sopenharmony_ci
2043141cc406Sopenharmony_ciSANE_Status
2044141cc406Sopenharmony_cisane_get_parameters(SANE_Handle handle, SANE_Parameters *params)
2045141cc406Sopenharmony_ci{
2046141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
2047141cc406Sopenharmony_ci
2048141cc406Sopenharmony_ci	DBG(5, "%s\n", __func__);
2049141cc406Sopenharmony_ci
2050141cc406Sopenharmony_ci	if (params == NULL)
2051141cc406Sopenharmony_ci		DBG(1, "%s: params is NULL\n", __func__);
2052141cc406Sopenharmony_ci
2053141cc406Sopenharmony_ci	/*
2054141cc406Sopenharmony_ci	 * If sane_start was already called, then just retrieve the parameters
2055141cc406Sopenharmony_ci	 * from the scanner data structure
2056141cc406Sopenharmony_ci	 */
2057141cc406Sopenharmony_ci
2058141cc406Sopenharmony_ci	if (!s->eof && s->ptr != NULL) {
2059141cc406Sopenharmony_ci		DBG(5, "scan in progress, returning saved params structure\n");
2060141cc406Sopenharmony_ci	} else {
2061141cc406Sopenharmony_ci		/* otherwise initialize the params structure and gather the data */
2062141cc406Sopenharmony_ci		e2_init_parameters(s);
2063141cc406Sopenharmony_ci	}
2064141cc406Sopenharmony_ci
2065141cc406Sopenharmony_ci	if (params != NULL)
2066141cc406Sopenharmony_ci		*params = s->params;
2067141cc406Sopenharmony_ci
2068141cc406Sopenharmony_ci	print_params(s->params);
2069141cc406Sopenharmony_ci
2070141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
2071141cc406Sopenharmony_ci}
2072141cc406Sopenharmony_ci
2073141cc406Sopenharmony_cistatic void e2_load_cct_profile(struct Epson_Scanner *s, unsigned int index)
2074141cc406Sopenharmony_ci{
2075141cc406Sopenharmony_ci        s->cct_table[0] = SANE_FIX(s->hw->cct_profile->cct[index][0]);
2076141cc406Sopenharmony_ci        s->cct_table[1] = SANE_FIX(s->hw->cct_profile->cct[index][1]);
2077141cc406Sopenharmony_ci        s->cct_table[2] = SANE_FIX(s->hw->cct_profile->cct[index][2]);
2078141cc406Sopenharmony_ci        s->cct_table[3] = SANE_FIX(s->hw->cct_profile->cct[index][3]);
2079141cc406Sopenharmony_ci        s->cct_table[4] = SANE_FIX(s->hw->cct_profile->cct[index][4]);
2080141cc406Sopenharmony_ci        s->cct_table[5] = SANE_FIX(s->hw->cct_profile->cct[index][5]);
2081141cc406Sopenharmony_ci        s->cct_table[6] = SANE_FIX(s->hw->cct_profile->cct[index][6]);
2082141cc406Sopenharmony_ci        s->cct_table[7] = SANE_FIX(s->hw->cct_profile->cct[index][7]);
2083141cc406Sopenharmony_ci        s->cct_table[8] = SANE_FIX(s->hw->cct_profile->cct[index][8]);
2084141cc406Sopenharmony_ci}
2085141cc406Sopenharmony_ci
2086141cc406Sopenharmony_ci/*
2087141cc406Sopenharmony_ci * This function is part of the SANE API and gets called from the front end to
2088141cc406Sopenharmony_ci * start the scan process.
2089141cc406Sopenharmony_ci */
2090141cc406Sopenharmony_ci
2091141cc406Sopenharmony_ciSANE_Status
2092141cc406Sopenharmony_cisane_start(SANE_Handle handle)
2093141cc406Sopenharmony_ci{
2094141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
2095141cc406Sopenharmony_ci	Epson_Device *dev = s->hw;
2096141cc406Sopenharmony_ci	SANE_Status status;
2097141cc406Sopenharmony_ci
2098141cc406Sopenharmony_ci	DBG(5, "* %s\n", __func__);
2099141cc406Sopenharmony_ci
2100141cc406Sopenharmony_ci	s->eof = SANE_FALSE;
2101141cc406Sopenharmony_ci	s->canceling = SANE_FALSE;
2102141cc406Sopenharmony_ci
2103141cc406Sopenharmony_ci	/* check if we just have finished working with the ADF */
2104141cc406Sopenharmony_ci	status = e2_check_adf(s);
2105141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
2106141cc406Sopenharmony_ci		return status;
2107141cc406Sopenharmony_ci
2108141cc406Sopenharmony_ci	/* calc scanning parameters */
2109141cc406Sopenharmony_ci	status = e2_init_parameters(s);
2110141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
2111141cc406Sopenharmony_ci		return status;
2112141cc406Sopenharmony_ci
2113141cc406Sopenharmony_ci	print_params(s->params);
2114141cc406Sopenharmony_ci
2115141cc406Sopenharmony_ci	/* enable infrared */
2116141cc406Sopenharmony_ci	if (s->val[OPT_MODE].w == MODE_INFRARED)
2117141cc406Sopenharmony_ci		esci_enable_infrared(handle);
2118141cc406Sopenharmony_ci
2119141cc406Sopenharmony_ci	/* ESC , bay */
2120141cc406Sopenharmony_ci	if (SANE_OPTION_IS_ACTIVE(s->opt[OPT_BAY].cap)) {
2121141cc406Sopenharmony_ci		status = esci_set_bay(s, s->val[OPT_BAY].w);
2122141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD)
2123141cc406Sopenharmony_ci			return status;
2124141cc406Sopenharmony_ci	}
2125141cc406Sopenharmony_ci
2126141cc406Sopenharmony_ci	/* set scanning parameters */
2127141cc406Sopenharmony_ci	if (dev->extended_commands)
2128141cc406Sopenharmony_ci		status = e2_set_extended_scanning_parameters(s);
2129141cc406Sopenharmony_ci	else
2130141cc406Sopenharmony_ci		status = e2_set_scanning_parameters(s);
2131141cc406Sopenharmony_ci
2132141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
2133141cc406Sopenharmony_ci		return status;
2134141cc406Sopenharmony_ci
2135141cc406Sopenharmony_ci	/*
2136141cc406Sopenharmony_ci	 * set focus after we set scanning parameters because the scanner will
2137141cc406Sopenharmony_ci	 * use the middle of the scanning area for autofocus. If we want to
2138141cc406Sopenharmony_ci	 * support a defined x,y position for autofocus, we'd need to send
2139141cc406Sopenharmony_ci	 * specific scanning paramters just for autofocus.
2140141cc406Sopenharmony_ci	 */
2141141cc406Sopenharmony_ci	if (s->hw->focusSupport == SANE_TRUE) {
2142141cc406Sopenharmony_ci		if (s->val[OPT_AUTOFOCUS].w) {
2143141cc406Sopenharmony_ci			DBG(1, "setting autofocus\n");
2144141cc406Sopenharmony_ci			status = esci_set_focus_position(s, 0xff);
2145141cc406Sopenharmony_ci		} else {
2146141cc406Sopenharmony_ci			DBG(1, "setting focus to %u\n", s->val[OPT_FOCUS_POS].w);
2147141cc406Sopenharmony_ci			status = esci_set_focus_position(s, s->val[OPT_FOCUS_POS].w);
2148141cc406Sopenharmony_ci		}
2149141cc406Sopenharmony_ci
2150141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD) {
2151141cc406Sopenharmony_ci			DBG(1, "setting focus failed\n");
2152141cc406Sopenharmony_ci			return status;
2153141cc406Sopenharmony_ci		}
2154141cc406Sopenharmony_ci	}
2155141cc406Sopenharmony_ci
2156141cc406Sopenharmony_ci	/* ESC z, user defined gamma table */
2157141cc406Sopenharmony_ci	if (dev->cmd->set_gamma_table
2158141cc406Sopenharmony_ci	    && gamma_userdefined[s->val[OPT_GAMMA_CORRECTION].w]) {
2159141cc406Sopenharmony_ci		status = esci_set_gamma_table(s);
2160141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD)
2161141cc406Sopenharmony_ci			return status;
2162141cc406Sopenharmony_ci	}
2163141cc406Sopenharmony_ci
2164141cc406Sopenharmony_ci
2165141cc406Sopenharmony_ci	if (s->val[OPT_COLOR_CORRECTION].w == CORR_AUTO) { /* Automatic */
2166141cc406Sopenharmony_ci
2167141cc406Sopenharmony_ci		DBG(1, "using built in CCT profile\n");
2168141cc406Sopenharmony_ci
2169141cc406Sopenharmony_ci		if (dev->model_id == 0)
2170141cc406Sopenharmony_ci			DBG(1, " specific profile not available, using default\n");
2171141cc406Sopenharmony_ci
2172141cc406Sopenharmony_ci
2173141cc406Sopenharmony_ci		if (0) { /* XXX TPU */
2174141cc406Sopenharmony_ci
2175141cc406Sopenharmony_ci		        /* XXX check this */
2176141cc406Sopenharmony_ci			if (s->val[OPT_FILM_TYPE].w == 0)
2177141cc406Sopenharmony_ci				e2_load_cct_profile(s, CCTP_COLORPOS);
2178141cc406Sopenharmony_ci			else
2179141cc406Sopenharmony_ci				e2_load_cct_profile(s, CCTP_COLORNEG);
2180141cc406Sopenharmony_ci
2181141cc406Sopenharmony_ci		} else {
2182141cc406Sopenharmony_ci			e2_load_cct_profile(s, CCTP_REFLECTIVE);
2183141cc406Sopenharmony_ci		}
2184141cc406Sopenharmony_ci	}
2185141cc406Sopenharmony_ci
2186141cc406Sopenharmony_ci	/* ESC m, user defined color correction */
2187141cc406Sopenharmony_ci	if (s->hw->cmd->set_color_correction_coefficients
2188141cc406Sopenharmony_ci		&& correction_userdefined[s->val[OPT_COLOR_CORRECTION].w]) {
2189141cc406Sopenharmony_ci
2190141cc406Sopenharmony_ci		status = esci_set_color_correction_coefficients(s,
2191141cc406Sopenharmony_ci                                                        s->cct_table);
2192141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD)
2193141cc406Sopenharmony_ci			return status;
2194141cc406Sopenharmony_ci	}
2195141cc406Sopenharmony_ci
2196141cc406Sopenharmony_ci	/* check if we just have finished working with the ADF.
2197141cc406Sopenharmony_ci	 * this seems to work only after the scanner has been
2198141cc406Sopenharmony_ci	 * set up with scanning parameters
2199141cc406Sopenharmony_ci	 */
2200141cc406Sopenharmony_ci	status = e2_check_adf(s);
2201141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
2202141cc406Sopenharmony_ci		return status;
2203141cc406Sopenharmony_ci
2204141cc406Sopenharmony_ci	/*
2205141cc406Sopenharmony_ci	 * If WAIT_FOR_BUTTON is active, then do just that:
2206141cc406Sopenharmony_ci	 * Wait until the button is pressed. If the button was already
2207141cc406Sopenharmony_ci	 * pressed, then we will get the button pressed event right away.
2208141cc406Sopenharmony_ci	 */
2209141cc406Sopenharmony_ci	if (s->val[OPT_WAIT_FOR_BUTTON].w == SANE_TRUE)
2210141cc406Sopenharmony_ci		e2_wait_button(s);
2211141cc406Sopenharmony_ci
2212141cc406Sopenharmony_ci	/* for debug, request command parameter */
2213141cc406Sopenharmony_ci/*	if (DBG_LEVEL) {
2214141cc406Sopenharmony_ci		unsigned char buf[45];
2215141cc406Sopenharmony_ci		request_command_parameter(s, buf);
2216141cc406Sopenharmony_ci	}
2217141cc406Sopenharmony_ci*/
2218141cc406Sopenharmony_ci	/* set the retry count to 0 */
2219141cc406Sopenharmony_ci	s->retry_count = 0;
2220141cc406Sopenharmony_ci
2221141cc406Sopenharmony_ci	/* allocate buffers for color shuffling */
2222141cc406Sopenharmony_ci	if (dev->color_shuffle == SANE_TRUE) {
2223141cc406Sopenharmony_ci		int i;
2224141cc406Sopenharmony_ci		/* initialize the line buffers */
2225141cc406Sopenharmony_ci		for (i = 0; i < s->line_distance * 2 + 1; i++) {
2226141cc406Sopenharmony_ci
2227141cc406Sopenharmony_ci			if (s->line_buffer[i] != NULL)
2228141cc406Sopenharmony_ci				free(s->line_buffer[i]);
2229141cc406Sopenharmony_ci
2230141cc406Sopenharmony_ci			s->line_buffer[i] = malloc(s->params.bytes_per_line);
2231141cc406Sopenharmony_ci			if (s->line_buffer[i] == NULL) {
2232141cc406Sopenharmony_ci				DBG(1, "out of memory (line %d)\n", __LINE__);
2233141cc406Sopenharmony_ci				return SANE_STATUS_NO_MEM;
2234141cc406Sopenharmony_ci			}
2235141cc406Sopenharmony_ci		}
2236141cc406Sopenharmony_ci	}
2237141cc406Sopenharmony_ci
2238141cc406Sopenharmony_ci	/* prepare buffer here so that a memory allocation failure
2239141cc406Sopenharmony_ci	 * will leave the scanner in a sane state.
2240141cc406Sopenharmony_ci	 * the buffer will have to hold the image data plus
2241141cc406Sopenharmony_ci	 * an error code in the extended handshaking mode.
2242141cc406Sopenharmony_ci	 */
2243141cc406Sopenharmony_ci	s->buf = realloc(s->buf, (s->lcount * s->params.bytes_per_line) + 1);
2244141cc406Sopenharmony_ci	if (s->buf == NULL)
2245141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
2246141cc406Sopenharmony_ci
2247141cc406Sopenharmony_ci	s->ptr = s->end = s->buf;
2248141cc406Sopenharmony_ci
2249141cc406Sopenharmony_ci	/* feed the first sheet in the ADF */
2250141cc406Sopenharmony_ci	if (dev->ADF && dev->use_extension && dev->cmd->feed) {
2251141cc406Sopenharmony_ci		status = esci_feed(s);
2252141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD)
2253141cc406Sopenharmony_ci			return status;
2254141cc406Sopenharmony_ci	}
2255141cc406Sopenharmony_ci
2256141cc406Sopenharmony_ci	/* this seems to work only for some devices */
2257141cc406Sopenharmony_ci	status = e2_wait_warm_up(s);
2258141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
2259141cc406Sopenharmony_ci		return status;
2260141cc406Sopenharmony_ci
2261141cc406Sopenharmony_ci	if (s->hw->focusSupport == SANE_TRUE && s->val[OPT_AUTOFOCUS].w) {
2262141cc406Sopenharmony_ci		status = esci_request_focus_position(s, &s->currentFocusPosition);
2263141cc406Sopenharmony_ci		if (status == SANE_STATUS_GOOD)
2264141cc406Sopenharmony_ci			s->val[OPT_FOCUS_POS].w = s->currentFocusPosition;
2265141cc406Sopenharmony_ci	}
2266141cc406Sopenharmony_ci
2267141cc406Sopenharmony_ci	/* start scanning */
2268141cc406Sopenharmony_ci	DBG(1, "%s: scanning...\n", __func__);
2269141cc406Sopenharmony_ci
2270141cc406Sopenharmony_ci	if (dev->extended_commands) {
2271141cc406Sopenharmony_ci		status = e2_start_ext_scan(s);
2272141cc406Sopenharmony_ci
2273141cc406Sopenharmony_ci		/* sometimes the scanner gives an io error when
2274141cc406Sopenharmony_ci		 * it's warming up.
2275141cc406Sopenharmony_ci		 */
2276141cc406Sopenharmony_ci		if (status == SANE_STATUS_IO_ERROR) {
2277141cc406Sopenharmony_ci			status = e2_wait_warm_up(s);
2278141cc406Sopenharmony_ci			if (status == SANE_STATUS_GOOD)
2279141cc406Sopenharmony_ci				status = e2_start_ext_scan(s);
2280141cc406Sopenharmony_ci		}
2281141cc406Sopenharmony_ci	} else
2282141cc406Sopenharmony_ci		status = e2_start_std_scan(s);
2283141cc406Sopenharmony_ci
2284141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
2285141cc406Sopenharmony_ci		DBG(1, "%s: start failed: %s\n", __func__,
2286141cc406Sopenharmony_ci		    sane_strstatus(status));
2287141cc406Sopenharmony_ci
2288141cc406Sopenharmony_ci		return status;
2289141cc406Sopenharmony_ci	}
2290141cc406Sopenharmony_ci
2291141cc406Sopenharmony_ci	/* this is a kind of read request */
2292141cc406Sopenharmony_ci	if (dev->connection == SANE_EPSON_NET) {
2293141cc406Sopenharmony_ci		sanei_epson_net_write(s, 0x2000, NULL, 0,
2294141cc406Sopenharmony_ci		      s->ext_block_len + 1, &status);
2295141cc406Sopenharmony_ci	}
2296141cc406Sopenharmony_ci
2297141cc406Sopenharmony_ci	return status;
2298141cc406Sopenharmony_ci}
2299141cc406Sopenharmony_ci
2300141cc406Sopenharmony_ci/* this moves data from our buffers to SANE */
2301141cc406Sopenharmony_ci
2302141cc406Sopenharmony_ciSANE_Status
2303141cc406Sopenharmony_cisane_read(SANE_Handle handle, SANE_Byte *data, SANE_Int max_length,
2304141cc406Sopenharmony_ci	  SANE_Int *length)
2305141cc406Sopenharmony_ci{
2306141cc406Sopenharmony_ci	SANE_Status status;
2307141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
2308141cc406Sopenharmony_ci
2309141cc406Sopenharmony_ci	DBG(18, "* %s: eof: %d, canceling: %d\n",
2310141cc406Sopenharmony_ci		__func__, s->eof, s->canceling);
2311141cc406Sopenharmony_ci
2312141cc406Sopenharmony_ci	/* sane_read called before sane_start? */
2313141cc406Sopenharmony_ci	if (s->buf == NULL) {
2314141cc406Sopenharmony_ci		DBG(1, "%s: buffer is NULL", __func__);
2315141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
2316141cc406Sopenharmony_ci	}
2317141cc406Sopenharmony_ci
2318141cc406Sopenharmony_ci	*length = 0;
2319141cc406Sopenharmony_ci
2320141cc406Sopenharmony_ci	if (s->hw->extended_commands)
2321141cc406Sopenharmony_ci		status = e2_ext_read(s);
2322141cc406Sopenharmony_ci	else
2323141cc406Sopenharmony_ci		status = e2_block_read(s);
2324141cc406Sopenharmony_ci
2325141cc406Sopenharmony_ci	/* The scanning operation might be canceled by the scanner itself
2326141cc406Sopenharmony_ci	 * or the fronted program
2327141cc406Sopenharmony_ci	 */
2328141cc406Sopenharmony_ci	if (status == SANE_STATUS_CANCELLED || s->canceling) {
2329141cc406Sopenharmony_ci		e2_scan_finish(s);
2330141cc406Sopenharmony_ci		return SANE_STATUS_CANCELLED;
2331141cc406Sopenharmony_ci	}
2332141cc406Sopenharmony_ci
2333141cc406Sopenharmony_ci	/* XXX if FS G and STATUS_IOERR, use e2_check_extended_status */
2334141cc406Sopenharmony_ci
2335141cc406Sopenharmony_ci	DBG(18, "moving data %p %p, %d (%d lines)\n",
2336141cc406Sopenharmony_ci		(void *) s->ptr, (void *) s->end,
2337141cc406Sopenharmony_ci		max_length, max_length / s->params.bytes_per_line);
2338141cc406Sopenharmony_ci
2339141cc406Sopenharmony_ci	e2_copy_image_data(s, data, max_length, length);
2340141cc406Sopenharmony_ci
2341141cc406Sopenharmony_ci	DBG(18, "%d lines read, eof: %d, canceling: %d, status: %d\n",
2342141cc406Sopenharmony_ci		*length / s->params.bytes_per_line,
2343141cc406Sopenharmony_ci		s->canceling, s->eof, status);
2344141cc406Sopenharmony_ci
2345141cc406Sopenharmony_ci	/* continue reading if appropriate */
2346141cc406Sopenharmony_ci	if (status == SANE_STATUS_GOOD)
2347141cc406Sopenharmony_ci		return status;
2348141cc406Sopenharmony_ci
2349141cc406Sopenharmony_ci	e2_scan_finish(s);
2350141cc406Sopenharmony_ci
2351141cc406Sopenharmony_ci	return status;
2352141cc406Sopenharmony_ci}
2353141cc406Sopenharmony_ci
2354141cc406Sopenharmony_ci/*
2355141cc406Sopenharmony_ci * void sane_cancel(SANE_Handle handle)
2356141cc406Sopenharmony_ci *
2357141cc406Sopenharmony_ci * Set the cancel flag to true. The next time the backend requests data
2358141cc406Sopenharmony_ci * from the scanner the CAN message will be sent.
2359141cc406Sopenharmony_ci */
2360141cc406Sopenharmony_ci
2361141cc406Sopenharmony_civoid
2362141cc406Sopenharmony_cisane_cancel(SANE_Handle handle)
2363141cc406Sopenharmony_ci{
2364141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
2365141cc406Sopenharmony_ci
2366141cc406Sopenharmony_ci	DBG(1, "* %s\n", __func__);
2367141cc406Sopenharmony_ci
2368141cc406Sopenharmony_ci	s->canceling = SANE_TRUE;
2369141cc406Sopenharmony_ci}
2370141cc406Sopenharmony_ci
2371141cc406Sopenharmony_ci/*
2372141cc406Sopenharmony_ci * SANE_Status sane_set_io_mode()
2373141cc406Sopenharmony_ci *
2374141cc406Sopenharmony_ci * not supported - for asynchronous I/O
2375141cc406Sopenharmony_ci */
2376141cc406Sopenharmony_ci
2377141cc406Sopenharmony_ciSANE_Status
2378141cc406Sopenharmony_cisane_set_io_mode(SANE_Handle __sane_unused__ handle,
2379141cc406Sopenharmony_ci	SANE_Bool __sane_unused__ non_blocking)
2380141cc406Sopenharmony_ci{
2381141cc406Sopenharmony_ci	return SANE_STATUS_UNSUPPORTED;
2382141cc406Sopenharmony_ci}
2383141cc406Sopenharmony_ci
2384141cc406Sopenharmony_ci/*
2385141cc406Sopenharmony_ci * SANE_Status sane_get_select_fd()
2386141cc406Sopenharmony_ci *
2387141cc406Sopenharmony_ci * not supported - for asynchronous I/O
2388141cc406Sopenharmony_ci */
2389141cc406Sopenharmony_ci
2390141cc406Sopenharmony_ciSANE_Status
2391141cc406Sopenharmony_cisane_get_select_fd(SANE_Handle __sane_unused__ handle,
2392141cc406Sopenharmony_ci	SANE_Int __sane_unused__ *fd)
2393141cc406Sopenharmony_ci{
2394141cc406Sopenharmony_ci	return SANE_STATUS_UNSUPPORTED;
2395141cc406Sopenharmony_ci}
2396