1 /*
2  * epsonds-cmd.c - Epson ESC/I-2 routines.
3  *
4  * Copyright (C) 2015 Tower Technologies
5  * Author: Alessandro Zummo <a.zummo@towertech.it>
6  *
7  * This file is part of the SANE package.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation, version 2.
12  */
13 
14 #define DEBUG_DECLARE_ONLY
15 
16 #include "sane/config.h"
17 #include <ctype.h>
18 #include <unistd.h>	     /* sleep */
19 
20 #include "epsonds.h"
21 #include "epsonds-io.h"
22 #include "epsonds-cmd.h"
23 #include "epsonds-ops.h"
24 #include "epsonds-net.h"
25 
26 static SANE_Status
esci2_parse_block(char * buf,int len,void * userdata,SANE_Status (* cb)(void * userdata,char * token,int len))27 esci2_parse_block(char *buf, int len, void *userdata, SANE_Status (*cb)(void *userdata, char *token, int len))
28 {
29 	SANE_Status status = SANE_STATUS_GOOD;
30 	SANE_Status delayed_status = SANE_STATUS_GOOD;
31 
32 
33 	char *start = buf;
34 	char *end = (buf + len) - 1;
35 
36 	/* 0  : #
37 	 * 1-3: param
38 	 * 4- : data
39 	*/
40 
41 	while (1) {
42 
43 		char param[4];
44 
45 		while (*start != '#' && start < end)
46 			start++;
47 
48 		if (*start != '#')
49 			break;
50 
51 		param[0] = *++start;
52 		param[1] = *++start;
53 		param[2] = *++start;
54 		param[3] = '\0';
55 
56 		if (strncmp("---", param, 3) == 0)
57 			break;
58 
59 		/* ugly hack to skip over GMT in RESA */
60 		if (strncmp("GMT", param, 3) == 0 && *(start + 5) == 'h') {
61 			start = start + 4 + 0x100;
62 			continue;
63 		}
64 
65 		/* find the end of the token */
66 		{
67 			int tlen;
68 			char *next = start;
69 
70 			while (*next != '#' && *next != 0x00 && next < end)
71 				next++;
72 
73 			tlen = next - start - 1;
74 
75 			if (cb) {
76 				status = cb(userdata, start - 2, tlen);
77 				if (status != SANE_STATUS_GOOD) {
78 					delayed_status = status;
79 				}
80 			}
81 
82 			start = next;
83 		}
84 	}
85 
86 	if (delayed_status != SANE_STATUS_GOOD)
87 		return delayed_status;
88 
89 	return status;
90 }
91 
92 static SANE_Bool
esci2_check_header(const char * cmd,const char * buf,unsigned int * more)93 esci2_check_header(const char *cmd, const char *buf, unsigned int *more)
94 {
95 	int err;
96 
97 	*more = 0;
98 
99 	if (strncmp(cmd, buf, 4) != 0) {
100 
101 		if (strncmp("UNKN", buf, 4) == 0) {
102 			DBG(1, "UNKN reply code received\n");
103 		} else if (strncmp("INVD", buf, 4) == 0) {
104 			DBG(1, "INVD reply code received\n");
105 		} else {
106 			DBG(1, "%c%c%c%c, unexpected reply code\n", buf[0], buf[1], buf[2], buf[3]);
107 		}
108 
109 		return 0;
110 	}
111 
112 	/* INFOx0000100#.... */
113 
114 	/* read the answer len */
115 	if (buf[4] != 'x') {
116 		DBG(1, "unknown type in header: %c\n", buf[4]);
117 		return 0;
118 	}
119 
120 	err = sscanf(&buf[5], "%7x#", more);
121 	if (err != 1) {
122 		DBG(1, "cannot decode length from header\n");
123 		return 0;
124 	}
125 
126 	return 1;
127 }
128 
esci2_cmd(epsonds_scanner * s,char * cmd,size_t len,char * payload,size_t plen,void * userdata,SANE_Status (* cb)(void * userdata,char * token,int len))129 static SANE_Status esci2_cmd(epsonds_scanner* s,
130 	char *cmd, size_t len,
131 	char *payload, size_t plen,
132 	void *userdata, SANE_Status (*cb)(void *userdata, char *token, int len))
133 {
134 	SANE_Status status;
135 	unsigned int more;
136 	char header[13], rbuf[64]; /* add one more byte for header buffer to correct buffer overflow issue,*/
137 
138 	DBG(8, "%s: %4s len %lu, payload len: %lu\n", __func__, cmd, len, plen);
139 
140 	memset(header, 0x00, sizeof(header));
141 	memset(rbuf, 0x00, sizeof(rbuf));
142 
143 	// extra safety check, will not happen
144 	if (len != 12) {
145 		DBG(1, "%s: command has wrong size (%lu != 12)\n", __func__, len);
146 		return SANE_STATUS_INVAL;
147 	}
148 
149 	// merge ParameterBlock size
150 	sprintf(header, "%4.4sx%07x", cmd, (unsigned int)plen);
151 
152 	// send RequestBlock, request immediate response if there's no payload
153 	status = eds_txrx(s, header, len, rbuf, (plen > 0) ? 0 : 64);
154 	if (status != SANE_STATUS_GOOD) {
155 		return status;
156 	}
157 
158 	/* send ParameterBlock, request response */
159 	if (plen) {
160 
161 		DBG(8, " %12.12s (%lu)\n", header, plen);
162 
163 		status = eds_txrx(s, payload, plen, rbuf, 64);
164 		if (status != SANE_STATUS_GOOD) {
165 			return status;
166 		}
167 	}
168 
169 	/* rxbuf holds the DataHeaderBlock, which should be
170 	 * parsed to know if we need to read more data
171 	 */
172 	if (!esci2_check_header(cmd, rbuf, &more)) {
173 		return SANE_STATUS_IO_ERROR;
174 	}
175 
176 	/* parse the received header block */
177 	if (cb) {
178 		status = esci2_parse_block(rbuf + 12, 64 - 12, userdata, cb);
179 		if (status != SANE_STATUS_GOOD && status != SANE_STATUS_DEVICE_BUSY) {
180 			DBG(1, "%s: %4s error while parsing received header\n", __func__, cmd);
181 		}
182 	}
183 
184 	/* header valid, get the data block if present */
185 	if (more) {
186 
187 		char *pbuf = malloc(more);
188 		if (pbuf) {
189 
190 			if (s->hw->connection == SANE_EPSONDS_NET) {
191 				epsonds_net_request_read(s, more);
192 			}
193 
194 			ssize_t read = eds_recv(s, pbuf, more, &status);
195 			if (read != more) {
196 				free(pbuf);
197 				return SANE_STATUS_IO_ERROR;
198 			}
199 
200 			/* parse the received data block */
201 			if (cb) {
202 				status = esci2_parse_block(pbuf, more, userdata, cb);
203 				if (status != SANE_STATUS_GOOD) {
204 					DBG(1, "%s: %4s error while parsing received data block\n", __func__, cmd);
205 				}
206 			}
207 
208 			free(pbuf);
209 
210 		} else {
211 			return SANE_STATUS_NO_MEM;
212 		}
213 	}
214 
215 	return status;
216 }
217 
esci2_cmd_simple(epsonds_scanner * s,char * cmd,SANE_Status (* cb)(void * userdata,char * token,int len))218 static SANE_Status esci2_cmd_simple(epsonds_scanner* s, char *cmd, SANE_Status (*cb)(void *userdata, char *token, int len))
219 {
220 	return esci2_cmd(s, cmd, 12, NULL, 0, s, cb);
221 }
222 
esci2_fin(epsonds_scanner * s)223 SANE_Status esci2_fin(epsonds_scanner *s)
224 {
225 	SANE_Status status;
226 
227 	DBG(5, "%s\n", __func__);
228 
229 	status = esci2_cmd_simple(s, "FIN x0000000", NULL);
230 	s->locked = 0;
231 	return status;
232 }
233 
esci2_can(epsonds_scanner * s)234 SANE_Status esci2_can(epsonds_scanner *s)
235 {
236 	return esci2_cmd_simple(s, "CAN x0000000", NULL);
237 }
238 
decode_value(char * buf,int len)239 static int decode_value(char *buf, int len)
240 {
241 	char tmp[10];
242 
243 	memcpy(tmp, buf, len);
244 	tmp[len] = '\0';
245 
246 	if (buf[0] == 'd' && len == 4) {
247 		return strtol(buf + 1, NULL, 10);
248 	} else if (buf[0] == 'i' && len == 8) {
249 		return strtol(buf + 1, NULL, 10);
250 	} else if (buf[0] == 'x' && len == 8) {
251 		return strtol(buf + 1, NULL, 16);
252 	} else if (buf[0] == 'h' && len == 4) {
253 		return strtol(buf + 1, NULL, 16);
254 	}
255 
256 	return -1;
257 }
258 
259 /* h000 */
decode_binary(char * buf,int len)260 static char *decode_binary(char *buf, int len)
261 {
262 	char tmp[6];
263 	int hl;
264 
265 	memcpy(tmp, buf, 4);
266 	tmp[4] = '\0';
267 	len -= 4;
268 
269 	if (buf[0] != 'h')
270 		return NULL;
271 
272 	hl = strtol(tmp + 1, NULL, 16);
273 	if (hl > len) hl = len;
274 	if (hl) {
275 
276 		char *v = malloc(hl + 1);
277 		memcpy(v, buf + 4, hl);
278 		v[hl] = '\0';
279 
280 		return v;
281 	}
282 
283 	return NULL;
284 }
285 
decode_string(char * buf,int len)286 static char *decode_string(char *buf, int len)
287 {
288 	char *p, *s = decode_binary(buf, len);
289 	if (s == NULL)
290 		return NULL;
291 
292 	/* trim white space at the end */
293 	p = s + strlen(s);
294 	while (*--p == ' ')
295 		*p = '\0';
296 
297 	return s;
298 }
299 
debug_token(int level,const char * func,char * token,int len)300 static void debug_token(int level, const char *func, char *token, int len)
301 {
302 	char *tdata = malloc(len + 1);
303 	memcpy(tdata, token + 3, len);
304 	tdata[len] = '\0';
305 
306 	DBG(level, "%s: %3.3s / %s / %d\n", func, token, tdata, len);
307 
308 	free(tdata);
309 }
310 
info_cb(void * userdata,char * token,int len)311 static SANE_Status info_cb(void *userdata, char *token, int len)
312 {
313 	epsonds_scanner *s = (epsonds_scanner *)userdata;
314 	char *value;
315 
316 	if (DBG_LEVEL >= 11) {
317 		debug_token(DBG_LEVEL, __func__, token, len);
318 	}
319 
320 	/* pointer to the token's value */
321 	value = token + 3;
322 
323 	/* nrd / nrdBUSY */
324 
325 	if (strncmp("nrd", token, 3) == 0) {
326 		if (strncmp("BUSY", value, 4) == 0) {
327 			return SANE_STATUS_DEVICE_BUSY;
328 		}
329 	}
330 
331 	if (strncmp("PRD", token, 3) == 0) {
332 		free(s->hw->model);
333 		s->hw->model = decode_string(value, len);
334 		s->hw->sane.model = s->hw->model;
335 		DBG(1, " product: %s\n", s->hw->model);
336 		/* we will free the string later */
337 	}
338 
339 	if (strncmp("VER", token, 3) == 0) {
340 		char *v = decode_string(value, len);
341 		DBG(1, " version: %s\n", v);
342 		free(v);
343 	}
344 
345 	if (strncmp("S/N", token, 3) == 0) {
346 		char *v = decode_string(value, len);
347 		DBG(1, "  serial: %s\n", v);
348 		free(v);
349 	}
350 
351 	if (strncmp("ADF", token, 3) == 0) {
352 
353 		s->hw->has_adf = 1;
354 
355 		if (len == 8) {
356 
357 			if (strncmp("TYPEPAGE", value, len) == 0) {
358 				DBG(1, "     ADF: page type\n");
359 			}
360 
361 			if (strncmp("TYPEFEED", value, len) == 0) {
362 				DBG(1, "     ADF: sheet feed type\n");
363 			}
364 
365 			if (strncmp("DPLX1SCN", value, len) == 0) {
366 				DBG(1, "     ADF: duplex single pass\n");
367 				s->hw->adf_singlepass = 1;
368 			}
369 
370 			if (strncmp("DPLX2SCN", value, len) == 0) {
371 				DBG(1, "     ADF: duplex double pass\n");
372 				s->hw->adf_singlepass = 0;
373 			}
374 
375 			if (strncmp("FORDPF1N", value, len) == 0) {
376 				DBG(1, "     ADF: order is 1 to N\n");
377 			}
378 
379 			if (strncmp("FORDPFN1", value, len) == 0) {
380 				DBG(1, "     ADF: order is N to 1\n");
381 			}
382 
383 			if (strncmp("ALGNLEFT", value, len) == 0) {
384 				DBG(1, "     ADF: left aligned\n");
385 				s->hw->adf_alignment = 0;
386 			}
387 
388 			if (strncmp("ALGNCNTR", value, len) == 0) {
389 				DBG(1, "     ADF: center aligned\n");
390 				s->hw->adf_alignment = 1;
391 			}
392 
393 			if (strncmp("ALGNRIGT", value, len) == 0) {
394 				DBG(1, "     ADF: right aligned (not supported!)\n");
395 				s->hw->adf_alignment = 2;
396 			}
397 		}
398 
399 		if (len == 4) {
400 
401 			if (strncmp("PREF", value, len) == 0) {
402 				DBG(1, "     ADF: auto pre-feed\n");
403 			}
404 
405 			if (strncmp("ASCN", value, len) == 0) {
406 				DBG(1, "     ADF: auto scan\n");
407 			}
408 
409 			if (strncmp("RCVR", value, len) == 0) {
410 				DBG(1, "     ADF: auto recovery\n");
411 			}
412 		}
413 
414 		if (len == 20) {
415 
416 			/* ADFAREAi0000850i0001400 */
417 
418 			if (strncmp("AREA", value, 4) == 0) {
419 
420 				int min = decode_value(value + 4, 8);
421 				int max = decode_value(value + 4 + 8, 8);
422 
423 				DBG(1, "     ADF: area %dx%d @ 100dpi\n", min, max);
424 			}
425 
426 			if (strncmp("AMIN", value, 4) == 0) {
427 
428 				int min = decode_value(value + 4, 8);
429 				int max = decode_value(value + 4 + 8, 8);
430 
431 				DBG(1, "     ADF: min %dx%d @ 100dpi\n", min, max);
432 			}
433 
434 			if (strncmp("AMAX", value, 4) == 0) {
435 
436 				int min = decode_value(value + 4, 8);
437 				int max = decode_value(value + 4 + 8, 8);
438 
439 				DBG(1, "     ADF: max %dx%d @ 100dpi\n", min, max);
440 
441 				eds_set_adf_area(s->hw,	min, max, 100);
442 			}
443 		}
444 
445 		if (len == 12) {
446 
447 			/* RESOi0000600 */
448 
449 			if (strncmp("RESO", value, 4) == 0) {
450 
451 				int res = decode_value(value + 4, 8);
452 
453 				DBG(1, "     ADF: basic resolution is %d dpi\n", res);
454 			}
455 
456 			/* OVSNd025d035 */
457 
458 			if (strncmp("OVSN", value, 4) == 0) {
459 
460 				int x = decode_value(value + 4, 4);
461 				int y = decode_value(value + 4 + 4, 4);
462 
463 				DBG(1, "     ADF: overscan %dx%d @ 100dpi\n", x, y);
464 			}
465 		}
466 	}
467 
468 	if (strncmp("FB ", token, 3) == 0) {
469 
470 		s->hw->has_fb = 1;
471 
472 		if (len == 20) {
473 
474 			/* AREAi0000850i0001400 */
475 			if (strncmp("AREA", value, 4) == 0) {
476 
477 				int min = decode_value(value + 4, 8);
478 				int max = decode_value(value + 4 + 8, 8);
479 
480 				DBG(1, "      FB: area %dx%d @ 100dpi\n", min, max);
481 
482 				eds_set_fbf_area(s->hw,	min, max, 100);
483 			}
484 		}
485 
486 		if (len == 8) {
487 
488 			if (strncmp("ALGNLEFT", value, len) == 0) {
489 				DBG(1, "      FB: left aligned\n");
490 				s->hw->fbf_alignment = 0;
491 			}
492 
493 			if (strncmp("ALGNCNTR", value, len) == 0) {
494 				DBG(1, "      FB: center aligned\n");
495 				s->hw->fbf_alignment = 1;
496 			}
497 
498 			if (strncmp("ALGNRIGT", value, len) == 0) {
499 				DBG(1, "      FB: right aligned (not supported!)\n");
500 				s->hw->fbf_alignment = 2;
501 			}
502 		}
503 
504 		if (len == 12) {
505 
506 			/* RESOi0000600 */
507 
508 			if (strncmp("RESO", value, 4) == 0) {
509 
510 				int res = decode_value(value + 4, 8);
511 
512 				DBG(1, "      FB: basic resolution is %d dpi\n", res);
513 			}
514 
515 			/* OVSNd025d035 */
516 
517 			if (strncmp("OVSN", value, 4) == 0) {
518 
519 				int x = decode_value(value + 4, 4);
520 				int y = decode_value(value + 4 + 4, 4);
521 
522 				DBG(1, "      FB: overscan %dx%d @ 100dpi\n", x, y);
523 			}
524 		}
525 
526 		if (len == 4) {
527 
528 			if (strncmp("DETX", value, len) == 0) {
529 				DBG(1, "      FB: paper width detection\n");
530 			}
531 
532 			if (strncmp("DETY", value, len) == 0) {
533 				DBG(1, "      FB: paper height detection\n");
534 			}
535 		}
536 	}
537 
538 	return SANE_STATUS_GOOD;
539 }
540 
esci2_info(epsonds_scanner * s)541 SANE_Status esci2_info(epsonds_scanner *s)
542 {
543 	SANE_Status status;
544 	int i = 4;
545 
546 	DBG(1, "= gathering device information\n");
547 
548 	do {
549 		status = esci2_cmd_simple(s, "INFOx0000000", &info_cb);
550 		if (status == SANE_STATUS_DEVICE_BUSY) {
551 			sleep(2);
552 		}
553 
554 		i--;
555 
556 	} while (status == SANE_STATUS_DEVICE_BUSY && i);
557 
558 	return status;
559 }
560 
561 /* CAPA */
562 
capa_cb(void * userdata,char * token,int len)563 static SANE_Status capa_cb(void *userdata, char *token, int len)
564 {
565 	epsonds_scanner *s = (epsonds_scanner *)userdata;
566 
567 	char *value = token + 3;
568 
569 	if (DBG_LEVEL >= 11) {
570 		debug_token(DBG_LEVEL, __func__, token, len);
571 	}
572 
573 	if (len == 4) {
574 
575 		if (strncmp("ADFDPLX", token, 3 + 4) == 0) {
576 			DBG(1, "     ADF: duplex\n");
577 			s->hw->adf_is_duplex = 1;
578 		}
579 
580 		if (strncmp("ADFSKEW", token, 3 + 4) == 0) {
581 			DBG(1, "     ADF: skew correction\n");
582 			s->hw->adf_has_skew = 1;
583 		}
584 
585 		if (strncmp("ADFOVSN", token, 3 + 4) == 0) {
586 			DBG(1, "     ADF: overscan\n");
587 		}
588 
589 		if (strncmp("ADFPEDT", token, 3 + 4) == 0) {
590 			DBG(1, "     ADF: paper end detection\n");
591 		}
592 
593 		if (strncmp("ADFLOAD", token, 3 + 4) == 0) {
594 			DBG(1, "     ADF: paper load\n");
595 			s->hw->adf_has_load = 1;
596 		}
597 
598 		if (strncmp("ADFEJCT", token, 3 + 4) == 0) {
599 			DBG(1, "     ADF: paper eject\n");
600 			s->hw->adf_has_eject = 1;
601 		}
602 
603 		if (strncmp("ADFCRP ", token, 3 + 4) == 0) {
604 			DBG(1, "     ADF: image cropping\n");
605 		}
606 
607 		if (strncmp("ADFFAST", token, 3 + 4) == 0) {
608 			DBG(1, "     ADF: fast mode available\n");
609 		}
610 
611 		if (strncmp("ADFDFL1", token, 3 + 4) == 0) {
612 			DBG(1, "     ADF: double feed detection\n");
613 			s->hw->adf_has_dfd = 1;
614 		}
615 	}
616 
617 	if (len == 8 && strncmp("ADFDFL1DFL2", token, 3 + 4) == 0) {
618 		DBG(1, "     ADF: double feed detection (high sensitivity)\n");
619 		s->hw->adf_has_dfd = 2;
620 	}
621 
622 	if (strncmp("FMT", token, 3) == 0) {
623 
624 		/* a bit ugly... */
625 
626 		if (len >= 8) {
627 			if (strncmp("RAW ", value + 4, 4) == 0) {
628 				s->hw->has_raw = 1;
629 			}
630 		}
631 
632 		if (len >= 12) {
633 			if (strncmp("RAW ", value + 8, 4) == 0) {
634 				s->hw->has_raw = 1;
635 			}
636 		}
637 	}
638 
639 	/* RSMRANGi0000050i0000600 */
640 
641 	if (strncmp("RSMRANG", token, 3 + 4) == 0) {
642 
643 		char *p = token + 3 + 4;
644 
645 		if (p[0] == 'i') {
646 
647 			int min = decode_value(p, 8);
648 			int max = decode_value(p + 8, 8);
649 
650 			eds_set_resolution_range(s->hw, min, max);
651 
652 			DBG(1, "resolution min/max %d/%d\n", min, max);
653 		}
654 	}
655 
656 	/* RSMLISTi0000300i0000600 */
657 
658 	if (strncmp("RSMLIST", token, 3 + 4) == 0) {
659 
660 		char *p = token + 3 + 4;
661 
662 		if (p[0] == 'i') {
663 
664 			int i;
665 			int count = (len - 4) / 8;
666 
667 			for (i = 0; i < count; i++) {
668 
669 				eds_add_resolution(s->hw, decode_value(p, 8));
670 				p += 8;
671 			}
672 		}
673 	}
674 
675 	return SANE_STATUS_GOOD;
676 }
677 
esci2_capa(epsonds_scanner * s)678 SANE_Status esci2_capa(epsonds_scanner *s)
679 {
680 	return esci2_cmd_simple(s, "CAPAx0000000", &capa_cb);
681 }
682 
683 /* STAT */
684 
stat_cb(void * userdata,char * token,int len)685 static SANE_Status stat_cb(void *userdata, char *token, int len)
686 {
687 /*
688 	epsonds_scanner *s = (epsonds_scanner *)userdata;
689 	char *value = token + 3;
690 */
691 	userdata = userdata;
692 
693 	if (DBG_LEVEL >= 11) {
694 		debug_token(DBG_LEVEL, __func__, token, len);
695 	}
696 
697 	return SANE_STATUS_GOOD;
698 }
699 
esci2_stat(epsonds_scanner * s)700 SANE_Status esci2_stat(epsonds_scanner *s)
701 {
702 	return esci2_cmd_simple(s, "STATx0000000", &stat_cb);
703 }
704 
705 /* RESA */
706 
resa_cb(void * userdata,char * token,int len)707 static SANE_Status resa_cb(void *userdata, char *token, int len)
708 {
709 	/* epsonds_scanner *s = (epsonds_scanner *)userdata; */
710 
711 	userdata = userdata;
712 
713 	if (DBG_LEVEL >= 11) {
714 		debug_token(DBG_LEVEL, __func__, token, len);
715 	}
716 
717 	return SANE_STATUS_GOOD;
718 }
719 
esci2_resa(epsonds_scanner * s)720 SANE_Status esci2_resa(epsonds_scanner *s)
721 {
722 	return esci2_cmd_simple(s, "RESAx0000000", &resa_cb);
723 }
724 
725 /* PARA */
726 
para_cb(void * userdata,char * token,int len)727 static SANE_Status para_cb(void *userdata, char *token, int len)
728 {
729 	if (DBG_LEVEL >= 11) {
730 		debug_token(DBG_LEVEL, __func__, token, len);
731 	}
732 
733 	userdata = userdata;
734 
735 	if (strncmp("par", token, 3) == 0) {
736 		if (strncmp("FAIL", token + 3, 4) == 0) {
737 			DBG(1, "%s: parameter setting failed\n", __func__);
738 			return SANE_STATUS_INVAL;
739 		}
740 	}
741 
742 	return SANE_STATUS_GOOD;
743 }
744 
esci2_para(epsonds_scanner * s,char * parameters)745 SANE_Status esci2_para(epsonds_scanner *s, char *parameters)
746 {
747 	DBG(8, "%s: %s\n", __func__, parameters);
748 	return esci2_cmd(s, "PARAx0000000", 12, parameters, strlen(parameters), NULL, &para_cb);
749 }
750 
esci2_mech(epsonds_scanner * s,char * parameters)751 SANE_Status esci2_mech(epsonds_scanner *s, char *parameters)
752 {
753 	DBG(8, "%s: %s\n", __func__, parameters);
754 	return esci2_cmd(s, "MECHx0000000", 12, parameters, strlen(parameters), NULL, &para_cb);
755 }
756 
esci2_trdt(epsonds_scanner * s)757 SANE_Status esci2_trdt(epsonds_scanner *s)
758 {
759 	return esci2_cmd_simple(s, "TRDTx0000000", NULL);
760 }
761 
762 
img_cb(void * userdata,char * token,int len)763 static SANE_Status img_cb(void *userdata, char *token, int len)
764 {
765 	struct epsonds_scanner *s = userdata;
766 
767 	if (DBG_LEVEL >= 11) {
768 		debug_token(DBG_LEVEL, __func__, token, len);
769 	}
770 
771 	/* psti0000256i0000000i0000945 / 24 */
772 
773 	/* integer comparison first so it's faster */
774 	if (len == 24 && strncmp("pst", token, 3) == 0) {
775 
776 		s->dummy = decode_value(token + 3 + 8, 8);
777 
778 		DBG(10, "%s: pst width: %d, height: %d, dummy: %d\n",
779 			__func__,
780 			decode_value(token + 3, 8),
781 			decode_value(token + 3 + 8 + 8, 8),
782 			s->dummy);
783 
784 		return SANE_STATUS_GOOD;
785 	}
786 
787 	if (len == 16 && strncmp("pen", token, 3) == 0) {
788 		DBG(10, "%s: page end\n", __func__);
789 		s->eof = 1;
790 		return SANE_STATUS_EOF;
791 	}
792 
793 	/* typIMGA or typIMGB */
794 	if (len == 4 && strncmp("typ", token, 3) == 0) {
795 
796 		if (token[6] == 'B')
797 			s->backside = 1;
798 		else
799 			s->backside = 0;
800 
801 		return SANE_STATUS_GOOD;
802 	}
803 
804 	if (strncmp("err", token, 3) == 0) {
805 
806 		char *option = token + 3;	/* ADF, TPU, FB */
807 		char *cause = token + 3 + 4;	/* OPN, PJ, PE, ERR, LTF, LOCK, DFED, DTCL, AUT, PERM */
808 
809 		s->scanning = 0;
810 
811 		DBG(1, "%s: error on option %3.3s, cause %4.4s\n",
812 			__func__, option, cause);
813 
814 		if (cause[0] == 'P' && cause[1] == 'J')
815 			return SANE_STATUS_JAMMED;
816 
817 		if (cause[0] == 'P' && cause[1] == 'E')
818 			return SANE_STATUS_NO_DOCS;
819 
820 		if (cause[0] == 'O' && cause[1] == 'P' && cause[2] == 'N')
821 			return SANE_STATUS_COVER_OPEN;
822 
823 		return SANE_STATUS_IO_ERROR;
824 	}
825 
826 	if (len == 4 && strncmp("atnCAN ", token, 3 + 4) == 0) {
827 		DBG(1, "%s: cancel request\n", __func__);
828 		s->canceling = 1;
829 		s->scanning = 0;
830 		return SANE_STATUS_CANCELLED;
831 	}
832 
833 	if (len == 4 && strncmp("lftd000", token, 3 + 4) == 0) {
834 		s->scanning = 0;
835 	}
836 
837 	return SANE_STATUS_GOOD;
838 }
839 
840 
841 SANE_Status
esci2_img(struct epsonds_scanner * s,SANE_Int * length)842 esci2_img(struct epsonds_scanner *s, SANE_Int *length)
843 {
844 	SANE_Status status = SANE_STATUS_GOOD;
845 	SANE_Status parse_status;
846 	unsigned int more;
847 	ssize_t read;
848 
849 	*length = 0;
850 
851 	if (s->canceling)
852 		return SANE_STATUS_CANCELLED;
853 
854 	/* request image data */
855 	eds_send(s, "IMG x0000000", 12, &status, 64);
856 	if (status != SANE_STATUS_GOOD) {
857 		return status;
858 	}
859 
860 	/* receive DataHeaderBlock */
861 	memset(s->buf, 0x00, 64);
862 	eds_recv(s, s->buf, 64, &status);
863 	if (status != SANE_STATUS_GOOD) {
864 		return status;
865 	}
866 
867 	/* check if we need to read any image data */
868 	more = 0;
869 	if (!esci2_check_header("IMG ", (char *)s->buf, &more)) {
870 		return SANE_STATUS_IO_ERROR;
871 	}
872 
873 	/* this handles eof and errors */
874 	parse_status = esci2_parse_block((char *)s->buf + 12, 64 - 12, s, &img_cb);
875 
876 	/* no more data? return using the status of the esci2_parse_block
877 	 * call, which might hold other error conditions.
878 	 */
879 	if (!more) {
880 		return parse_status;
881 	}
882 
883 	/* more data than was accounted for in s->buf */
884 	if (more > s->bsz) {
885 		return SANE_STATUS_IO_ERROR;
886 	}
887 
888 	/* ALWAYS read image data */
889 	if (s->hw->connection == SANE_EPSONDS_NET) {
890 		epsonds_net_request_read(s, more);
891 	}
892 
893 	read = eds_recv(s, s->buf, more, &status);
894 	if (status != SANE_STATUS_GOOD) {
895 		return status;
896 	}
897 
898 	if (read != more) {
899 		return SANE_STATUS_IO_ERROR;
900 	}
901 
902 	/* handle esci2_parse_block errors */
903 	if (parse_status != SANE_STATUS_GOOD) {
904 		return parse_status;
905 	}
906 
907 	DBG(15, "%s: read %lu bytes, status: %d\n", __func__, (unsigned long) read, status);
908 
909 	*length = read;
910 
911 	if (s->canceling) {
912 		return SANE_STATUS_CANCELLED;
913 	}
914 
915 	return SANE_STATUS_GOOD;
916 }
917