1141cc406Sopenharmony_ci/*
2141cc406Sopenharmony_ci * epsonds-cmd.c - Epson ESC/I-2 routines.
3141cc406Sopenharmony_ci *
4141cc406Sopenharmony_ci * Copyright (C) 2015 Tower Technologies
5141cc406Sopenharmony_ci * Author: Alessandro Zummo <a.zummo@towertech.it>
6141cc406Sopenharmony_ci *
7141cc406Sopenharmony_ci * This file is part of the SANE package.
8141cc406Sopenharmony_ci *
9141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or
10141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as
11141cc406Sopenharmony_ci * published by the Free Software Foundation, version 2.
12141cc406Sopenharmony_ci */
13141cc406Sopenharmony_ci
14141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY
15141cc406Sopenharmony_ci
16141cc406Sopenharmony_ci#include "sane/config.h"
17141cc406Sopenharmony_ci#include <ctype.h>
18141cc406Sopenharmony_ci#include <unistd.h>	     /* sleep */
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci#include "epsonds.h"
21141cc406Sopenharmony_ci#include "epsonds-io.h"
22141cc406Sopenharmony_ci#include "epsonds-cmd.h"
23141cc406Sopenharmony_ci#include "epsonds-ops.h"
24141cc406Sopenharmony_ci#include "epsonds-net.h"
25141cc406Sopenharmony_ci
26141cc406Sopenharmony_cistatic SANE_Status
27141cc406Sopenharmony_ciesci2_parse_block(char *buf, int len, void *userdata, SANE_Status (*cb)(void *userdata, char *token, int len))
28141cc406Sopenharmony_ci{
29141cc406Sopenharmony_ci	SANE_Status status = SANE_STATUS_GOOD;
30141cc406Sopenharmony_ci	SANE_Status delayed_status = SANE_STATUS_GOOD;
31141cc406Sopenharmony_ci
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci	char *start = buf;
34141cc406Sopenharmony_ci	char *end = (buf + len) - 1;
35141cc406Sopenharmony_ci
36141cc406Sopenharmony_ci	/* 0  : #
37141cc406Sopenharmony_ci	 * 1-3: param
38141cc406Sopenharmony_ci	 * 4- : data
39141cc406Sopenharmony_ci	*/
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci	while (1) {
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci		char param[4];
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci		while (*start != '#' && start < end)
46141cc406Sopenharmony_ci			start++;
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci		if (*start != '#')
49141cc406Sopenharmony_ci			break;
50141cc406Sopenharmony_ci
51141cc406Sopenharmony_ci		param[0] = *++start;
52141cc406Sopenharmony_ci		param[1] = *++start;
53141cc406Sopenharmony_ci		param[2] = *++start;
54141cc406Sopenharmony_ci		param[3] = '\0';
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci		if (strncmp("---", param, 3) == 0)
57141cc406Sopenharmony_ci			break;
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_ci		/* ugly hack to skip over GMT in RESA */
60141cc406Sopenharmony_ci		if (strncmp("GMT", param, 3) == 0 && *(start + 5) == 'h') {
61141cc406Sopenharmony_ci			start = start + 4 + 0x100;
62141cc406Sopenharmony_ci			continue;
63141cc406Sopenharmony_ci		}
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci		/* find the end of the token */
66141cc406Sopenharmony_ci		{
67141cc406Sopenharmony_ci			int tlen;
68141cc406Sopenharmony_ci			char *next = start;
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_ci			while (*next != '#' && *next != 0x00 && next < end)
71141cc406Sopenharmony_ci				next++;
72141cc406Sopenharmony_ci
73141cc406Sopenharmony_ci			tlen = next - start - 1;
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci			if (cb) {
76141cc406Sopenharmony_ci				status = cb(userdata, start - 2, tlen);
77141cc406Sopenharmony_ci				if (status != SANE_STATUS_GOOD) {
78141cc406Sopenharmony_ci					delayed_status = status;
79141cc406Sopenharmony_ci				}
80141cc406Sopenharmony_ci			}
81141cc406Sopenharmony_ci
82141cc406Sopenharmony_ci			start = next;
83141cc406Sopenharmony_ci		}
84141cc406Sopenharmony_ci	}
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci	if (delayed_status != SANE_STATUS_GOOD)
87141cc406Sopenharmony_ci		return delayed_status;
88141cc406Sopenharmony_ci
89141cc406Sopenharmony_ci	return status;
90141cc406Sopenharmony_ci}
91141cc406Sopenharmony_ci
92141cc406Sopenharmony_cistatic SANE_Bool
93141cc406Sopenharmony_ciesci2_check_header(const char *cmd, const char *buf, unsigned int *more)
94141cc406Sopenharmony_ci{
95141cc406Sopenharmony_ci	int err;
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci	*more = 0;
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci	if (strncmp(cmd, buf, 4) != 0) {
100141cc406Sopenharmony_ci
101141cc406Sopenharmony_ci		if (strncmp("UNKN", buf, 4) == 0) {
102141cc406Sopenharmony_ci			DBG(1, "UNKN reply code received\n");
103141cc406Sopenharmony_ci		} else if (strncmp("INVD", buf, 4) == 0) {
104141cc406Sopenharmony_ci			DBG(1, "INVD reply code received\n");
105141cc406Sopenharmony_ci		} else {
106141cc406Sopenharmony_ci			DBG(1, "%c%c%c%c, unexpected reply code\n", buf[0], buf[1], buf[2], buf[3]);
107141cc406Sopenharmony_ci		}
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci		return 0;
110141cc406Sopenharmony_ci	}
111141cc406Sopenharmony_ci
112141cc406Sopenharmony_ci	/* INFOx0000100#.... */
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci	/* read the answer len */
115141cc406Sopenharmony_ci	if (buf[4] != 'x') {
116141cc406Sopenharmony_ci		DBG(1, "unknown type in header: %c\n", buf[4]);
117141cc406Sopenharmony_ci		return 0;
118141cc406Sopenharmony_ci	}
119141cc406Sopenharmony_ci
120141cc406Sopenharmony_ci	err = sscanf(&buf[5], "%7x#", more);
121141cc406Sopenharmony_ci	if (err != 1) {
122141cc406Sopenharmony_ci		DBG(1, "cannot decode length from header\n");
123141cc406Sopenharmony_ci		return 0;
124141cc406Sopenharmony_ci	}
125141cc406Sopenharmony_ci
126141cc406Sopenharmony_ci	return 1;
127141cc406Sopenharmony_ci}
128141cc406Sopenharmony_ci
129141cc406Sopenharmony_cistatic SANE_Status esci2_cmd(epsonds_scanner* s,
130141cc406Sopenharmony_ci	char *cmd, size_t len,
131141cc406Sopenharmony_ci	char *payload, size_t plen,
132141cc406Sopenharmony_ci	void *userdata, SANE_Status (*cb)(void *userdata, char *token, int len))
133141cc406Sopenharmony_ci{
134141cc406Sopenharmony_ci	SANE_Status status;
135141cc406Sopenharmony_ci	unsigned int more;
136141cc406Sopenharmony_ci	char header[13], rbuf[64]; /* add one more byte for header buffer to correct buffer overflow issue,*/
137141cc406Sopenharmony_ci	char *buf;
138141cc406Sopenharmony_ci
139141cc406Sopenharmony_ci	DBG(8, "%s: %4s len %lu, payload len: %lu\n", __func__, cmd, len, plen);
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_ci	memset(header, 0x00, sizeof(header));
142141cc406Sopenharmony_ci	memset(rbuf, 0x00, sizeof(rbuf));
143141cc406Sopenharmony_ci
144141cc406Sopenharmony_ci	// extra safety check, will not happen
145141cc406Sopenharmony_ci	if (len != 12) {
146141cc406Sopenharmony_ci		DBG(1, "%s: command has wrong size (%lu != 12)\n", __func__, len);
147141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
148141cc406Sopenharmony_ci	}
149141cc406Sopenharmony_ci
150141cc406Sopenharmony_ci	// merge ParameterBlock size
151141cc406Sopenharmony_ci	sprintf(header, "%4.4sx%07x", cmd, (unsigned int)plen);
152141cc406Sopenharmony_ci
153141cc406Sopenharmony_ci	// send RequestBlock, request immediate response if there's no payload
154141cc406Sopenharmony_ci	status = eds_txrx(s, header, len, rbuf, (plen > 0) ? 0 : 64);
155141cc406Sopenharmony_ci
156141cc406Sopenharmony_ci	/* pointer to the token's value */
157141cc406Sopenharmony_ci	buf = rbuf + 12;
158141cc406Sopenharmony_ci	/* nrd / nrdBUSY */
159141cc406Sopenharmony_ci	DBG(8, "buf = %s\n",buf);
160141cc406Sopenharmony_ci	if (strncmp("#nrd", buf, 4) == 0) {
161141cc406Sopenharmony_ci		buf += 4;
162141cc406Sopenharmony_ci			DBG(8, "buf = %s\n",buf);
163141cc406Sopenharmony_ci		if (strncmp("BUSY", buf, 4) == 0) {
164141cc406Sopenharmony_ci			DBG(8, "device busy\n");
165141cc406Sopenharmony_ci			DBG(8, "SANE_STATUS:%d\n", SANE_STATUS_DEVICE_BUSY);
166141cc406Sopenharmony_ci			return SANE_STATUS_DEVICE_BUSY;
167141cc406Sopenharmony_ci		}
168141cc406Sopenharmony_ci	}
169141cc406Sopenharmony_ci
170141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
171141cc406Sopenharmony_ci		return status;
172141cc406Sopenharmony_ci	}
173141cc406Sopenharmony_ci
174141cc406Sopenharmony_ci	/* send ParameterBlock, request response */
175141cc406Sopenharmony_ci	if (plen) {
176141cc406Sopenharmony_ci
177141cc406Sopenharmony_ci		DBG(8, " %12.12s (%lu)\n", header, plen);
178141cc406Sopenharmony_ci
179141cc406Sopenharmony_ci		status = eds_txrx(s, payload, plen, rbuf, 64);
180141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD) {
181141cc406Sopenharmony_ci			return status;
182141cc406Sopenharmony_ci		}
183141cc406Sopenharmony_ci	}
184141cc406Sopenharmony_ci
185141cc406Sopenharmony_ci	/* rxbuf holds the DataHeaderBlock, which should be
186141cc406Sopenharmony_ci	 * parsed to know if we need to read more data
187141cc406Sopenharmony_ci	 */
188141cc406Sopenharmony_ci	if (!esci2_check_header(cmd, rbuf, &more)) {
189141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
190141cc406Sopenharmony_ci	}
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_ci	/* parse the received header block */
193141cc406Sopenharmony_ci	if (cb) {
194141cc406Sopenharmony_ci		status = esci2_parse_block(rbuf + 12, 64 - 12, userdata, cb);
195141cc406Sopenharmony_ci		if (status != SANE_STATUS_GOOD && status != SANE_STATUS_DEVICE_BUSY) {
196141cc406Sopenharmony_ci			DBG(1, "%s: %4s error while parsing received header\n", __func__, cmd);
197141cc406Sopenharmony_ci		}
198141cc406Sopenharmony_ci	}
199141cc406Sopenharmony_ci
200141cc406Sopenharmony_ci	/* header valid, get the data block if present */
201141cc406Sopenharmony_ci	if (more) {
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_ci		char *pbuf = malloc(more);
204141cc406Sopenharmony_ci		if (pbuf) {
205141cc406Sopenharmony_ci
206141cc406Sopenharmony_ci			if (s->hw->connection == SANE_EPSONDS_NET) {
207141cc406Sopenharmony_ci				epsonds_net_request_read(s, more);
208141cc406Sopenharmony_ci			}
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_ci			ssize_t read = eds_recv(s, pbuf, more, &status);
211141cc406Sopenharmony_ci			if (read != more) {
212141cc406Sopenharmony_ci				free(pbuf);
213141cc406Sopenharmony_ci				return SANE_STATUS_IO_ERROR;
214141cc406Sopenharmony_ci			}
215141cc406Sopenharmony_ci
216141cc406Sopenharmony_ci			/* parse the received data block */
217141cc406Sopenharmony_ci			if (cb) {
218141cc406Sopenharmony_ci				status = esci2_parse_block(pbuf, more, userdata, cb);
219141cc406Sopenharmony_ci				if (status != SANE_STATUS_GOOD) {
220141cc406Sopenharmony_ci					DBG(1, "%s: %4s error while parsing received data block\n", __func__, cmd);
221141cc406Sopenharmony_ci				}
222141cc406Sopenharmony_ci			}
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_ci			free(pbuf);
225141cc406Sopenharmony_ci
226141cc406Sopenharmony_ci		} else {
227141cc406Sopenharmony_ci			return SANE_STATUS_NO_MEM;
228141cc406Sopenharmony_ci		}
229141cc406Sopenharmony_ci	}
230141cc406Sopenharmony_ci
231141cc406Sopenharmony_ci	return status;
232141cc406Sopenharmony_ci}
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_cistatic SANE_Status esci2_cmd_simple(epsonds_scanner* s, char *cmd, SANE_Status (*cb)(void *userdata, char *token, int len))
235141cc406Sopenharmony_ci{
236141cc406Sopenharmony_ci	return esci2_cmd(s, cmd, 12, NULL, 0, s, cb);
237141cc406Sopenharmony_ci}
238141cc406Sopenharmony_ci
239141cc406Sopenharmony_ciSANE_Status esci2_fin(epsonds_scanner *s)
240141cc406Sopenharmony_ci{
241141cc406Sopenharmony_ci	SANE_Status status;
242141cc406Sopenharmony_ci
243141cc406Sopenharmony_ci	DBG(5, "%s\n", __func__);
244141cc406Sopenharmony_ci
245141cc406Sopenharmony_ci	status = esci2_cmd_simple(s, "FIN x0000000", NULL);
246141cc406Sopenharmony_ci
247141cc406Sopenharmony_ci	for(int i = 0; i < 10; i++) {
248141cc406Sopenharmony_ci
249141cc406Sopenharmony_ci		if(status == SANE_STATUS_DEVICE_BUSY || status == SANE_STATUS_IO_ERROR) {
250141cc406Sopenharmony_ci			status = esci2_cmd_simple(s, "FIN x0000000", NULL);
251141cc406Sopenharmony_ci		}
252141cc406Sopenharmony_ci		else {
253141cc406Sopenharmony_ci			DBG(1, "break\n");
254141cc406Sopenharmony_ci			break;
255141cc406Sopenharmony_ci		}
256141cc406Sopenharmony_ci		DBG(1, "sleep(5)\n");
257141cc406Sopenharmony_ci		sleep(5);
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci	}
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci	s->locked = 0;
262141cc406Sopenharmony_ci	return status;
263141cc406Sopenharmony_ci}
264141cc406Sopenharmony_ci
265141cc406Sopenharmony_ciSANE_Status esci2_can(epsonds_scanner *s)
266141cc406Sopenharmony_ci{
267141cc406Sopenharmony_ci	return esci2_cmd_simple(s, "CAN x0000000", NULL);
268141cc406Sopenharmony_ci}
269141cc406Sopenharmony_ci
270141cc406Sopenharmony_cistatic int decode_value(char *buf, int len)
271141cc406Sopenharmony_ci{
272141cc406Sopenharmony_ci	char tmp[10];
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci	memcpy(tmp, buf, len);
275141cc406Sopenharmony_ci	tmp[len] = '\0';
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci	if (buf[0] == 'd' && len == 4) {
278141cc406Sopenharmony_ci		return strtol(buf + 1, NULL, 10);
279141cc406Sopenharmony_ci	} else if (buf[0] == 'i' && len == 8) {
280141cc406Sopenharmony_ci		return strtol(buf + 1, NULL, 10);
281141cc406Sopenharmony_ci	} else if (buf[0] == 'x' && len == 8) {
282141cc406Sopenharmony_ci		return strtol(buf + 1, NULL, 16);
283141cc406Sopenharmony_ci	} else if (buf[0] == 'h' && len == 4) {
284141cc406Sopenharmony_ci		return strtol(buf + 1, NULL, 16);
285141cc406Sopenharmony_ci	}
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_ci	return -1;
288141cc406Sopenharmony_ci}
289141cc406Sopenharmony_ci
290141cc406Sopenharmony_ci/* h000 */
291141cc406Sopenharmony_cistatic char *decode_binary(char *buf, int len)
292141cc406Sopenharmony_ci{
293141cc406Sopenharmony_ci	char tmp[6];
294141cc406Sopenharmony_ci	int hl;
295141cc406Sopenharmony_ci
296141cc406Sopenharmony_ci	memcpy(tmp, buf, 4);
297141cc406Sopenharmony_ci	tmp[4] = '\0';
298141cc406Sopenharmony_ci
299141cc406Sopenharmony_ci	if (buf[0] != 'h')
300141cc406Sopenharmony_ci		return NULL;
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_ci	hl = strtol(tmp + 1, NULL, 16);
303141cc406Sopenharmony_ci	if (hl > len)
304141cc406Sopenharmony_ci		hl = len;
305141cc406Sopenharmony_ci	if (hl) {
306141cc406Sopenharmony_ci
307141cc406Sopenharmony_ci		char *v = malloc(hl + 1);
308141cc406Sopenharmony_ci		memcpy(v, buf + 4, hl);
309141cc406Sopenharmony_ci		v[hl] = '\0';
310141cc406Sopenharmony_ci
311141cc406Sopenharmony_ci		return v;
312141cc406Sopenharmony_ci	}
313141cc406Sopenharmony_ci
314141cc406Sopenharmony_ci	return NULL;
315141cc406Sopenharmony_ci}
316141cc406Sopenharmony_ci
317141cc406Sopenharmony_cistatic char *decode_string(char *buf, int len)
318141cc406Sopenharmony_ci{
319141cc406Sopenharmony_ci	char *p, *s = decode_binary(buf, len);
320141cc406Sopenharmony_ci	if (s == NULL)
321141cc406Sopenharmony_ci		return NULL;
322141cc406Sopenharmony_ci
323141cc406Sopenharmony_ci	/* trim white space at the end */
324141cc406Sopenharmony_ci	p = s + strlen(s);
325141cc406Sopenharmony_ci	while (*--p == ' ')
326141cc406Sopenharmony_ci		*p = '\0';
327141cc406Sopenharmony_ci
328141cc406Sopenharmony_ci	return s;
329141cc406Sopenharmony_ci}
330141cc406Sopenharmony_ci
331141cc406Sopenharmony_cistatic void debug_token(int level, const char *func, char *token, int len)
332141cc406Sopenharmony_ci{
333141cc406Sopenharmony_ci	char *tdata = malloc(len + 1);
334141cc406Sopenharmony_ci	memcpy(tdata, token + 3, len);
335141cc406Sopenharmony_ci	tdata[len] = '\0';
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_ci	DBG(level, "%s: %3.3s / %s / %d\n", func, token, tdata, len);
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci	free(tdata);
340141cc406Sopenharmony_ci}
341141cc406Sopenharmony_ci
342141cc406Sopenharmony_cistatic SANE_Status info_cb(void *userdata, char *token, int len)
343141cc406Sopenharmony_ci{
344141cc406Sopenharmony_ci	epsonds_scanner *s = (epsonds_scanner *)userdata;
345141cc406Sopenharmony_ci	char *value;
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci
348141cc406Sopenharmony_ci	/* pointer to the token's value */
349141cc406Sopenharmony_ci	value = token + 3;
350141cc406Sopenharmony_ci
351141cc406Sopenharmony_ci	/* nrd / nrdBUSY */
352141cc406Sopenharmony_ci
353141cc406Sopenharmony_ci	if (strncmp("nrd", token, 3) == 0) {
354141cc406Sopenharmony_ci		if (strncmp("BUSY", value, 4) == 0) {
355141cc406Sopenharmony_ci			return SANE_STATUS_DEVICE_BUSY;
356141cc406Sopenharmony_ci		}
357141cc406Sopenharmony_ci	}
358141cc406Sopenharmony_ci
359141cc406Sopenharmony_ci	if (strncmp("PRD", token, 3) == 0) {
360141cc406Sopenharmony_ci		free(s->hw->model);
361141cc406Sopenharmony_ci		s->hw->model = decode_string(value, len);
362141cc406Sopenharmony_ci		s->hw->sane.model = s->hw->model;
363141cc406Sopenharmony_ci		DBG(1, " product: %s\n", s->hw->model);
364141cc406Sopenharmony_ci	}
365141cc406Sopenharmony_ci
366141cc406Sopenharmony_ci	if (strncmp("VER", token, 3) == 0) {
367141cc406Sopenharmony_ci		char *v = decode_string(value, len);
368141cc406Sopenharmony_ci		DBG(1, " version: %s\n", v);
369141cc406Sopenharmony_ci		free(v);
370141cc406Sopenharmony_ci	}
371141cc406Sopenharmony_ci
372141cc406Sopenharmony_ci	if (strncmp("S/N", token, 3) == 0) {
373141cc406Sopenharmony_ci		char *v = decode_string(value, len);
374141cc406Sopenharmony_ci		DBG(1, "  serial: %s\n", v);
375141cc406Sopenharmony_ci		free(v);
376141cc406Sopenharmony_ci	}
377141cc406Sopenharmony_ci
378141cc406Sopenharmony_ci	if (strncmp("ADF", token, 3) == 0) {
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ci		s->hw->has_adf = 1;
381141cc406Sopenharmony_ci
382141cc406Sopenharmony_ci		if (len == 8) {
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_ci			if (strncmp("TYPEPAGE", value, len) == 0) {
385141cc406Sopenharmony_ci				DBG(1, "     ADF: page type\n");
386141cc406Sopenharmony_ci			}
387141cc406Sopenharmony_ci
388141cc406Sopenharmony_ci			if (strncmp("TYPEFEED", value, len) == 0) {
389141cc406Sopenharmony_ci				DBG(1, "     ADF: sheet feed type\n");
390141cc406Sopenharmony_ci			}
391141cc406Sopenharmony_ci
392141cc406Sopenharmony_ci			if (strncmp("DPLX1SCN", value, len) == 0) {
393141cc406Sopenharmony_ci				DBG(1, "     ADF: duplex single pass\n");
394141cc406Sopenharmony_ci				s->hw->adf_singlepass = 1;
395141cc406Sopenharmony_ci			}
396141cc406Sopenharmony_ci
397141cc406Sopenharmony_ci			if (strncmp("DPLX2SCN", value, len) == 0) {
398141cc406Sopenharmony_ci				DBG(1, "     ADF: duplex double pass\n");
399141cc406Sopenharmony_ci				s->hw->adf_singlepass = 0;
400141cc406Sopenharmony_ci			}
401141cc406Sopenharmony_ci
402141cc406Sopenharmony_ci			if (strncmp("FORDPF1N", value, len) == 0) {
403141cc406Sopenharmony_ci				DBG(1, "     ADF: order is 1 to N\n");
404141cc406Sopenharmony_ci			}
405141cc406Sopenharmony_ci
406141cc406Sopenharmony_ci			if (strncmp("FORDPFN1", value, len) == 0) {
407141cc406Sopenharmony_ci				DBG(1, "     ADF: order is N to 1\n");
408141cc406Sopenharmony_ci			}
409141cc406Sopenharmony_ci
410141cc406Sopenharmony_ci			if (strncmp("ALGNLEFT", value, len) == 0) {
411141cc406Sopenharmony_ci				DBG(1, "     ADF: left aligned\n");
412141cc406Sopenharmony_ci				s->hw->adf_alignment = 0;
413141cc406Sopenharmony_ci			}
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci			if (strncmp("ALGNCNTR", value, len) == 0) {
416141cc406Sopenharmony_ci				DBG(1, "     ADF: center aligned\n");
417141cc406Sopenharmony_ci				s->hw->adf_alignment = 1;
418141cc406Sopenharmony_ci			}
419141cc406Sopenharmony_ci
420141cc406Sopenharmony_ci			if (strncmp("ALGNRIGT", value, len) == 0) {
421141cc406Sopenharmony_ci				DBG(1, "     ADF: right aligned (not supported!)\n");
422141cc406Sopenharmony_ci				s->hw->adf_alignment = 2;
423141cc406Sopenharmony_ci			}
424141cc406Sopenharmony_ci		}
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci		if (len == 4) {
427141cc406Sopenharmony_ci
428141cc406Sopenharmony_ci			if (strncmp("PREF", value, len) == 0) {
429141cc406Sopenharmony_ci				DBG(1, "     ADF: auto pre-feed\n");
430141cc406Sopenharmony_ci			}
431141cc406Sopenharmony_ci
432141cc406Sopenharmony_ci			if (strncmp("ASCN", value, len) == 0) {
433141cc406Sopenharmony_ci				DBG(1, "     ADF: auto scan\n");
434141cc406Sopenharmony_ci			}
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ci			if (strncmp("RCVR", value, len) == 0) {
437141cc406Sopenharmony_ci				DBG(1, "     ADF: auto recovery\n");
438141cc406Sopenharmony_ci			}
439141cc406Sopenharmony_ci		}
440141cc406Sopenharmony_ci
441141cc406Sopenharmony_ci		if (len == 20) {
442141cc406Sopenharmony_ci
443141cc406Sopenharmony_ci			/* ADFAREAi0000850i0001400 */
444141cc406Sopenharmony_ci
445141cc406Sopenharmony_ci			if (strncmp("AREA", value, 4) == 0) {
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_ci				int min = decode_value(value + 4, 8);
448141cc406Sopenharmony_ci				int max = decode_value(value + 4 + 8, 8);
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ci				DBG(1, "     ADF: area %dx%d @ 100dpi\n", min, max);
451141cc406Sopenharmony_ci				eds_set_adf_area(s->hw,	min, max, 100);
452141cc406Sopenharmony_ci			}
453141cc406Sopenharmony_ci
454141cc406Sopenharmony_ci			if (strncmp("AMIN", value, 4) == 0) {
455141cc406Sopenharmony_ci
456141cc406Sopenharmony_ci				int min = decode_value(value + 4, 8);
457141cc406Sopenharmony_ci				int max = decode_value(value + 4 + 8, 8);
458141cc406Sopenharmony_ci
459141cc406Sopenharmony_ci				DBG(1, "     ADF: min %dx%d @ 100dpi\n", min, max);
460141cc406Sopenharmony_ci			}
461141cc406Sopenharmony_ci
462141cc406Sopenharmony_ci			if (strncmp("AMAX", value, 4) == 0) {
463141cc406Sopenharmony_ci
464141cc406Sopenharmony_ci				int min = decode_value(value + 4, 8);
465141cc406Sopenharmony_ci				int max = decode_value(value + 4 + 8, 8);
466141cc406Sopenharmony_ci
467141cc406Sopenharmony_ci				DBG(1, "     ADF: max %dx%d @ 100dpi\n", min, max);
468141cc406Sopenharmony_ci			}
469141cc406Sopenharmony_ci		}
470141cc406Sopenharmony_ci
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci
475141cc406Sopenharmony_ci
476141cc406Sopenharmony_ci		if (len == 16) {
477141cc406Sopenharmony_ci
478141cc406Sopenharmony_ci			if (strncmp("AREA", value, 4) == 0) {
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci				int min = decode_value(value + 4, 4);
481141cc406Sopenharmony_ci				int max = decode_value(value + 4 + 4, 8);
482141cc406Sopenharmony_ci
483141cc406Sopenharmony_ci				DBG(1, "     ADF: area %dx%d @ 100dpi\n", min, max);
484141cc406Sopenharmony_ci
485141cc406Sopenharmony_ci				eds_set_adf_area(s->hw,	min, max, 100);
486141cc406Sopenharmony_ci			}
487141cc406Sopenharmony_ci
488141cc406Sopenharmony_ci			if (strncmp("AMAX", value, 4) == 0) {
489141cc406Sopenharmony_ci
490141cc406Sopenharmony_ci				// d
491141cc406Sopenharmony_ci				int min = decode_value(value + 4, 4);
492141cc406Sopenharmony_ci				// i
493141cc406Sopenharmony_ci				int max = decode_value(value + 4 + 4, 8);
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci				DBG(1, "     ADF: max %dx%d @ 100dpi\n", min, max);
496141cc406Sopenharmony_ci			}
497141cc406Sopenharmony_ci		}
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_ci
500141cc406Sopenharmony_ci
501141cc406Sopenharmony_ci
502141cc406Sopenharmony_ci		if (len == 12) {
503141cc406Sopenharmony_ci
504141cc406Sopenharmony_ci			/* RESOi0000600 */
505141cc406Sopenharmony_ci
506141cc406Sopenharmony_ci			if (strncmp("RESO", value, 4) == 0) {
507141cc406Sopenharmony_ci
508141cc406Sopenharmony_ci				int res = decode_value(value + 4, 8);
509141cc406Sopenharmony_ci
510141cc406Sopenharmony_ci				DBG(1, "     ADF: basic resolution is %d dpi\n", res);
511141cc406Sopenharmony_ci			}
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci			/* OVSNd025d035 */
514141cc406Sopenharmony_ci
515141cc406Sopenharmony_ci			if (strncmp("OVSN", value, 4) == 0) {
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci				int x = decode_value(value + 4, 4);
518141cc406Sopenharmony_ci				int y = decode_value(value + 4 + 4, 4);
519141cc406Sopenharmony_ci
520141cc406Sopenharmony_ci				DBG(1, "     ADF: overscan %dx%d @ 100dpi\n", x, y);
521141cc406Sopenharmony_ci			}
522141cc406Sopenharmony_ci		}
523141cc406Sopenharmony_ci	}
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci	if (strncmp("FB ", token, 3) == 0) {
526141cc406Sopenharmony_ci
527141cc406Sopenharmony_ci		s->hw->has_fb = 1;
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci		if (len == 20) {
530141cc406Sopenharmony_ci
531141cc406Sopenharmony_ci			/* AREAi0000850i0001400 */
532141cc406Sopenharmony_ci			if (strncmp("AREA", value, 4) == 0) {
533141cc406Sopenharmony_ci
534141cc406Sopenharmony_ci				int min = decode_value(value + 4, 8);
535141cc406Sopenharmony_ci				int max = decode_value(value + 4 + 8, 8);
536141cc406Sopenharmony_ci
537141cc406Sopenharmony_ci				DBG(1, "      FB: area %dx%d @ 100dpi\n", min, max);
538141cc406Sopenharmony_ci
539141cc406Sopenharmony_ci				eds_set_fbf_area(s->hw,	min, max, 100);
540141cc406Sopenharmony_ci			}
541141cc406Sopenharmony_ci		}
542141cc406Sopenharmony_ci
543141cc406Sopenharmony_ci
544141cc406Sopenharmony_ci		if (len == 16) {
545141cc406Sopenharmony_ci
546141cc406Sopenharmony_ci			/* AREAi0000850i0001400 */
547141cc406Sopenharmony_ci			if (strncmp("AREA", value, 4) == 0) {
548141cc406Sopenharmony_ci				//d
549141cc406Sopenharmony_ci				int min = decode_value(value + 4, 4);
550141cc406Sopenharmony_ci				//i
551141cc406Sopenharmony_ci				int max = decode_value(value + 4 + 4, 8);
552141cc406Sopenharmony_ci
553141cc406Sopenharmony_ci				DBG(1, "      FB: area %dx%d @ 100dpi\n", min, max);
554141cc406Sopenharmony_ci
555141cc406Sopenharmony_ci				eds_set_fbf_area(s->hw,	min, max, 100);
556141cc406Sopenharmony_ci			}
557141cc406Sopenharmony_ci		}
558141cc406Sopenharmony_ci
559141cc406Sopenharmony_ci		if (len == 8) {
560141cc406Sopenharmony_ci
561141cc406Sopenharmony_ci			if (strncmp("ALGNLEFT", value, len) == 0) {
562141cc406Sopenharmony_ci				DBG(1, "      FB: left aligned\n");
563141cc406Sopenharmony_ci				s->hw->fbf_alignment = 0;
564141cc406Sopenharmony_ci			}
565141cc406Sopenharmony_ci
566141cc406Sopenharmony_ci			if (strncmp("ALGNCNTR", value, len) == 0) {
567141cc406Sopenharmony_ci				DBG(1, "      FB: center aligned\n");
568141cc406Sopenharmony_ci				s->hw->fbf_alignment = 1;
569141cc406Sopenharmony_ci			}
570141cc406Sopenharmony_ci
571141cc406Sopenharmony_ci			if (strncmp("ALGNRIGT", value, len) == 0) {
572141cc406Sopenharmony_ci				DBG(1, "      FB: right aligned (not supported!)\n");
573141cc406Sopenharmony_ci				s->hw->fbf_alignment = 2;
574141cc406Sopenharmony_ci			}
575141cc406Sopenharmony_ci		}
576141cc406Sopenharmony_ci
577141cc406Sopenharmony_ci		if (len == 12) {
578141cc406Sopenharmony_ci
579141cc406Sopenharmony_ci			/* RESOi0000600 */
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ci			if (strncmp("RESO", value, 4) == 0) {
582141cc406Sopenharmony_ci
583141cc406Sopenharmony_ci				int res = decode_value(value + 4, 8);
584141cc406Sopenharmony_ci
585141cc406Sopenharmony_ci				DBG(1, "      FB: basic resolution is %d dpi\n", res);
586141cc406Sopenharmony_ci			}
587141cc406Sopenharmony_ci
588141cc406Sopenharmony_ci			/* OVSNd025d035 */
589141cc406Sopenharmony_ci
590141cc406Sopenharmony_ci			if (strncmp("OVSN", value, 4) == 0) {
591141cc406Sopenharmony_ci
592141cc406Sopenharmony_ci				int x = decode_value(value + 4, 4);
593141cc406Sopenharmony_ci				int y = decode_value(value + 4 + 4, 4);
594141cc406Sopenharmony_ci
595141cc406Sopenharmony_ci				DBG(1, "      FB: overscan %dx%d @ 100dpi\n", x, y);
596141cc406Sopenharmony_ci			}
597141cc406Sopenharmony_ci		}
598141cc406Sopenharmony_ci
599141cc406Sopenharmony_ci		if (len == 4) {
600141cc406Sopenharmony_ci
601141cc406Sopenharmony_ci			if (strncmp("DETX", value, len) == 0) {
602141cc406Sopenharmony_ci				DBG(1, "      FB: paper width detection\n");
603141cc406Sopenharmony_ci			}
604141cc406Sopenharmony_ci
605141cc406Sopenharmony_ci			if (strncmp("DETY", value, len) == 0) {
606141cc406Sopenharmony_ci				DBG(1, "      FB: paper height detection\n");
607141cc406Sopenharmony_ci			}
608141cc406Sopenharmony_ci		}
609141cc406Sopenharmony_ci	}
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
612141cc406Sopenharmony_ci}
613141cc406Sopenharmony_ci
614141cc406Sopenharmony_ciSANE_Status esci2_info(epsonds_scanner *s)
615141cc406Sopenharmony_ci{
616141cc406Sopenharmony_ci	SANE_Status status;
617141cc406Sopenharmony_ci	int i = 4;
618141cc406Sopenharmony_ci
619141cc406Sopenharmony_ci	DBG(1, "= gathering device information\n");
620141cc406Sopenharmony_ci
621141cc406Sopenharmony_ci	do {
622141cc406Sopenharmony_ci		status = esci2_cmd_simple(s, "INFOx0000000", &info_cb);
623141cc406Sopenharmony_ci		if (status == SANE_STATUS_DEVICE_BUSY) {
624141cc406Sopenharmony_ci			sleep(2);
625141cc406Sopenharmony_ci		}
626141cc406Sopenharmony_ci
627141cc406Sopenharmony_ci		i--;
628141cc406Sopenharmony_ci
629141cc406Sopenharmony_ci	} while (status == SANE_STATUS_DEVICE_BUSY && i);
630141cc406Sopenharmony_ci
631141cc406Sopenharmony_ci	return status;
632141cc406Sopenharmony_ci}
633141cc406Sopenharmony_ci
634141cc406Sopenharmony_ci/* CAPA */
635141cc406Sopenharmony_ci
636141cc406Sopenharmony_cistatic SANE_Status capa_cb(void *userdata, char *token, int len)
637141cc406Sopenharmony_ci{
638141cc406Sopenharmony_ci	epsonds_scanner *s = (epsonds_scanner *)userdata;
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci	char *value = token + 3;
641141cc406Sopenharmony_ci
642141cc406Sopenharmony_ci	if (DBG_LEVEL >= 11) {
643141cc406Sopenharmony_ci		debug_token(DBG_LEVEL, __func__, token, len);
644141cc406Sopenharmony_ci	}
645141cc406Sopenharmony_ci
646141cc406Sopenharmony_ci	if (len == 4) {
647141cc406Sopenharmony_ci
648141cc406Sopenharmony_ci		if (strncmp("ADFDPLX", token, 3 + 4) == 0) {
649141cc406Sopenharmony_ci			DBG(1, "     ADF: duplex\n");
650141cc406Sopenharmony_ci			s->hw->adf_is_duplex = 1;
651141cc406Sopenharmony_ci		}
652141cc406Sopenharmony_ci
653141cc406Sopenharmony_ci		if (strncmp("ADFSKEW", token, 3 + 4) == 0) {
654141cc406Sopenharmony_ci			DBG(1, "     ADF: skew correction\n");
655141cc406Sopenharmony_ci			s->hw->adf_has_skew = 1;
656141cc406Sopenharmony_ci		}
657141cc406Sopenharmony_ci
658141cc406Sopenharmony_ci		if (strncmp("ADFOVSN", token, 3 + 4) == 0) {
659141cc406Sopenharmony_ci			DBG(1, "     ADF: overscan\n");
660141cc406Sopenharmony_ci		}
661141cc406Sopenharmony_ci
662141cc406Sopenharmony_ci		if (strncmp("ADFPEDT", token, 3 + 4) == 0) {
663141cc406Sopenharmony_ci			DBG(1, "     ADF: paper end detection\n");
664141cc406Sopenharmony_ci		}
665141cc406Sopenharmony_ci
666141cc406Sopenharmony_ci		if (strncmp("ADFLOAD", token, 3 + 4) == 0) {
667141cc406Sopenharmony_ci			DBG(1, "     ADF: paper load\n");
668141cc406Sopenharmony_ci			s->hw->adf_has_load = 1;
669141cc406Sopenharmony_ci		}
670141cc406Sopenharmony_ci
671141cc406Sopenharmony_ci		if (strncmp("ADFEJCT", token, 3 + 4) == 0) {
672141cc406Sopenharmony_ci			DBG(1, "     ADF: paper eject\n");
673141cc406Sopenharmony_ci			s->hw->adf_has_eject = 1;
674141cc406Sopenharmony_ci		}
675141cc406Sopenharmony_ci
676141cc406Sopenharmony_ci		if (strncmp("ADFCRP ", token, 3 + 4) == 0) {
677141cc406Sopenharmony_ci			DBG(1, "     ADF: image cropping\n");
678141cc406Sopenharmony_ci			s->hw->adf_has_crp = 1;
679141cc406Sopenharmony_ci		}
680141cc406Sopenharmony_ci
681141cc406Sopenharmony_ci		if (strncmp("ADFFAST", token, 3 + 4) == 0) {
682141cc406Sopenharmony_ci			DBG(1, "     ADF: fast mode available\n");
683141cc406Sopenharmony_ci		}
684141cc406Sopenharmony_ci
685141cc406Sopenharmony_ci		if (strncmp("ADFDFL1", token, 3 + 4) == 0) {
686141cc406Sopenharmony_ci			DBG(1, "     ADF: double feed detection\n");
687141cc406Sopenharmony_ci			s->hw->adf_has_dfd = 1;
688141cc406Sopenharmony_ci		}
689141cc406Sopenharmony_ci	}
690141cc406Sopenharmony_ci
691141cc406Sopenharmony_ci	if (len == 8 && strncmp("ADFDFL1DFL2", token, 3 + 4) == 0) {
692141cc406Sopenharmony_ci		DBG(1, "     ADF: double feed detection (high sensitivity)\n");
693141cc406Sopenharmony_ci		s->hw->adf_has_dfd = 2;
694141cc406Sopenharmony_ci	}
695141cc406Sopenharmony_ci
696141cc406Sopenharmony_ci	if (strncmp("FMT", token, 3) == 0) {
697141cc406Sopenharmony_ci
698141cc406Sopenharmony_ci		/* a bit ugly... */
699141cc406Sopenharmony_ci
700141cc406Sopenharmony_ci		if (len >= 8) {
701141cc406Sopenharmony_ci			if (strncmp("RAW ", value + 4, 4) == 0) {
702141cc406Sopenharmony_ci				s->hw->has_raw = 1;
703141cc406Sopenharmony_ci			}
704141cc406Sopenharmony_ci		}
705141cc406Sopenharmony_ci
706141cc406Sopenharmony_ci		if (len >= 12) {
707141cc406Sopenharmony_ci			if (strncmp("RAW ", value + 8, 4) == 0) {
708141cc406Sopenharmony_ci				s->hw->has_raw = 1;
709141cc406Sopenharmony_ci			}
710141cc406Sopenharmony_ci		}
711141cc406Sopenharmony_ci	}
712141cc406Sopenharmony_ci
713141cc406Sopenharmony_ci
714141cc406Sopenharmony_ci	if (strncmp("COLLIST", token, 3 + 4) == 0)
715141cc406Sopenharmony_ci	{
716141cc406Sopenharmony_ci		char *p = token + 3 + 4;
717141cc406Sopenharmony_ci		int count = (len - 4);
718141cc406Sopenharmony_ci		int readBytes = 0;
719141cc406Sopenharmony_ci		s->hw->has_mono = 0;
720141cc406Sopenharmony_ci		while (readBytes < count) {
721141cc406Sopenharmony_ci			if (strncmp(p, "M001", 4) == 0)
722141cc406Sopenharmony_ci			{
723141cc406Sopenharmony_ci				s->hw->has_mono = 1;
724141cc406Sopenharmony_ci			}
725141cc406Sopenharmony_ci			readBytes+=4;
726141cc406Sopenharmony_ci			p+=4;
727141cc406Sopenharmony_ci		}
728141cc406Sopenharmony_ci	}
729141cc406Sopenharmony_ci
730141cc406Sopenharmony_ci	/* RSMRANGi0000050i0000600 */
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_ci	if (strncmp("RSMRANG", token, 3 + 4) == 0) {
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci		char *p = token + 3 + 4;
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci		if (p[0] == 'i') {
737141cc406Sopenharmony_ci
738141cc406Sopenharmony_ci			int min = decode_value(p, 8);
739141cc406Sopenharmony_ci			int max = decode_value(p + 8, 8);
740141cc406Sopenharmony_ci
741141cc406Sopenharmony_ci			eds_set_resolution_range(s->hw, min, max);
742141cc406Sopenharmony_ci
743141cc406Sopenharmony_ci			DBG(1, "resolution min/max %d/%d\n", min, max);
744141cc406Sopenharmony_ci		}
745141cc406Sopenharmony_ci	}
746141cc406Sopenharmony_ci
747141cc406Sopenharmony_ci	/* RSMLISTi0000300i0000600 */
748141cc406Sopenharmony_ci
749141cc406Sopenharmony_ci	if (strncmp("RSMLIST", token, 3 + 4) == 0) {
750141cc406Sopenharmony_ci
751141cc406Sopenharmony_ci		char *p = token + 3 + 4;
752141cc406Sopenharmony_ci
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci			int count = (len - 4);
755141cc406Sopenharmony_ci			int readBytes = 0;
756141cc406Sopenharmony_ci
757141cc406Sopenharmony_ci			while (readBytes < count) {
758141cc406Sopenharmony_ci			      if(*p == 'i')
759141cc406Sopenharmony_ci		             {
760141cc406Sopenharmony_ci				eds_add_resolution(s->hw, decode_value(p, 8));
761141cc406Sopenharmony_ci				p += 8;
762141cc406Sopenharmony_ci				readBytes += 8;
763141cc406Sopenharmony_ci			     }else if(*p == 'd')
764141cc406Sopenharmony_ci			    {
765141cc406Sopenharmony_ci				eds_add_resolution(s->hw, decode_value(p, 4));
766141cc406Sopenharmony_ci				p += 4;
767141cc406Sopenharmony_ci				readBytes +=4;
768141cc406Sopenharmony_ci			     }
769141cc406Sopenharmony_ci			}
770141cc406Sopenharmony_ci
771141cc406Sopenharmony_ci	}
772141cc406Sopenharmony_ci
773141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
774141cc406Sopenharmony_ci}
775141cc406Sopenharmony_ci
776141cc406Sopenharmony_ciSANE_Status esci2_capa(epsonds_scanner *s)
777141cc406Sopenharmony_ci{
778141cc406Sopenharmony_ci	return esci2_cmd_simple(s, "CAPAx0000000", &capa_cb);
779141cc406Sopenharmony_ci}
780141cc406Sopenharmony_ci
781141cc406Sopenharmony_ci/* STAT */
782141cc406Sopenharmony_ci
783141cc406Sopenharmony_cistatic SANE_Status stat_cb(void *userdata, char *token, int len)
784141cc406Sopenharmony_ci{
785141cc406Sopenharmony_ci	char *value = token + 3;
786141cc406Sopenharmony_ci
787141cc406Sopenharmony_ci	(void) userdata;
788141cc406Sopenharmony_ci
789141cc406Sopenharmony_ci	if (DBG_LEVEL >= 11) {
790141cc406Sopenharmony_ci		debug_token(DBG_LEVEL, __func__, token, len);
791141cc406Sopenharmony_ci	}
792141cc406Sopenharmony_ci
793141cc406Sopenharmony_ci	if (strncmp("ERR", token, 3) == 0) {
794141cc406Sopenharmony_ci		if (strncmp("ADF PE ", value, len) == 0) {
795141cc406Sopenharmony_ci			DBG(1, "     PE : paper empty\n");
796141cc406Sopenharmony_ci			return SANE_STATUS_NO_DOCS;
797141cc406Sopenharmony_ci		}
798141cc406Sopenharmony_ci
799141cc406Sopenharmony_ci		if (strncmp("ADF OPN", value, len) == 0) {
800141cc406Sopenharmony_ci			DBG(1, "     conver open\n");
801141cc406Sopenharmony_ci			return SANE_STATUS_COVER_OPEN;
802141cc406Sopenharmony_ci		}
803141cc406Sopenharmony_ci	}
804141cc406Sopenharmony_ci
805141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
806141cc406Sopenharmony_ci}
807141cc406Sopenharmony_ci
808141cc406Sopenharmony_ciSANE_Status esci2_stat(epsonds_scanner *s)
809141cc406Sopenharmony_ci{
810141cc406Sopenharmony_ci	return esci2_cmd_simple(s, "STATx0000000", &stat_cb);
811141cc406Sopenharmony_ci}
812141cc406Sopenharmony_ci
813141cc406Sopenharmony_ci/* RESA */
814141cc406Sopenharmony_ci
815141cc406Sopenharmony_cistatic SANE_Status resa_cb(void *userdata, char *token, int len)
816141cc406Sopenharmony_ci{
817141cc406Sopenharmony_ci	/* epsonds_scanner *s = (epsonds_scanner *)userdata; */
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_ci	(void) userdata;
820141cc406Sopenharmony_ci
821141cc406Sopenharmony_ci	if (DBG_LEVEL >= 11) {
822141cc406Sopenharmony_ci		debug_token(DBG_LEVEL, __func__, token, len);
823141cc406Sopenharmony_ci	}
824141cc406Sopenharmony_ci
825141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
826141cc406Sopenharmony_ci}
827141cc406Sopenharmony_ci
828141cc406Sopenharmony_ciSANE_Status esci2_resa(epsonds_scanner *s)
829141cc406Sopenharmony_ci{
830141cc406Sopenharmony_ci	return esci2_cmd_simple(s, "RESAx0000000", &resa_cb);
831141cc406Sopenharmony_ci}
832141cc406Sopenharmony_ci
833141cc406Sopenharmony_ci/* PARA */
834141cc406Sopenharmony_ci
835141cc406Sopenharmony_cistatic SANE_Status para_cb(void *userdata, char *token, int len)
836141cc406Sopenharmony_ci{
837141cc406Sopenharmony_ci	if (DBG_LEVEL >= 11) {
838141cc406Sopenharmony_ci		debug_token(DBG_LEVEL, __func__, token, len);
839141cc406Sopenharmony_ci	}
840141cc406Sopenharmony_ci
841141cc406Sopenharmony_ci	(void) userdata;
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci	if (strncmp("par", token, 3) == 0) {
844141cc406Sopenharmony_ci		if (strncmp("FAIL", token + 3, 4) == 0) {
845141cc406Sopenharmony_ci			DBG(1, "%s: parameter setting failed\n", __func__);
846141cc406Sopenharmony_ci			return SANE_STATUS_INVAL;
847141cc406Sopenharmony_ci		}
848141cc406Sopenharmony_ci	}
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
851141cc406Sopenharmony_ci}
852141cc406Sopenharmony_ci
853141cc406Sopenharmony_ciSANE_Status esci2_para(epsonds_scanner *s, char *parameters, int len)
854141cc406Sopenharmony_ci{
855141cc406Sopenharmony_ci	DBG(8, "%s: %s\n", __func__, parameters);
856141cc406Sopenharmony_ci	return esci2_cmd(s, "PARAx0000000", 12, parameters, len, NULL, &para_cb);
857141cc406Sopenharmony_ci}
858141cc406Sopenharmony_ci
859141cc406Sopenharmony_ciSANE_Status esci2_mech(epsonds_scanner *s, char *parameters)
860141cc406Sopenharmony_ci{
861141cc406Sopenharmony_ci	DBG(8, "%s: %s\n", __func__, parameters);
862141cc406Sopenharmony_ci	return esci2_cmd(s, "MECHx0000000", 12, parameters, strlen(parameters), NULL, &para_cb);
863141cc406Sopenharmony_ci}
864141cc406Sopenharmony_ci
865141cc406Sopenharmony_ciSANE_Status esci2_trdt(epsonds_scanner *s)
866141cc406Sopenharmony_ci{
867141cc406Sopenharmony_ci	return esci2_cmd_simple(s, "TRDTx0000000", NULL);
868141cc406Sopenharmony_ci}
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_ci
871141cc406Sopenharmony_cistatic SANE_Status img_cb(void *userdata, char *token, int len)
872141cc406Sopenharmony_ci{
873141cc406Sopenharmony_ci	struct epsonds_scanner *s = userdata;
874141cc406Sopenharmony_ci
875141cc406Sopenharmony_ci	if (DBG_LEVEL >= 11) {
876141cc406Sopenharmony_ci		debug_token(DBG_LEVEL, __func__, token, len);
877141cc406Sopenharmony_ci	}
878141cc406Sopenharmony_ci
879141cc406Sopenharmony_ci	/* psti0000256i0000000i0000945 / 24 */
880141cc406Sopenharmony_ci
881141cc406Sopenharmony_ci	/* integer comparison first so it's faster */
882141cc406Sopenharmony_ci	if (len == 24 && strncmp("pst", token, 3) == 0) {
883141cc406Sopenharmony_ci
884141cc406Sopenharmony_ci		s->dummy = decode_value(token + 3 + 8, 8);
885141cc406Sopenharmony_ci
886141cc406Sopenharmony_ci		DBG(10, "%s: pst width: %d, height: %d, dummy: %d\n",
887141cc406Sopenharmony_ci			__func__,
888141cc406Sopenharmony_ci			decode_value(token + 3, 8),
889141cc406Sopenharmony_ci			decode_value(token + 3 + 8 + 8, 8),
890141cc406Sopenharmony_ci			s->dummy);
891141cc406Sopenharmony_ci
892141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
893141cc406Sopenharmony_ci	}
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ci	if (len == 12 && strncmp("pst", token, 3) == 0) {
896141cc406Sopenharmony_ci
897141cc406Sopenharmony_ci		s->dummy = decode_value(token + 3 + 4, 4);
898141cc406Sopenharmony_ci
899141cc406Sopenharmony_ci		DBG(10, "%s: pst width: %d, height: %d, dummy: %d\n",
900141cc406Sopenharmony_ci			__func__,
901141cc406Sopenharmony_ci			decode_value(token + 3, 4),
902141cc406Sopenharmony_ci			decode_value(token + 3 + 4 + 4, 4),
903141cc406Sopenharmony_ci			s->dummy);
904141cc406Sopenharmony_ci
905141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
906141cc406Sopenharmony_ci	}
907141cc406Sopenharmony_ci
908141cc406Sopenharmony_ci	if (len == 16 && strncmp("pst", token, 3) == 0) {
909141cc406Sopenharmony_ci
910141cc406Sopenharmony_ci		s->dummy = decode_value(token + 3 + 4, 4);
911141cc406Sopenharmony_ci
912141cc406Sopenharmony_ci		DBG(10, "%s: pst width: %d, height: %d, dummy: %d\n",
913141cc406Sopenharmony_ci			__func__,
914141cc406Sopenharmony_ci			decode_value(token + 3, 4),
915141cc406Sopenharmony_ci			decode_value(token + 3 + 4 + 4, 8),
916141cc406Sopenharmony_ci			s->dummy);
917141cc406Sopenharmony_ci
918141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
919141cc406Sopenharmony_ci	}
920141cc406Sopenharmony_ci
921141cc406Sopenharmony_ci	if (len == 20 && strncmp("pst", token, 3) == 0) {
922141cc406Sopenharmony_ci
923141cc406Sopenharmony_ci		s->dummy = decode_value(token + 3 + 8, 4);
924141cc406Sopenharmony_ci
925141cc406Sopenharmony_ci		DBG(10, "%s: pst width: %d, height: %d, dummy: %d\n",
926141cc406Sopenharmony_ci			__func__,
927141cc406Sopenharmony_ci			decode_value(token + 3, 8),
928141cc406Sopenharmony_ci			decode_value(token + 3 + 8 + 4, 8),
929141cc406Sopenharmony_ci			s->dummy);
930141cc406Sopenharmony_ci
931141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
932141cc406Sopenharmony_ci	}
933141cc406Sopenharmony_ci
934141cc406Sopenharmony_ci
935141cc406Sopenharmony_ci	// i0001696i0002347
936141cc406Sopenharmony_ci	if (len == 16 && strncmp("pen", token, 3) == 0) {
937141cc406Sopenharmony_ci		DBG(10, "%s: page end\n", __func__);
938141cc406Sopenharmony_ci		s->eof = 1;
939141cc406Sopenharmony_ci		if (s->isflatbedScan)
940141cc406Sopenharmony_ci		{
941141cc406Sopenharmony_ci			s->scanning = 0;
942141cc406Sopenharmony_ci		}
943141cc406Sopenharmony_ci		DBG(10, "%s: pen width: %d, height: %d, dummy: %d\n",
944141cc406Sopenharmony_ci			__func__,
945141cc406Sopenharmony_ci			decode_value(token + 3, 8),
946141cc406Sopenharmony_ci			decode_value(token + 3 + 8, 8),
947141cc406Sopenharmony_ci		s->dummy);
948141cc406Sopenharmony_ci		s->width_temp = decode_value(token + 3, 8);
949141cc406Sopenharmony_ci		s->height_temp = decode_value(token + 3 + 8, 8);
950141cc406Sopenharmony_ci		return SANE_STATUS_EOF;
951141cc406Sopenharmony_ci	}
952141cc406Sopenharmony_ci
953141cc406Sopenharmony_ci	// d696i0002347
954141cc406Sopenharmony_ci	if (len == 12 && strncmp("pen", token, 3) == 0) {
955141cc406Sopenharmony_ci		DBG(10, "%s: page end\n", __func__);
956141cc406Sopenharmony_ci		s->eof = 1;
957141cc406Sopenharmony_ci		if (s->isflatbedScan)
958141cc406Sopenharmony_ci		{
959141cc406Sopenharmony_ci			s->scanning = 0;
960141cc406Sopenharmony_ci		}
961141cc406Sopenharmony_ci
962141cc406Sopenharmony_ci		DBG(10, "%s: pen width: %d, height: %d, dummy: %d\n",
963141cc406Sopenharmony_ci			__func__,
964141cc406Sopenharmony_ci			decode_value(token + 3, 4),
965141cc406Sopenharmony_ci			decode_value(token + 3 + 4, 8),
966141cc406Sopenharmony_ci			s->dummy);
967141cc406Sopenharmony_ci
968141cc406Sopenharmony_ci		s->width_temp = decode_value(token + 3, 4);
969141cc406Sopenharmony_ci		s->height_temp = decode_value(token + 3 + 4, 8);
970141cc406Sopenharmony_ci		return SANE_STATUS_EOF;
971141cc406Sopenharmony_ci	}
972141cc406Sopenharmony_ci
973141cc406Sopenharmony_ci	// d696d2347
974141cc406Sopenharmony_ci	if (len == 8 && strncmp("pen", token, 3) == 0) {
975141cc406Sopenharmony_ci		DBG(10, "%s: page end\n", __func__);
976141cc406Sopenharmony_ci		s->eof = 1;
977141cc406Sopenharmony_ci		if (s->isflatbedScan)
978141cc406Sopenharmony_ci		{
979141cc406Sopenharmony_ci			s->scanning = 0;
980141cc406Sopenharmony_ci		}
981141cc406Sopenharmony_ci		DBG(10, "%s: pen width: %d, height: %d, dummy: %d\n",
982141cc406Sopenharmony_ci			__func__,
983141cc406Sopenharmony_ci			decode_value(token + 3, 4),
984141cc406Sopenharmony_ci			decode_value(token + 3 + 4, 4),
985141cc406Sopenharmony_ci			s->dummy);
986141cc406Sopenharmony_ci
987141cc406Sopenharmony_ci		s->width_temp = decode_value(token + 3, 4);
988141cc406Sopenharmony_ci		s->height_temp = decode_value(token + 3 + 4, 4);
989141cc406Sopenharmony_ci
990141cc406Sopenharmony_ci		return SANE_STATUS_EOF;
991141cc406Sopenharmony_ci	}
992141cc406Sopenharmony_ci
993141cc406Sopenharmony_ci
994141cc406Sopenharmony_ci	/* typIMGA or typIMGB */
995141cc406Sopenharmony_ci	if (len == 4 && strncmp("typ", token, 3) == 0) {
996141cc406Sopenharmony_ci
997141cc406Sopenharmony_ci		if (token[6] == 'B')
998141cc406Sopenharmony_ci			s->backside = 1;
999141cc406Sopenharmony_ci		else
1000141cc406Sopenharmony_ci			s->backside = 0;
1001141cc406Sopenharmony_ci
1002141cc406Sopenharmony_ci		return SANE_STATUS_GOOD;
1003141cc406Sopenharmony_ci	}
1004141cc406Sopenharmony_ci
1005141cc406Sopenharmony_ci	if (strncmp("err", token, 3) == 0) {
1006141cc406Sopenharmony_ci
1007141cc406Sopenharmony_ci		char *option = token + 3;	/* ADF, TPU, FB */
1008141cc406Sopenharmony_ci		char *cause = token + 3 + 4;	/* OPN, PJ, PE, ERR, LTF, LOCK, DFED, DTCL, AUT, PERM */
1009141cc406Sopenharmony_ci
1010141cc406Sopenharmony_ci		s->scanning = 0;
1011141cc406Sopenharmony_ci		s->scanEnd = 1;
1012141cc406Sopenharmony_ci
1013141cc406Sopenharmony_ci		DBG(1, "%s: error on option %3.3s, cause %4.4s\n",
1014141cc406Sopenharmony_ci			__func__, option, cause);
1015141cc406Sopenharmony_ci
1016141cc406Sopenharmony_ci		if (cause[0] == 'P' && cause[1] == 'J')
1017141cc406Sopenharmony_ci			return SANE_STATUS_JAMMED;
1018141cc406Sopenharmony_ci
1019141cc406Sopenharmony_ci		if (cause[0] == 'P' && cause[1] == 'E')
1020141cc406Sopenharmony_ci			return SANE_STATUS_NO_DOCS;
1021141cc406Sopenharmony_ci
1022141cc406Sopenharmony_ci		if (cause[0] == 'O' && cause[1] == 'P' && cause[2] == 'N')
1023141cc406Sopenharmony_ci			return SANE_STATUS_COVER_OPEN;
1024141cc406Sopenharmony_ci
1025141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1026141cc406Sopenharmony_ci	}
1027141cc406Sopenharmony_ci
1028141cc406Sopenharmony_ci	if (len == 4 && strncmp("atnCAN ", token, 3 + 4) == 0) {
1029141cc406Sopenharmony_ci		DBG(1, "%s: cancel request\n", __func__);
1030141cc406Sopenharmony_ci		s->canceling = 1;
1031141cc406Sopenharmony_ci		s->scanning = 0;
1032141cc406Sopenharmony_ci		return SANE_STATUS_CANCELLED;
1033141cc406Sopenharmony_ci	}
1034141cc406Sopenharmony_ci
1035141cc406Sopenharmony_ci	if (len == 4 && strncmp("lftd000", token, 3 + 4) == 0) {
1036141cc406Sopenharmony_ci		DBG(1, "%s:lft ok\n", __func__);
1037141cc406Sopenharmony_ci		s->scanEnd = 1;
1038141cc406Sopenharmony_ci		s->scanning = 0;
1039141cc406Sopenharmony_ci	}
1040141cc406Sopenharmony_ci
1041141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1042141cc406Sopenharmony_ci}
1043141cc406Sopenharmony_ci
1044141cc406Sopenharmony_ci
1045141cc406Sopenharmony_ciSANE_Status
1046141cc406Sopenharmony_ciesci2_img(struct epsonds_scanner *s, SANE_Int *length)
1047141cc406Sopenharmony_ci{
1048141cc406Sopenharmony_ci	SANE_Status status = SANE_STATUS_GOOD;
1049141cc406Sopenharmony_ci	SANE_Status parse_status;
1050141cc406Sopenharmony_ci	unsigned int more;
1051141cc406Sopenharmony_ci	ssize_t read;
1052141cc406Sopenharmony_ci
1053141cc406Sopenharmony_ci	DBG(15, "esci2_img start\n");
1054141cc406Sopenharmony_ci
1055141cc406Sopenharmony_ci	*length = 0;
1056141cc406Sopenharmony_ci
1057141cc406Sopenharmony_ci	if (s->canceling)
1058141cc406Sopenharmony_ci		return SANE_STATUS_CANCELLED;
1059141cc406Sopenharmony_ci
1060141cc406Sopenharmony_ci	/* request image data */
1061141cc406Sopenharmony_ci	eds_send(s, "IMG x0000000", 12, &status, 64);
1062141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
1063141cc406Sopenharmony_ci		return status;
1064141cc406Sopenharmony_ci	}
1065141cc406Sopenharmony_ci	DBG(15, "request img OK\n");
1066141cc406Sopenharmony_ci
1067141cc406Sopenharmony_ci	/* receive DataHeaderBlock */
1068141cc406Sopenharmony_ci	memset(s->buf, 0x00, 64);
1069141cc406Sopenharmony_ci	eds_recv(s, s->buf, 64, &status);
1070141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
1071141cc406Sopenharmony_ci		return status;
1072141cc406Sopenharmony_ci	}
1073141cc406Sopenharmony_ci	DBG(15, "receive img OK\n");
1074141cc406Sopenharmony_ci
1075141cc406Sopenharmony_ci	/* check if we need to read any image data */
1076141cc406Sopenharmony_ci	more = 0;
1077141cc406Sopenharmony_ci	if (!esci2_check_header("IMG ", (char *)s->buf, &more)) {
1078141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1079141cc406Sopenharmony_ci	}
1080141cc406Sopenharmony_ci
1081141cc406Sopenharmony_ci	/* this handles eof and errors */
1082141cc406Sopenharmony_ci	parse_status = esci2_parse_block((char *)s->buf + 12, 64 - 12, s, &img_cb);
1083141cc406Sopenharmony_ci
1084141cc406Sopenharmony_ci	if (s->backside)
1085141cc406Sopenharmony_ci	{
1086141cc406Sopenharmony_ci		s->width_back = s->width_temp;
1087141cc406Sopenharmony_ci		s->height_back = s->height_temp;
1088141cc406Sopenharmony_ci	}else{
1089141cc406Sopenharmony_ci		s->width_front = s->width_temp;
1090141cc406Sopenharmony_ci		s->height_front = s->height_temp;
1091141cc406Sopenharmony_ci
1092141cc406Sopenharmony_ci	}
1093141cc406Sopenharmony_ci
1094141cc406Sopenharmony_ci
1095141cc406Sopenharmony_ci	/* no more data? return using the status of the esci2_parse_block
1096141cc406Sopenharmony_ci	 * call, which might hold other error conditions.
1097141cc406Sopenharmony_ci	 */
1098141cc406Sopenharmony_ci	if (!more) {
1099141cc406Sopenharmony_ci		return parse_status;
1100141cc406Sopenharmony_ci	}
1101141cc406Sopenharmony_ci
1102141cc406Sopenharmony_ci	/* more data than was accounted for in s->buf */
1103141cc406Sopenharmony_ci	if (more > s->bsz) {
1104141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1105141cc406Sopenharmony_ci	}
1106141cc406Sopenharmony_ci	/* ALWAYS read image data */
1107141cc406Sopenharmony_ci	if (s->hw->connection == SANE_EPSONDS_NET) {
1108141cc406Sopenharmony_ci		epsonds_net_request_read(s, more);
1109141cc406Sopenharmony_ci	}
1110141cc406Sopenharmony_ci
1111141cc406Sopenharmony_ci	read = eds_recv(s, s->buf, more, &status);
1112141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
1113141cc406Sopenharmony_ci		return status;
1114141cc406Sopenharmony_ci	}
1115141cc406Sopenharmony_ci
1116141cc406Sopenharmony_ci	if (read != more) {
1117141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1118141cc406Sopenharmony_ci	}
1119141cc406Sopenharmony_ci
1120141cc406Sopenharmony_ci	/* handle esci2_parse_block errors */
1121141cc406Sopenharmony_ci	if (parse_status != SANE_STATUS_GOOD) {
1122141cc406Sopenharmony_ci		return parse_status;
1123141cc406Sopenharmony_ci	}
1124141cc406Sopenharmony_ci
1125141cc406Sopenharmony_ci	DBG(15, "%s: read %lu bytes, status: %d\n", __func__, (unsigned long) read, status);
1126141cc406Sopenharmony_ci
1127141cc406Sopenharmony_ci	*length = read;
1128141cc406Sopenharmony_ci
1129141cc406Sopenharmony_ci	if (s->canceling) {
1130141cc406Sopenharmony_ci		return SANE_STATUS_CANCELLED;
1131141cc406Sopenharmony_ci	}
1132141cc406Sopenharmony_ci
1133141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1134141cc406Sopenharmony_ci}
1135