1141cc406Sopenharmony_ci/*
2141cc406Sopenharmony_ci * ESC/I commands 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 original copyrights.
7141cc406Sopenharmony_ci *
8141cc406Sopenharmony_ci * Copyright (C) 2006 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#define DEBUG_DECLARE_ONLY
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci#include "sane/config.h"
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci#include <byteorder.h>
23141cc406Sopenharmony_ci#include <math.h>
24141cc406Sopenharmony_ci#include <sys/types.h>
25141cc406Sopenharmony_ci
26141cc406Sopenharmony_ci#include "epson2.h"
27141cc406Sopenharmony_ci#include "epson2-io.h"
28141cc406Sopenharmony_ci#include "epson2-commands.h"
29141cc406Sopenharmony_ci
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci/* ESC H, set zoom */
32141cc406Sopenharmony_ciSANE_Status
33141cc406Sopenharmony_ciesci_set_zoom(Epson_Scanner * s, unsigned char x, unsigned char y)
34141cc406Sopenharmony_ci{
35141cc406Sopenharmony_ci	SANE_Status status;
36141cc406Sopenharmony_ci	unsigned char params[2];
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci	DBG(8, "%s: x = %d, y = %d\n", __func__, x, y);
39141cc406Sopenharmony_ci
40141cc406Sopenharmony_ci	if (!s->hw->cmd->set_zoom) {
41141cc406Sopenharmony_ci		DBG(1, "%s: not supported\n", __func__);
42141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
43141cc406Sopenharmony_ci	}
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci	params[0] = ESC;
46141cc406Sopenharmony_ci	params[1] = s->hw->cmd->set_zoom;
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci	status = e2_cmd_simple(s, params, 2);
49141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
50141cc406Sopenharmony_ci		return status;
51141cc406Sopenharmony_ci
52141cc406Sopenharmony_ci	params[0] = x;
53141cc406Sopenharmony_ci	params[1] = y;
54141cc406Sopenharmony_ci
55141cc406Sopenharmony_ci	return e2_cmd_simple(s, params, 2);
56141cc406Sopenharmony_ci}
57141cc406Sopenharmony_ci
58141cc406Sopenharmony_ci/* ESC R */
59141cc406Sopenharmony_ciSANE_Status
60141cc406Sopenharmony_ciesci_set_resolution(Epson_Scanner * s, int x, int y)
61141cc406Sopenharmony_ci{
62141cc406Sopenharmony_ci	SANE_Status status;
63141cc406Sopenharmony_ci	unsigned char params[4];
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci	DBG(8, "%s: x = %d, y = %d\n", __func__, x, y);
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci	if (!s->hw->cmd->set_resolution) {
68141cc406Sopenharmony_ci		DBG(1, "%s: not supported\n", __func__);
69141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
70141cc406Sopenharmony_ci	}
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci	params[0] = ESC;
73141cc406Sopenharmony_ci	params[1] = s->hw->cmd->set_resolution;
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci	status = e2_cmd_simple(s, params, 2);
76141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
77141cc406Sopenharmony_ci		return status;
78141cc406Sopenharmony_ci
79141cc406Sopenharmony_ci	params[0] = x;
80141cc406Sopenharmony_ci	params[1] = x >> 8;
81141cc406Sopenharmony_ci	params[2] = y;
82141cc406Sopenharmony_ci	params[3] = y >> 8;
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci	return e2_cmd_simple(s, params, 4);
85141cc406Sopenharmony_ci}
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_ci/*
88141cc406Sopenharmony_ci * Sends the "set scan area" command to the scanner with the currently selected
89141cc406Sopenharmony_ci * scan area. This scan area must be already corrected for "color shuffling" if
90141cc406Sopenharmony_ci * necessary.
91141cc406Sopenharmony_ci */
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ciSANE_Status
94141cc406Sopenharmony_ciesci_set_scan_area(Epson_Scanner * s, int x, int y, int width, int height)
95141cc406Sopenharmony_ci{
96141cc406Sopenharmony_ci	SANE_Status status;
97141cc406Sopenharmony_ci	unsigned char params[8];
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci	DBG(8, "%s: x = %d, y = %d, w = %d, h = %d\n",
100141cc406Sopenharmony_ci	    __func__, x, y, width, height);
101141cc406Sopenharmony_ci
102141cc406Sopenharmony_ci	if (!s->hw->cmd->set_scan_area) {
103141cc406Sopenharmony_ci		DBG(1, "%s: not supported\n", __func__);
104141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
105141cc406Sopenharmony_ci	}
106141cc406Sopenharmony_ci
107141cc406Sopenharmony_ci	/* verify the scan area */
108141cc406Sopenharmony_ci	if (x < 0 || y < 0 || width <= 0 || height <= 0)
109141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_ci	params[0] = ESC;
112141cc406Sopenharmony_ci	params[1] = s->hw->cmd->set_scan_area;
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci	status = e2_cmd_simple(s, params, 2);
115141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
116141cc406Sopenharmony_ci		return status;
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_ci	params[0] = x;
119141cc406Sopenharmony_ci	params[1] = x >> 8;
120141cc406Sopenharmony_ci	params[2] = y;
121141cc406Sopenharmony_ci	params[3] = y >> 8;
122141cc406Sopenharmony_ci	params[4] = width;
123141cc406Sopenharmony_ci	params[5] = width >> 8;
124141cc406Sopenharmony_ci	params[6] = height;
125141cc406Sopenharmony_ci	params[7] = height >> 8;
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ci	return e2_cmd_simple(s, params, 8);
128141cc406Sopenharmony_ci}
129141cc406Sopenharmony_ci
130141cc406Sopenharmony_cistatic int
131141cc406Sopenharmony_ciget_roundup_index(double frac[], int n)
132141cc406Sopenharmony_ci{
133141cc406Sopenharmony_ci	int i, index = -1;
134141cc406Sopenharmony_ci	double max_val = 0.0;
135141cc406Sopenharmony_ci
136141cc406Sopenharmony_ci	for (i = 0; i < n; i++) {
137141cc406Sopenharmony_ci
138141cc406Sopenharmony_ci		if (frac[i] < 0)
139141cc406Sopenharmony_ci			continue;
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_ci		if (max_val < frac[i]) {
142141cc406Sopenharmony_ci			index = i;
143141cc406Sopenharmony_ci			max_val = frac[i];
144141cc406Sopenharmony_ci		}
145141cc406Sopenharmony_ci	}
146141cc406Sopenharmony_ci
147141cc406Sopenharmony_ci	return index;
148141cc406Sopenharmony_ci}
149141cc406Sopenharmony_ci
150141cc406Sopenharmony_cistatic int
151141cc406Sopenharmony_ciget_rounddown_index(double frac[], int n)
152141cc406Sopenharmony_ci{
153141cc406Sopenharmony_ci	int i, index = -1;
154141cc406Sopenharmony_ci	double min_val = 1.0;
155141cc406Sopenharmony_ci
156141cc406Sopenharmony_ci	for (i = 0; i < n; i++) {
157141cc406Sopenharmony_ci
158141cc406Sopenharmony_ci		if (frac[i] > 0)
159141cc406Sopenharmony_ci			continue;
160141cc406Sopenharmony_ci
161141cc406Sopenharmony_ci		if (min_val > frac[i]) {
162141cc406Sopenharmony_ci			index = i;
163141cc406Sopenharmony_ci			min_val = frac[i];
164141cc406Sopenharmony_ci		}
165141cc406Sopenharmony_ci	}
166141cc406Sopenharmony_ci
167141cc406Sopenharmony_ci	return index;
168141cc406Sopenharmony_ci}
169141cc406Sopenharmony_ci
170141cc406Sopenharmony_cistatic unsigned char
171141cc406Sopenharmony_ciint2cpt(int val)
172141cc406Sopenharmony_ci{
173141cc406Sopenharmony_ci	if (val >= 0) {
174141cc406Sopenharmony_ci
175141cc406Sopenharmony_ci		if (val > 127)
176141cc406Sopenharmony_ci			val = 127;
177141cc406Sopenharmony_ci
178141cc406Sopenharmony_ci		return (unsigned char) val;
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_ci	} else {
181141cc406Sopenharmony_ci
182141cc406Sopenharmony_ci		val = -val;
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci		if (val > 127)
185141cc406Sopenharmony_ci			val = 127;
186141cc406Sopenharmony_ci
187141cc406Sopenharmony_ci		return (unsigned char) (0x80 | val);
188141cc406Sopenharmony_ci	}
189141cc406Sopenharmony_ci}
190141cc406Sopenharmony_ci
191141cc406Sopenharmony_cistatic void
192141cc406Sopenharmony_ciround_cct(double org_cct[], int rnd_cct[])
193141cc406Sopenharmony_ci{
194141cc406Sopenharmony_ci	int loop = 0;
195141cc406Sopenharmony_ci	int i, j, sum[3];
196141cc406Sopenharmony_ci	double mult_cct[9], frac[9];
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_ci	for (i = 0; i < 9; i++) {
199141cc406Sopenharmony_ci  		mult_cct[i] = org_cct[i] * 32;
200141cc406Sopenharmony_ci		rnd_cct[i] = (int) floor(mult_cct[i] + 0.5);
201141cc406Sopenharmony_ci	}
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_ci	do {
204141cc406Sopenharmony_ci		for (i = 0; i < 3; i++) {
205141cc406Sopenharmony_ci
206141cc406Sopenharmony_ci			int k = i * 3;
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_ci			if ((rnd_cct[k] == 11) &&
209141cc406Sopenharmony_ci				(rnd_cct[k] == rnd_cct[k + 1]) &&
210141cc406Sopenharmony_ci				(rnd_cct[k] == rnd_cct[k + 2])) {
211141cc406Sopenharmony_ci
212141cc406Sopenharmony_ci				rnd_cct[k + i]--;
213141cc406Sopenharmony_ci				mult_cct[k + i] = rnd_cct[k + i];
214141cc406Sopenharmony_ci			}
215141cc406Sopenharmony_ci		}
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci		for (i = 0; i < 3; i++) {
218141cc406Sopenharmony_ci
219141cc406Sopenharmony_ci			int k = i * 3;
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_ci			for (sum[i] = j = 0; j < 3; j++)
222141cc406Sopenharmony_ci				sum[i] += rnd_cct[k + j];
223141cc406Sopenharmony_ci		}
224141cc406Sopenharmony_ci
225141cc406Sopenharmony_ci		for (i = 0; i < 9; i++)
226141cc406Sopenharmony_ci			frac[i] = mult_cct[i] - rnd_cct[i];
227141cc406Sopenharmony_ci
228141cc406Sopenharmony_ci		for (i = 0; i < 3; i++) {
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_ci			int k = i * 3;
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_ci			if (sum[i] < 32) {
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_ci				int index = get_roundup_index(&frac[k], 3);
235141cc406Sopenharmony_ci				if (index != -1) {
236141cc406Sopenharmony_ci					rnd_cct[k + index]++;
237141cc406Sopenharmony_ci					mult_cct[k + index] = rnd_cct[k + index];
238141cc406Sopenharmony_ci					sum[i]++;
239141cc406Sopenharmony_ci				}
240141cc406Sopenharmony_ci
241141cc406Sopenharmony_ci			} else if (sum[i] > 32) {
242141cc406Sopenharmony_ci
243141cc406Sopenharmony_ci				int index = get_rounddown_index(&frac[k], 3);
244141cc406Sopenharmony_ci				if (index != -1) {
245141cc406Sopenharmony_ci					rnd_cct[k + index]--;
246141cc406Sopenharmony_ci					mult_cct[k + index] = rnd_cct[k + index];
247141cc406Sopenharmony_ci					sum[i]--;
248141cc406Sopenharmony_ci				}
249141cc406Sopenharmony_ci			}
250141cc406Sopenharmony_ci		}
251141cc406Sopenharmony_ci	}
252141cc406Sopenharmony_ci
253141cc406Sopenharmony_ci	while ((++loop < 2)
254141cc406Sopenharmony_ci		&& ((sum[0] != 32) || (sum[1] != 32) || (sum[2] != 32)));
255141cc406Sopenharmony_ci}
256141cc406Sopenharmony_ci
257141cc406Sopenharmony_cistatic void
258141cc406Sopenharmony_ciprofile_to_colorcoeff(double *profile, unsigned char *color_coeff)
259141cc406Sopenharmony_ci{
260141cc406Sopenharmony_ci	int cc_idx[] = { 4, 1, 7, 3, 0, 6, 5, 2, 8 };
261141cc406Sopenharmony_ci	int i, color_table[9];
262141cc406Sopenharmony_ci
263141cc406Sopenharmony_ci  	round_cct(profile, color_table);
264141cc406Sopenharmony_ci
265141cc406Sopenharmony_ci  	for (i = 0; i < 9; i++)
266141cc406Sopenharmony_ci  		color_coeff[i] = int2cpt(color_table[cc_idx[i]]);
267141cc406Sopenharmony_ci}
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci
270141cc406Sopenharmony_ci/*
271141cc406Sopenharmony_ci * Sends the "set color correction coefficients" command with the
272141cc406Sopenharmony_ci * currently selected parameters to the scanner.
273141cc406Sopenharmony_ci */
274141cc406Sopenharmony_ci
275141cc406Sopenharmony_ciSANE_Status
276141cc406Sopenharmony_ciesci_set_color_correction_coefficients(Epson_Scanner * s, SANE_Word *table)
277141cc406Sopenharmony_ci{
278141cc406Sopenharmony_ci	SANE_Status status;
279141cc406Sopenharmony_ci	unsigned char params[2];
280141cc406Sopenharmony_ci	unsigned char data[9];
281141cc406Sopenharmony_ci	double cct[9];
282141cc406Sopenharmony_ci
283141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
284141cc406Sopenharmony_ci	if (!s->hw->cmd->set_color_correction_coefficients) {
285141cc406Sopenharmony_ci		DBG(1, "%s: not supported\n", __func__);
286141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
287141cc406Sopenharmony_ci	}
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci	params[0] = ESC;
290141cc406Sopenharmony_ci	params[1] = s->hw->cmd->set_color_correction_coefficients;
291141cc406Sopenharmony_ci
292141cc406Sopenharmony_ci	status = e2_cmd_simple(s, params, 2);
293141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
294141cc406Sopenharmony_ci		return status;
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci	cct[0] = SANE_UNFIX(table[0]);
297141cc406Sopenharmony_ci	cct[1] = SANE_UNFIX(table[1]);
298141cc406Sopenharmony_ci	cct[2] = SANE_UNFIX(table[2]);
299141cc406Sopenharmony_ci	cct[3] = SANE_UNFIX(table[3]);
300141cc406Sopenharmony_ci	cct[4] = SANE_UNFIX(table[4]);
301141cc406Sopenharmony_ci	cct[5] = SANE_UNFIX(table[5]);
302141cc406Sopenharmony_ci	cct[6] = SANE_UNFIX(table[6]);
303141cc406Sopenharmony_ci	cct[7] = SANE_UNFIX(table[7]);
304141cc406Sopenharmony_ci	cct[8] = SANE_UNFIX(table[8]);
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci	profile_to_colorcoeff(cct, data);
307141cc406Sopenharmony_ci
308141cc406Sopenharmony_ci	DBG(11, "%s: %d,%d,%d %d,%d,%d %d,%d,%d\n", __func__,
309141cc406Sopenharmony_ci	    data[0] , data[1], data[2], data[3],
310141cc406Sopenharmony_ci	    data[4], data[5], data[6], data[7], data[8]);
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_ci	return e2_cmd_simple(s, data, 9);
313141cc406Sopenharmony_ci}
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_ciSANE_Status
316141cc406Sopenharmony_ciesci_set_gamma_table(Epson_Scanner * s)
317141cc406Sopenharmony_ci{
318141cc406Sopenharmony_ci	SANE_Status status;
319141cc406Sopenharmony_ci	unsigned char params[2];
320141cc406Sopenharmony_ci	unsigned char gamma[257];
321141cc406Sopenharmony_ci	int n;
322141cc406Sopenharmony_ci	int table;
323141cc406Sopenharmony_ci
324141cc406Sopenharmony_ci/*	static const char gamma_cmds[] = { 'M', 'R', 'G', 'B' }; */
325141cc406Sopenharmony_ci	static const char gamma_cmds[] = { 'R', 'G', 'B' };
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
328141cc406Sopenharmony_ci	if (!s->hw->cmd->set_gamma_table)
329141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
330141cc406Sopenharmony_ci
331141cc406Sopenharmony_ci	params[0] = ESC;
332141cc406Sopenharmony_ci	params[1] = s->hw->cmd->set_gamma_table;
333141cc406Sopenharmony_ci
334141cc406Sopenharmony_ci	/* Print the gamma tables before sending them to the scanner */
335141cc406Sopenharmony_ci
336141cc406Sopenharmony_ci	if (DBG_LEVEL >= 16) {
337141cc406Sopenharmony_ci		int c, i, j;
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci		for (c = 0; c < 3; c++) {
340141cc406Sopenharmony_ci			for (i = 0; i < 256; i += 16) {
341141cc406Sopenharmony_ci				char gammaValues[16 * 3 + 1], newValue[4];
342141cc406Sopenharmony_ci
343141cc406Sopenharmony_ci				gammaValues[0] = '\0';
344141cc406Sopenharmony_ci
345141cc406Sopenharmony_ci				for (j = 0; j < 16; j++) {
346141cc406Sopenharmony_ci					sprintf(newValue, " %02x",
347141cc406Sopenharmony_ci						s->gamma_table[c][i + j]);
348141cc406Sopenharmony_ci					strcat(gammaValues, newValue);
349141cc406Sopenharmony_ci				}
350141cc406Sopenharmony_ci
351141cc406Sopenharmony_ci				DBG(16, "gamma table[%d][%d] %s\n", c, i,
352141cc406Sopenharmony_ci				    gammaValues);
353141cc406Sopenharmony_ci			}
354141cc406Sopenharmony_ci		}
355141cc406Sopenharmony_ci	}
356141cc406Sopenharmony_ci
357141cc406Sopenharmony_ci	for (table = 0; table < 3; table++) {
358141cc406Sopenharmony_ci		gamma[0] = gamma_cmds[table];
359141cc406Sopenharmony_ci
360141cc406Sopenharmony_ci		for (n = 0; n < 256; ++n)
361141cc406Sopenharmony_ci			gamma[n + 1] = s->gamma_table[table][n];
362141cc406Sopenharmony_ci
363141cc406Sopenharmony_ci		status = e2_cmd_simple(s, params, 2);
364141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD)
365141cc406Sopenharmony_ci			return status;
366141cc406Sopenharmony_ci
367141cc406Sopenharmony_ci		status = e2_cmd_simple(s, gamma, 257);
368141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD)
369141cc406Sopenharmony_ci			return status;
370141cc406Sopenharmony_ci	}
371141cc406Sopenharmony_ci
372141cc406Sopenharmony_ci	return status;
373141cc406Sopenharmony_ci}
374141cc406Sopenharmony_ci
375141cc406Sopenharmony_ci/* ESC F - Request Status
376141cc406Sopenharmony_ci * -> ESC f
377141cc406Sopenharmony_ci * <- Information block
378141cc406Sopenharmony_ci */
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ciSANE_Status
381141cc406Sopenharmony_ciesci_request_status(SANE_Handle handle, unsigned char *scanner_status)
382141cc406Sopenharmony_ci{
383141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
384141cc406Sopenharmony_ci	SANE_Status status;
385141cc406Sopenharmony_ci	unsigned char params[2];
386141cc406Sopenharmony_ci
387141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
388141cc406Sopenharmony_ci
389141cc406Sopenharmony_ci	if (s->hw->cmd->request_status == 0)
390141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
391141cc406Sopenharmony_ci
392141cc406Sopenharmony_ci	params[0] = ESC;
393141cc406Sopenharmony_ci	params[1] = s->hw->cmd->request_status;
394141cc406Sopenharmony_ci
395141cc406Sopenharmony_ci	e2_send(s, params, 2, 4, &status);
396141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
397141cc406Sopenharmony_ci		return status;
398141cc406Sopenharmony_ci
399141cc406Sopenharmony_ci	status = e2_recv_info_block(s, params, 4, NULL);
400141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
401141cc406Sopenharmony_ci		return status;
402141cc406Sopenharmony_ci
403141cc406Sopenharmony_ci	if (scanner_status)
404141cc406Sopenharmony_ci		*scanner_status = params[0];
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_ci	DBG(1, "status: %02x\n", params[0]);
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_ci	if (params[0] & STATUS_NOT_READY)
409141cc406Sopenharmony_ci		DBG(1, " scanner in use on another interface\n");
410141cc406Sopenharmony_ci	else
411141cc406Sopenharmony_ci		DBG(1, " ready\n");
412141cc406Sopenharmony_ci
413141cc406Sopenharmony_ci	if (params[0] & STATUS_FER)
414141cc406Sopenharmony_ci		DBG(1, " system error\n");
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci	if (params[0] & STATUS_OPTION)
417141cc406Sopenharmony_ci		DBG(1, " option equipment is installed\n");
418141cc406Sopenharmony_ci	else
419141cc406Sopenharmony_ci		DBG(1, " no option equipment installed\n");
420141cc406Sopenharmony_ci
421141cc406Sopenharmony_ci	if (params[0] & STATUS_EXT_COMMANDS)
422141cc406Sopenharmony_ci		DBG(1, " support extended commands\n");
423141cc406Sopenharmony_ci	else
424141cc406Sopenharmony_ci		DBG(1, " does NOT support extended commands\n");
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci	if (params[0] & STATUS_RESERVED)
427141cc406Sopenharmony_ci		DBG(0,
428141cc406Sopenharmony_ci		    " a reserved bit is set, please contact the author.\n");
429141cc406Sopenharmony_ci
430141cc406Sopenharmony_ci	return status;
431141cc406Sopenharmony_ci}
432141cc406Sopenharmony_ci
433141cc406Sopenharmony_ci/* extended commands */
434141cc406Sopenharmony_ci
435141cc406Sopenharmony_ci/* FS I, Request Extended Identity
436141cc406Sopenharmony_ci * -> FS I
437141cc406Sopenharmony_ci * <- Extended identity data (80)
438141cc406Sopenharmony_ci *
439141cc406Sopenharmony_ci * Request the properties of the scanner.
440141cc406Sopenharmony_ci */
441141cc406Sopenharmony_ci
442141cc406Sopenharmony_ciSANE_Status
443141cc406Sopenharmony_ciesci_request_extended_identity(SANE_Handle handle, unsigned char *buf)
444141cc406Sopenharmony_ci{
445141cc406Sopenharmony_ci	unsigned char model[17];
446141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
447141cc406Sopenharmony_ci	SANE_Status status;
448141cc406Sopenharmony_ci	unsigned char params[2];
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci	if (buf == NULL)
453141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
454141cc406Sopenharmony_ci
455141cc406Sopenharmony_ci	if (s->hw->cmd->request_extended_identity == 0)
456141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_ci	params[0] = FS;
459141cc406Sopenharmony_ci	params[1] = s->hw->cmd->request_extended_identity;
460141cc406Sopenharmony_ci
461141cc406Sopenharmony_ci	status = e2_txrx(s, params, 2, buf, 80);
462141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
463141cc406Sopenharmony_ci		return status;
464141cc406Sopenharmony_ci
465141cc406Sopenharmony_ci	DBG(1, " command level   : %c%c\n", buf[0], buf[1]);
466141cc406Sopenharmony_ci	DBG(1, " basic resolution: %lu\n", (unsigned long) le32atoh(&buf[4]));
467141cc406Sopenharmony_ci	DBG(1, " min resolution  : %lu\n", (unsigned long) le32atoh(&buf[8]));
468141cc406Sopenharmony_ci	DBG(1, " max resolution  : %lu\n", (unsigned long) le32atoh(&buf[12]));
469141cc406Sopenharmony_ci	DBG(1, " max pixel num   : %lu\n", (unsigned long) le32atoh(&buf[16]));
470141cc406Sopenharmony_ci	DBG(1, " scan area       : %lux%lu\n",
471141cc406Sopenharmony_ci	    (unsigned long) le32atoh(&buf[20]), (unsigned long) le32atoh(&buf[24]));
472141cc406Sopenharmony_ci
473141cc406Sopenharmony_ci	DBG(1, " adf area        : %lux%lu\n",
474141cc406Sopenharmony_ci	    (unsigned long) le32atoh(&buf[28]), (unsigned long) le32atoh(&buf[32]));
475141cc406Sopenharmony_ci
476141cc406Sopenharmony_ci	DBG(1, " tpu area        : %lux%lu\n",
477141cc406Sopenharmony_ci	    (unsigned long) le32atoh(&buf[36]), (unsigned long) le32atoh(&buf[40]));
478141cc406Sopenharmony_ci
479141cc406Sopenharmony_ci	DBG(1, " capabilities (1): 0x%02x\n", buf[44]);
480141cc406Sopenharmony_ci	DBG(1, " capabilities (2): 0x%02x\n", buf[45]);
481141cc406Sopenharmony_ci	DBG(1, " input depth     : %d\n", buf[66]);
482141cc406Sopenharmony_ci	DBG(1, " max output depth: %d\n", buf[67]);
483141cc406Sopenharmony_ci	DBG(1, " rom version     : %c%c%c%c\n",
484141cc406Sopenharmony_ci	    buf[62], buf[63], buf[64], buf[65]);
485141cc406Sopenharmony_ci
486141cc406Sopenharmony_ci	memcpy(model, &buf[46], 16);
487141cc406Sopenharmony_ci	model[16] = '\0';
488141cc406Sopenharmony_ci	DBG(1, " model name      : %s\n", model);
489141cc406Sopenharmony_ci
490141cc406Sopenharmony_ci	DBG(1, "options:\n");
491141cc406Sopenharmony_ci
492141cc406Sopenharmony_ci	if (le32atoh(&buf[28]) > 0)
493141cc406Sopenharmony_ci		DBG(1, " ADF detected\n");
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci	if (le32atoh(&buf[36]) > 0)
496141cc406Sopenharmony_ci		DBG(1, " TPU detected\n");
497141cc406Sopenharmony_ci
498141cc406Sopenharmony_ci	if (buf[44])
499141cc406Sopenharmony_ci		DBG(1, "capabilities (1):\n");
500141cc406Sopenharmony_ci
501141cc406Sopenharmony_ci	if (buf[44] & EXT_IDTY_CAP1_DLF)
502141cc406Sopenharmony_ci		DBG(1, " main lamp change is supported\n");
503141cc406Sopenharmony_ci
504141cc406Sopenharmony_ci	if (buf[44] & EXT_IDTY_CAP1_NOTFBF)
505141cc406Sopenharmony_ci		DBG(1, " the device is NOT flatbed\n");
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci	if (buf[44] & EXT_IDTY_CAP1_ADFT)
508141cc406Sopenharmony_ci		DBG(1, " page type ADF is installed\n");
509141cc406Sopenharmony_ci
510141cc406Sopenharmony_ci	if (buf[44] & EXT_IDTY_CAP1_ADFS)
511141cc406Sopenharmony_ci		DBG(1, " ADF is duplex capable\n");
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci	if (buf[44] & EXT_IDTY_CAP1_ADFO)
514141cc406Sopenharmony_ci		DBG(1, " page type ADF loads from the first sheet\n");
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci	if (buf[44] & EXT_IDTY_CAP1_LID)
517141cc406Sopenharmony_ci		DBG(1, " lid type option is installed\n");
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ci	if (buf[44] & EXT_IDTY_CAP1_TPIR)
520141cc406Sopenharmony_ci		DBG(1, " infrared scanning is supported\n");
521141cc406Sopenharmony_ci
522141cc406Sopenharmony_ci	if (buf[44] & EXT_IDTY_CAP1_PB)
523141cc406Sopenharmony_ci		DBG(1, " push button is supported\n");
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci
526141cc406Sopenharmony_ci	if (buf[45])
527141cc406Sopenharmony_ci		DBG(1, "capabilities (2):\n");
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci	if (buf[45] & EXT_IDTY_CAP2_AFF)
530141cc406Sopenharmony_ci		DBG(1, " ADF has auto form feed\n");
531141cc406Sopenharmony_ci
532141cc406Sopenharmony_ci	if (buf[45] & EXT_IDTY_CAP2_DFD)
533141cc406Sopenharmony_ci		DBG(1, " ADF has double feed detection\n");
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci	if (buf[45] & EXT_IDTY_CAP2_ADFAS)
536141cc406Sopenharmony_ci		DBG(1, " ADF has auto scan\n");
537141cc406Sopenharmony_ci
538141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
539141cc406Sopenharmony_ci}
540141cc406Sopenharmony_ci
541141cc406Sopenharmony_ci/* FS F, request scanner status */
542141cc406Sopenharmony_ciSANE_Status
543141cc406Sopenharmony_ciesci_request_scanner_status(SANE_Handle handle, unsigned char *buf)
544141cc406Sopenharmony_ci{
545141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
546141cc406Sopenharmony_ci	SANE_Status status;
547141cc406Sopenharmony_ci	unsigned char params[2];
548141cc406Sopenharmony_ci
549141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
550141cc406Sopenharmony_ci
551141cc406Sopenharmony_ci	if (!s->hw->extended_commands)
552141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
553141cc406Sopenharmony_ci
554141cc406Sopenharmony_ci	if (buf == NULL)
555141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
556141cc406Sopenharmony_ci
557141cc406Sopenharmony_ci	params[0] = FS;
558141cc406Sopenharmony_ci	params[1] = 'F';
559141cc406Sopenharmony_ci
560141cc406Sopenharmony_ci	status = e2_txrx(s, params, 2, buf, 16);
561141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
562141cc406Sopenharmony_ci		return status;
563141cc406Sopenharmony_ci
564141cc406Sopenharmony_ci	DBG(1, "global status   : 0x%02x\n", buf[0]);
565141cc406Sopenharmony_ci
566141cc406Sopenharmony_ci	if (buf[0] & FSF_STATUS_MAIN_FER)
567141cc406Sopenharmony_ci		DBG(1, " system error\n");
568141cc406Sopenharmony_ci
569141cc406Sopenharmony_ci	if (buf[0] & FSF_STATUS_MAIN_NR)
570141cc406Sopenharmony_ci		DBG(1, " not ready\n");
571141cc406Sopenharmony_ci
572141cc406Sopenharmony_ci	if (buf[0] & FSF_STATUS_MAIN_WU)
573141cc406Sopenharmony_ci		DBG(1, " scanner is warming up\n");
574141cc406Sopenharmony_ci
575141cc406Sopenharmony_ci	if (buf[0] & FSF_STATUS_MAIN_CWU)
576141cc406Sopenharmony_ci		DBG(1, " warmup can be cancelled\n");
577141cc406Sopenharmony_ci
578141cc406Sopenharmony_ci
579141cc406Sopenharmony_ci	DBG(1, "adf status      : 0x%02x\n", buf[1]);
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ci	if (buf[1] & FSF_STATUS_ADF_IST)
582141cc406Sopenharmony_ci		DBG(11, " installed\n");
583141cc406Sopenharmony_ci	else
584141cc406Sopenharmony_ci		DBG(11, " not installed\n");
585141cc406Sopenharmony_ci
586141cc406Sopenharmony_ci	if (buf[1] & FSF_STATUS_ADF_EN)
587141cc406Sopenharmony_ci		DBG(11, " enabled\n");
588141cc406Sopenharmony_ci	else
589141cc406Sopenharmony_ci		DBG(11, " not enabled\n");
590141cc406Sopenharmony_ci
591141cc406Sopenharmony_ci	if (buf[1] & FSF_STATUS_ADF_ERR)
592141cc406Sopenharmony_ci		DBG(1, " error\n");
593141cc406Sopenharmony_ci
594141cc406Sopenharmony_ci	if (buf[1] & FSF_STATUS_ADF_PE)
595141cc406Sopenharmony_ci		DBG(1, " paper empty\n");
596141cc406Sopenharmony_ci
597141cc406Sopenharmony_ci	if (buf[1] & FSF_STATUS_ADF_PJ)
598141cc406Sopenharmony_ci		DBG(1, " paper jam\n");
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_ci	if (buf[1] & FSF_STATUS_ADF_OPN)
601141cc406Sopenharmony_ci		DBG(1, " cover open\n");
602141cc406Sopenharmony_ci
603141cc406Sopenharmony_ci	if (buf[1] & FSF_STATUS_ADF_PAG)
604141cc406Sopenharmony_ci		DBG(1, " duplex capable\n");
605141cc406Sopenharmony_ci
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci	DBG(1, "tpu status      : 0x%02x\n", buf[2]);
608141cc406Sopenharmony_ci
609141cc406Sopenharmony_ci	if (buf[2] & FSF_STATUS_TPU_IST)
610141cc406Sopenharmony_ci		DBG(11, " installed\n");
611141cc406Sopenharmony_ci	else
612141cc406Sopenharmony_ci		DBG(11, " not installed\n");
613141cc406Sopenharmony_ci
614141cc406Sopenharmony_ci	if (buf[2] & FSF_STATUS_TPU_EN)
615141cc406Sopenharmony_ci		DBG(11, " enabled\n");
616141cc406Sopenharmony_ci	else
617141cc406Sopenharmony_ci		DBG(11, " not enabled\n");
618141cc406Sopenharmony_ci
619141cc406Sopenharmony_ci	if (buf[2] & FSF_STATUS_TPU_ERR)
620141cc406Sopenharmony_ci		DBG(1, " error\n");
621141cc406Sopenharmony_ci
622141cc406Sopenharmony_ci	if (buf[1] & FSF_STATUS_TPU_OPN)
623141cc406Sopenharmony_ci		DBG(1, " cover open\n");
624141cc406Sopenharmony_ci
625141cc406Sopenharmony_ci
626141cc406Sopenharmony_ci	DBG(1, "device type     : 0x%02x\n", buf[3] & 0xC0);
627141cc406Sopenharmony_ci	DBG(1, "main body status: 0x%02x\n", buf[3] & 0x3F);
628141cc406Sopenharmony_ci
629141cc406Sopenharmony_ci	if (buf[3] & FSF_STATUS_MAIN2_PE)
630141cc406Sopenharmony_ci		DBG(1, " paper empty\n");
631141cc406Sopenharmony_ci
632141cc406Sopenharmony_ci	if (buf[3] & FSF_STATUS_MAIN2_PJ)
633141cc406Sopenharmony_ci		DBG(1, " paper jam\n");
634141cc406Sopenharmony_ci
635141cc406Sopenharmony_ci	if (buf[3] & FSF_STATUS_MAIN2_OPN)
636141cc406Sopenharmony_ci		DBG(1, " cover open\n");
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
639141cc406Sopenharmony_ci}
640141cc406Sopenharmony_ci
641141cc406Sopenharmony_ciSANE_Status
642141cc406Sopenharmony_ciesci_set_scanning_parameter(SANE_Handle handle, unsigned char *buf)
643141cc406Sopenharmony_ci{
644141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
645141cc406Sopenharmony_ci	SANE_Status status;
646141cc406Sopenharmony_ci	unsigned char params[2];
647141cc406Sopenharmony_ci
648141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
649141cc406Sopenharmony_ci
650141cc406Sopenharmony_ci	if (buf == NULL)
651141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
652141cc406Sopenharmony_ci
653141cc406Sopenharmony_ci	params[0] = FS;
654141cc406Sopenharmony_ci	params[1] = 'W';
655141cc406Sopenharmony_ci
656141cc406Sopenharmony_ci	DBG(10, "resolution of main scan     : %lu\n", (unsigned long) le32atoh(&buf[0]));
657141cc406Sopenharmony_ci	DBG(10, "resolution of sub scan      : %lu\n", (unsigned long) le32atoh(&buf[4]));
658141cc406Sopenharmony_ci	DBG(10, "offset length of main scan  : %lu\n", (unsigned long) le32atoh(&buf[8]));
659141cc406Sopenharmony_ci	DBG(10, "offset length of sub scan   : %lu\n", (unsigned long) le32atoh(&buf[12]));
660141cc406Sopenharmony_ci	DBG(10, "scanning length of main scan: %lu\n", (unsigned long) le32atoh(&buf[16]));
661141cc406Sopenharmony_ci	DBG(10, "scanning length of sub scan : %lu\n", (unsigned long) le32atoh(&buf[20]));
662141cc406Sopenharmony_ci	DBG(10, "scanning color              : %d\n", buf[24]);
663141cc406Sopenharmony_ci	DBG(10, "data format                 : %d\n", buf[25]);
664141cc406Sopenharmony_ci	DBG(10, "option control              : %d\n", buf[26]);
665141cc406Sopenharmony_ci	DBG(10, "scanning mode               : %d\n", buf[27]);
666141cc406Sopenharmony_ci	DBG(10, "block line number           : %d\n", buf[28]);
667141cc406Sopenharmony_ci	DBG(10, "gamma correction            : %d\n", buf[29]);
668141cc406Sopenharmony_ci	DBG(10, "brightness                  : %d\n", buf[30]);
669141cc406Sopenharmony_ci	DBG(10, "color correction            : %d\n", buf[31]);
670141cc406Sopenharmony_ci	DBG(10, "halftone processing         : %d\n", buf[32]);
671141cc406Sopenharmony_ci	DBG(10, "threshold                   : %d\n", buf[33]);
672141cc406Sopenharmony_ci	DBG(10, "auto area segmentation      : %d\n", buf[34]);
673141cc406Sopenharmony_ci	DBG(10, "sharpness control           : %d\n", buf[35]);
674141cc406Sopenharmony_ci	DBG(10, "mirroring                   : %d\n", buf[36]);
675141cc406Sopenharmony_ci	DBG(10, "film type                   : %d\n", buf[37]);
676141cc406Sopenharmony_ci	DBG(10, "main lamp lighting mode     : %d\n", buf[38]);
677141cc406Sopenharmony_ci
678141cc406Sopenharmony_ci	status = e2_cmd_simple(s, params, 2);
679141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
680141cc406Sopenharmony_ci		return status;
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci	status = e2_cmd_simple(s, buf, 64);
683141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
684141cc406Sopenharmony_ci		DBG(1, "%s: invalid scanning parameters\n", __func__);
685141cc406Sopenharmony_ci		return status;
686141cc406Sopenharmony_ci	}
687141cc406Sopenharmony_ci
688141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
689141cc406Sopenharmony_ci}
690141cc406Sopenharmony_ci
691141cc406Sopenharmony_ci/* FS S */
692141cc406Sopenharmony_ci
693141cc406Sopenharmony_ciSANE_Status
694141cc406Sopenharmony_ciesci_get_scanning_parameter(SANE_Handle handle, unsigned char *buf)
695141cc406Sopenharmony_ci{
696141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
697141cc406Sopenharmony_ci	SANE_Status status;
698141cc406Sopenharmony_ci	unsigned char params[2];
699141cc406Sopenharmony_ci
700141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
701141cc406Sopenharmony_ci
702141cc406Sopenharmony_ci	if (buf == NULL)
703141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
704141cc406Sopenharmony_ci
705141cc406Sopenharmony_ci	params[0] = FS;
706141cc406Sopenharmony_ci	params[1] = 'S';
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci	status = e2_txrx(s, params, 2, buf, 64);
709141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
710141cc406Sopenharmony_ci		return status;
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci	DBG(10, "resolution of main scan     : %lu\n",
713141cc406Sopenharmony_ci	    (u_long) le32atoh(&buf[0]));
714141cc406Sopenharmony_ci	DBG(10, "resolution of sub scan      : %lu\n",
715141cc406Sopenharmony_ci	    (u_long) le32atoh(&buf[4]));
716141cc406Sopenharmony_ci	DBG(10, "offset length of main scan  : %lu\n",
717141cc406Sopenharmony_ci	    (u_long) le32atoh(&buf[8]));
718141cc406Sopenharmony_ci	DBG(10, "offset length of sub scan   : %lu\n",
719141cc406Sopenharmony_ci	    (u_long) le32atoh(&buf[12]));
720141cc406Sopenharmony_ci	DBG(10, "scanning length of main scan: %lu\n",
721141cc406Sopenharmony_ci	    (u_long) le32atoh(&buf[16]));
722141cc406Sopenharmony_ci	DBG(10, "scanning length of sub scan : %lu\n",
723141cc406Sopenharmony_ci	    (u_long) le32atoh(&buf[20]));
724141cc406Sopenharmony_ci	DBG(10, "scanning color              : %d\n", buf[24]);
725141cc406Sopenharmony_ci	DBG(10, "data format                 : %d\n", buf[25]);
726141cc406Sopenharmony_ci	DBG(10, "option control              : %d\n", buf[26]);
727141cc406Sopenharmony_ci	DBG(10, "scanning mode               : %d\n", buf[27]);
728141cc406Sopenharmony_ci	DBG(10, "block line number           : %d\n", buf[28]);
729141cc406Sopenharmony_ci	DBG(10, "gamma correction            : %d\n", buf[29]);
730141cc406Sopenharmony_ci	DBG(10, "brightness                  : %d\n", buf[30]);
731141cc406Sopenharmony_ci	DBG(10, "color correction            : %d\n", buf[31]);
732141cc406Sopenharmony_ci	DBG(10, "halftone processing         : %d\n", buf[32]);
733141cc406Sopenharmony_ci	DBG(10, "threshold                   : %d\n", buf[33]);
734141cc406Sopenharmony_ci	DBG(10, "auto area segmentation      : %d\n", buf[34]);
735141cc406Sopenharmony_ci	DBG(10, "sharpness control           : %d\n", buf[35]);
736141cc406Sopenharmony_ci	DBG(10, "mirroring                   : %d\n", buf[36]);
737141cc406Sopenharmony_ci	DBG(10, "film type                   : %d\n", buf[37]);
738141cc406Sopenharmony_ci	DBG(10, "main lamp lighting mode     : %d\n", buf[38]);
739141cc406Sopenharmony_ci
740141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
741141cc406Sopenharmony_ci}
742141cc406Sopenharmony_ci
743141cc406Sopenharmony_ci/* ESC # */
744141cc406Sopenharmony_ci
745141cc406Sopenharmony_ciSANE_Status
746141cc406Sopenharmony_ciesci_enable_infrared(SANE_Handle handle)
747141cc406Sopenharmony_ci{
748141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
749141cc406Sopenharmony_ci	SANE_Status status;
750141cc406Sopenharmony_ci	int i;
751141cc406Sopenharmony_ci	unsigned char params[2];
752141cc406Sopenharmony_ci	unsigned char buf[64];
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci	unsigned char seq[32] = {
755141cc406Sopenharmony_ci		0xCA, 0xFB, 0x77, 0x71, 0x20, 0x16, 0xDA, 0x09,
756141cc406Sopenharmony_ci		0x5F, 0x57, 0x09, 0x12, 0x04, 0x83, 0x76, 0x77,
757141cc406Sopenharmony_ci		0x3C, 0x73, 0x9C, 0xBE, 0x7A, 0xE0, 0x52, 0xE2,
758141cc406Sopenharmony_ci		0x90, 0x0D, 0xFF, 0x9A, 0xEF, 0x4C, 0x2C, 0x81
759141cc406Sopenharmony_ci	};
760141cc406Sopenharmony_ci
761141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
762141cc406Sopenharmony_ci
763141cc406Sopenharmony_ci	status = esci_get_scanning_parameter(handle, buf);
764141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
765141cc406Sopenharmony_ci		return status;
766141cc406Sopenharmony_ci
767141cc406Sopenharmony_ci	for (i = 0; i < 32; i++) {
768141cc406Sopenharmony_ci		buf[i] = seq[i] ^ buf[i];
769141cc406Sopenharmony_ci	}
770141cc406Sopenharmony_ci
771141cc406Sopenharmony_ci	params[0] = ESC;
772141cc406Sopenharmony_ci	params[1] = '#';
773141cc406Sopenharmony_ci
774141cc406Sopenharmony_ci	status = e2_cmd_simple(s, params, 2);
775141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
776141cc406Sopenharmony_ci		return status;
777141cc406Sopenharmony_ci
778141cc406Sopenharmony_ci	status = e2_cmd_simple(s, buf, 32);
779141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
780141cc406Sopenharmony_ci		return status;
781141cc406Sopenharmony_ci
782141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
783141cc406Sopenharmony_ci}
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_ciSANE_Status
786141cc406Sopenharmony_ciesci_request_command_parameter(SANE_Handle handle, unsigned char *buf)
787141cc406Sopenharmony_ci{
788141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
789141cc406Sopenharmony_ci	SANE_Status status;
790141cc406Sopenharmony_ci	unsigned char params[2];
791141cc406Sopenharmony_ci
792141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
793141cc406Sopenharmony_ci
794141cc406Sopenharmony_ci	if (s->hw->cmd->request_condition == 0)
795141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
796141cc406Sopenharmony_ci
797141cc406Sopenharmony_ci	params[0] = ESC;
798141cc406Sopenharmony_ci	params[1] = s->hw->cmd->request_condition;
799141cc406Sopenharmony_ci
800141cc406Sopenharmony_ci	status = e2_cmd_info_block(s, params, 2, 45, &buf, NULL);
801141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
802141cc406Sopenharmony_ci		return status;
803141cc406Sopenharmony_ci
804141cc406Sopenharmony_ci	DBG(1, "scanning parameters:\n");
805141cc406Sopenharmony_ci	DBG(1, "color                  : %d\n", buf[1]);
806141cc406Sopenharmony_ci	DBG(1, "resolution             : %dx%d\n",
807141cc406Sopenharmony_ci	    buf[4] << 8 | buf[3], buf[6] << 8 | buf[5]);
808141cc406Sopenharmony_ci	DBG(1, "halftone               : %d\n", buf[19]);
809141cc406Sopenharmony_ci	DBG(1, "brightness             : %d\n", buf[21]);
810141cc406Sopenharmony_ci	DBG(1, "color correction       : %d\n", buf[28]);
811141cc406Sopenharmony_ci	DBG(1, "gamma                  : %d\n", buf[23]);
812141cc406Sopenharmony_ci	DBG(1, "sharpness              : %d\n", buf[30]);
813141cc406Sopenharmony_ci	DBG(1, "threshold              : %d\n", buf[38]);
814141cc406Sopenharmony_ci	DBG(1, "data format            : %d\n", buf[17]);
815141cc406Sopenharmony_ci	DBG(1, "mirroring              : %d\n", buf[34]);
816141cc406Sopenharmony_ci	DBG(1, "option unit control    : %d\n", buf[42]);
817141cc406Sopenharmony_ci	DBG(1, "film type              : %d\n", buf[44]);
818141cc406Sopenharmony_ci	DBG(1, "auto area segmentation : %d\n", buf[36]);
819141cc406Sopenharmony_ci	DBG(1, "line counter           : %d\n", buf[40]);
820141cc406Sopenharmony_ci	DBG(1, "scanning mode          : %d\n", buf[32]);
821141cc406Sopenharmony_ci	DBG(1, "zoom                   : %d,%d\n", buf[26], buf[25]);
822141cc406Sopenharmony_ci	DBG(1, "scan area              : %d,%d %d,%d\n",
823141cc406Sopenharmony_ci	    buf[9] << 8 | buf[8], buf[11] << 8 | buf[10],
824141cc406Sopenharmony_ci	    buf[13] << 8 | buf[12], buf[15] << 8 | buf[14]);
825141cc406Sopenharmony_ci	return status;
826141cc406Sopenharmony_ci}
827141cc406Sopenharmony_ci
828141cc406Sopenharmony_ci/* ESC q - Request Focus Position
829141cc406Sopenharmony_ci * -> ESC q
830141cc406Sopenharmony_ci * <- Information block
831141cc406Sopenharmony_ci * <- Focus position status (2)
832141cc406Sopenharmony_ci *	0 - Error status
833141cc406Sopenharmony_ci *	1 - Focus position
834141cc406Sopenharmony_ci */
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ciSANE_Status
837141cc406Sopenharmony_ciesci_request_focus_position(SANE_Handle handle, unsigned char *position)
838141cc406Sopenharmony_ci{
839141cc406Sopenharmony_ci	SANE_Status status;
840141cc406Sopenharmony_ci	unsigned char *buf;
841141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci	unsigned char params[2];
844141cc406Sopenharmony_ci
845141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
846141cc406Sopenharmony_ci
847141cc406Sopenharmony_ci	if (s->hw->cmd->request_focus_position == 0)
848141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_ci	params[0] = ESC;
851141cc406Sopenharmony_ci	params[1] = s->hw->cmd->request_focus_position;
852141cc406Sopenharmony_ci
853141cc406Sopenharmony_ci	status = e2_cmd_info_block(s, params, 2, 2, &buf, NULL);
854141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
855141cc406Sopenharmony_ci		return status;
856141cc406Sopenharmony_ci
857141cc406Sopenharmony_ci	if (buf[0] & 0x01)
858141cc406Sopenharmony_ci		DBG(1, "autofocus error\n");
859141cc406Sopenharmony_ci
860141cc406Sopenharmony_ci	*position = buf[1];
861141cc406Sopenharmony_ci	DBG(8, " focus position = 0x%x\n", buf[1]);
862141cc406Sopenharmony_ci
863141cc406Sopenharmony_ci	free(buf);
864141cc406Sopenharmony_ci
865141cc406Sopenharmony_ci	return status;
866141cc406Sopenharmony_ci}
867141cc406Sopenharmony_ci
868141cc406Sopenharmony_ci/* ESC ! - Request Push Button Status
869141cc406Sopenharmony_ci * -> ESC !
870141cc406Sopenharmony_ci * <- Information block
871141cc406Sopenharmony_ci * <- Push button status (1)
872141cc406Sopenharmony_ci */
873141cc406Sopenharmony_ci
874141cc406Sopenharmony_ciSANE_Status
875141cc406Sopenharmony_ciesci_request_push_button_status(SANE_Handle handle, unsigned char *bstatus)
876141cc406Sopenharmony_ci{
877141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
878141cc406Sopenharmony_ci	SANE_Status status;
879141cc406Sopenharmony_ci	unsigned char params[2];
880141cc406Sopenharmony_ci	unsigned char *buf;
881141cc406Sopenharmony_ci
882141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
883141cc406Sopenharmony_ci
884141cc406Sopenharmony_ci	if (s->hw->cmd->request_push_button_status == 0) {
885141cc406Sopenharmony_ci		DBG(1, "push button status unsupported\n");
886141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
887141cc406Sopenharmony_ci	}
888141cc406Sopenharmony_ci
889141cc406Sopenharmony_ci	params[0] = ESC;
890141cc406Sopenharmony_ci	params[1] = s->hw->cmd->request_push_button_status;
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci	status = e2_cmd_info_block(s, params, 2, 1, &buf, NULL);
893141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
894141cc406Sopenharmony_ci		return status;
895141cc406Sopenharmony_ci
896141cc406Sopenharmony_ci	DBG(1, "push button status = %d\n", buf[0]);
897141cc406Sopenharmony_ci	*bstatus = buf[0];
898141cc406Sopenharmony_ci
899141cc406Sopenharmony_ci	free(buf);
900141cc406Sopenharmony_ci
901141cc406Sopenharmony_ci	return status;
902141cc406Sopenharmony_ci}
903141cc406Sopenharmony_ci
904141cc406Sopenharmony_ci
905141cc406Sopenharmony_ci/*
906141cc406Sopenharmony_ci * Request Identity information from scanner and fill in information
907141cc406Sopenharmony_ci * into dev and/or scanner structures.
908141cc406Sopenharmony_ci * XXX information should be parsed separately.
909141cc406Sopenharmony_ci */
910141cc406Sopenharmony_ciSANE_Status
911141cc406Sopenharmony_ciesci_request_identity(SANE_Handle handle, unsigned char **buf, size_t *len)
912141cc406Sopenharmony_ci{
913141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
914141cc406Sopenharmony_ci	unsigned char params[2];
915141cc406Sopenharmony_ci
916141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
917141cc406Sopenharmony_ci
918141cc406Sopenharmony_ci	if (!s->hw->cmd->request_identity)
919141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
920141cc406Sopenharmony_ci
921141cc406Sopenharmony_ci	params[0] = ESC;
922141cc406Sopenharmony_ci	params[1] = s->hw->cmd->request_identity;
923141cc406Sopenharmony_ci
924141cc406Sopenharmony_ci	return e2_cmd_info_block(s, params, 2, 0, buf, len);
925141cc406Sopenharmony_ci}
926141cc406Sopenharmony_ci
927141cc406Sopenharmony_ci
928141cc406Sopenharmony_ci/*
929141cc406Sopenharmony_ci * Request information from scanner
930141cc406Sopenharmony_ci */
931141cc406Sopenharmony_ciSANE_Status
932141cc406Sopenharmony_ciesci_request_identity2(SANE_Handle handle, unsigned char **buf)
933141cc406Sopenharmony_ci{
934141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
935141cc406Sopenharmony_ci	SANE_Status status;
936141cc406Sopenharmony_ci	size_t len;
937141cc406Sopenharmony_ci	unsigned char params[2];
938141cc406Sopenharmony_ci
939141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
940141cc406Sopenharmony_ci
941141cc406Sopenharmony_ci	if (s->hw->cmd->request_identity2 == 0)
942141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
943141cc406Sopenharmony_ci
944141cc406Sopenharmony_ci	params[0] = ESC;
945141cc406Sopenharmony_ci	params[1] = s->hw->cmd->request_identity2;
946141cc406Sopenharmony_ci
947141cc406Sopenharmony_ci	status = e2_cmd_info_block(s, params, 2, 0, buf, &len);
948141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
949141cc406Sopenharmony_ci		return status;
950141cc406Sopenharmony_ci
951141cc406Sopenharmony_ci	return status;
952141cc406Sopenharmony_ci}
953141cc406Sopenharmony_ci
954141cc406Sopenharmony_ci/* Send the "initialize scanner" command to the device and reset it */
955141cc406Sopenharmony_ci
956141cc406Sopenharmony_ciSANE_Status
957141cc406Sopenharmony_ciesci_reset(Epson_Scanner * s)
958141cc406Sopenharmony_ci{
959141cc406Sopenharmony_ci	SANE_Status status;
960141cc406Sopenharmony_ci	unsigned char params[2];
961141cc406Sopenharmony_ci
962141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
963141cc406Sopenharmony_ci
964141cc406Sopenharmony_ci	if (!s->hw->cmd->initialize_scanner)
965141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
966141cc406Sopenharmony_ci
967141cc406Sopenharmony_ci	params[0] = ESC;
968141cc406Sopenharmony_ci	params[1] = s->hw->cmd->initialize_scanner;
969141cc406Sopenharmony_ci
970141cc406Sopenharmony_ci	if (s->fd == -1)
971141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
972141cc406Sopenharmony_ci
973141cc406Sopenharmony_ci	status = e2_cmd_simple(s, params, 2);
974141cc406Sopenharmony_ci
975141cc406Sopenharmony_ci	return status;
976141cc406Sopenharmony_ci}
977141cc406Sopenharmony_ci
978141cc406Sopenharmony_ciSANE_Status
979141cc406Sopenharmony_ciesci_feed(Epson_Scanner * s)
980141cc406Sopenharmony_ci{
981141cc406Sopenharmony_ci	unsigned char params[1];
982141cc406Sopenharmony_ci
983141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci	if (!s->hw->cmd->feed)
986141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
987141cc406Sopenharmony_ci
988141cc406Sopenharmony_ci	params[0] = s->hw->cmd->feed;
989141cc406Sopenharmony_ci
990141cc406Sopenharmony_ci	return e2_cmd_simple(s, params, 1);
991141cc406Sopenharmony_ci}
992141cc406Sopenharmony_ci
993141cc406Sopenharmony_ci
994141cc406Sopenharmony_ci/*
995141cc406Sopenharmony_ci * Eject the current page from the ADF. The scanner is opened prior to
996141cc406Sopenharmony_ci * sending the command and closed afterwards.
997141cc406Sopenharmony_ci */
998141cc406Sopenharmony_ci
999141cc406Sopenharmony_ciSANE_Status
1000141cc406Sopenharmony_ciesci_eject(Epson_Scanner * s)
1001141cc406Sopenharmony_ci{
1002141cc406Sopenharmony_ci	unsigned char params[1];
1003141cc406Sopenharmony_ci
1004141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
1005141cc406Sopenharmony_ci
1006141cc406Sopenharmony_ci	if (!s->hw->cmd->eject)
1007141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
1008141cc406Sopenharmony_ci
1009141cc406Sopenharmony_ci	if (s->fd == -1)
1010141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
1011141cc406Sopenharmony_ci
1012141cc406Sopenharmony_ci	params[0] = s->hw->cmd->eject;
1013141cc406Sopenharmony_ci
1014141cc406Sopenharmony_ci	return e2_cmd_simple(s, params, 1);
1015141cc406Sopenharmony_ci}
1016141cc406Sopenharmony_ci
1017141cc406Sopenharmony_ciSANE_Status
1018141cc406Sopenharmony_ciesci_request_extended_status(SANE_Handle handle, unsigned char **data,
1019141cc406Sopenharmony_ci			size_t * data_len)
1020141cc406Sopenharmony_ci{
1021141cc406Sopenharmony_ci	Epson_Scanner *s = (Epson_Scanner *) handle;
1022141cc406Sopenharmony_ci	SANE_Status status = SANE_STATUS_GOOD;
1023141cc406Sopenharmony_ci	unsigned char params[2];
1024141cc406Sopenharmony_ci	unsigned char *buf;
1025141cc406Sopenharmony_ci	size_t buf_len;
1026141cc406Sopenharmony_ci
1027141cc406Sopenharmony_ci	DBG(8, "%s\n", __func__);
1028141cc406Sopenharmony_ci
1029141cc406Sopenharmony_ci	if (s->hw->cmd->request_extended_status == 0)
1030141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
1031141cc406Sopenharmony_ci
1032141cc406Sopenharmony_ci	params[0] = ESC;
1033141cc406Sopenharmony_ci	params[1] = s->hw->cmd->request_extended_status;
1034141cc406Sopenharmony_ci
1035141cc406Sopenharmony_ci	/* This command returns 33 bytes of data on old scanners
1036141cc406Sopenharmony_ci	 * and 42 (CMD_SIZE_EXT_STATUS) on new ones.
1037141cc406Sopenharmony_ci	 */
1038141cc406Sopenharmony_ci	status = e2_cmd_info_block(s, params, 2, CMD_SIZE_EXT_STATUS,
1039141cc406Sopenharmony_ci				       &buf, &buf_len);
1040141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD)
1041141cc406Sopenharmony_ci		return status;
1042141cc406Sopenharmony_ci
1043141cc406Sopenharmony_ci	switch (buf_len) {
1044141cc406Sopenharmony_ci	case 33:
1045141cc406Sopenharmony_ci	case 42:
1046141cc406Sopenharmony_ci		break;
1047141cc406Sopenharmony_ci	default:
1048141cc406Sopenharmony_ci		DBG(1, "%s: unknown reply length (%lu)\n", __func__,
1049141cc406Sopenharmony_ci			(unsigned long) buf_len);
1050141cc406Sopenharmony_ci		break;
1051141cc406Sopenharmony_ci	}
1052141cc406Sopenharmony_ci
1053141cc406Sopenharmony_ci	DBG(4, "main = %02x, ADF = %02x, TPU = %02x, main 2 = %02x\n",
1054141cc406Sopenharmony_ci		buf[0], buf[1], buf[6], buf[11]);
1055141cc406Sopenharmony_ci
1056141cc406Sopenharmony_ci	if (buf[0] & EXT_STATUS_FER)
1057141cc406Sopenharmony_ci		DBG(1, "system error\n");
1058141cc406Sopenharmony_ci
1059141cc406Sopenharmony_ci	if (buf[0] & EXT_STATUS_WU)
1060141cc406Sopenharmony_ci		DBG(1, "scanner is warming up\n");
1061141cc406Sopenharmony_ci
1062141cc406Sopenharmony_ci	if (buf[1] & EXT_STATUS_ERR)
1063141cc406Sopenharmony_ci		DBG(1, "ADF: other error\n");
1064141cc406Sopenharmony_ci
1065141cc406Sopenharmony_ci	if (buf[1] & EXT_STATUS_PE)
1066141cc406Sopenharmony_ci		DBG(1, "ADF: no paper\n");
1067141cc406Sopenharmony_ci
1068141cc406Sopenharmony_ci	if (buf[1] & EXT_STATUS_PJ)
1069141cc406Sopenharmony_ci		DBG(1, "ADF: paper jam\n");
1070141cc406Sopenharmony_ci
1071141cc406Sopenharmony_ci	if (buf[1] & EXT_STATUS_OPN)
1072141cc406Sopenharmony_ci		DBG(1, "ADF: cover open\n");
1073141cc406Sopenharmony_ci
1074141cc406Sopenharmony_ci	if (buf[6] & EXT_STATUS_ERR)
1075141cc406Sopenharmony_ci		DBG(1, "TPU: other error\n");
1076141cc406Sopenharmony_ci
1077141cc406Sopenharmony_ci	/* give back a pointer to the payload
1078141cc406Sopenharmony_ci	 * if the user requested it, otherwise
1079141cc406Sopenharmony_ci	 * free it.
1080141cc406Sopenharmony_ci	 */
1081141cc406Sopenharmony_ci
1082141cc406Sopenharmony_ci	if (data)
1083141cc406Sopenharmony_ci		*data = buf;
1084141cc406Sopenharmony_ci	else
1085141cc406Sopenharmony_ci		free(buf);
1086141cc406Sopenharmony_ci
1087141cc406Sopenharmony_ci	if (data_len)
1088141cc406Sopenharmony_ci		*data_len = buf_len;
1089141cc406Sopenharmony_ci
1090141cc406Sopenharmony_ci	return status;
1091141cc406Sopenharmony_ci}
1092