1141cc406Sopenharmony_ci/*
2141cc406Sopenharmony_ci * epson2_net.c - SANE library for Epson scanners.
3141cc406Sopenharmony_ci *
4141cc406Sopenharmony_ci * Copyright (C) 2006 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
18141cc406Sopenharmony_ci#ifdef HAVE_SYS_SELECT_H
19141cc406Sopenharmony_ci#include <sys/select.h>
20141cc406Sopenharmony_ci#endif
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci#include "sane/sane.h"
23141cc406Sopenharmony_ci#include "sane/saneopts.h"
24141cc406Sopenharmony_ci#include "sane/sanei_tcp.h"
25141cc406Sopenharmony_ci#include "sane/sanei_config.h"
26141cc406Sopenharmony_ci#include "sane/sanei_backend.h"
27141cc406Sopenharmony_ci
28141cc406Sopenharmony_ci#include "epson2.h"
29141cc406Sopenharmony_ci#include "epson2_net.h"
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci#include "byteorder.h"
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci#include "sane/sanei_debug.h"
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_cistatic ssize_t
36141cc406Sopenharmony_cisanei_epson_net_read_raw(Epson_Scanner *s, unsigned char *buf, ssize_t wanted,
37141cc406Sopenharmony_ci		       SANE_Status *status)
38141cc406Sopenharmony_ci{
39141cc406Sopenharmony_ci	int ready;
40141cc406Sopenharmony_ci	ssize_t read = -1;
41141cc406Sopenharmony_ci	fd_set readable;
42141cc406Sopenharmony_ci	struct timeval tv;
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci	tv.tv_sec = 10;
45141cc406Sopenharmony_ci	tv.tv_usec = 0;
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci	FD_ZERO(&readable);
48141cc406Sopenharmony_ci	FD_SET(s->fd, &readable);
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ci	ready = select(s->fd + 1, &readable, NULL, NULL, &tv);
51141cc406Sopenharmony_ci	if (ready > 0) {
52141cc406Sopenharmony_ci		read = sanei_tcp_read(s->fd, buf, wanted);
53141cc406Sopenharmony_ci	} else {
54141cc406Sopenharmony_ci		DBG(15, "%s: select failed: %d\n", __func__, ready);
55141cc406Sopenharmony_ci	}
56141cc406Sopenharmony_ci
57141cc406Sopenharmony_ci	*status = SANE_STATUS_GOOD;
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_ci	if (read < wanted) {
60141cc406Sopenharmony_ci		*status = SANE_STATUS_IO_ERROR;
61141cc406Sopenharmony_ci	}
62141cc406Sopenharmony_ci
63141cc406Sopenharmony_ci	return read;
64141cc406Sopenharmony_ci}
65141cc406Sopenharmony_ci
66141cc406Sopenharmony_cistatic ssize_t
67141cc406Sopenharmony_cisanei_epson_net_read_buf(Epson_Scanner *s, unsigned char *buf, ssize_t wanted,
68141cc406Sopenharmony_ci		       SANE_Status * status)
69141cc406Sopenharmony_ci{
70141cc406Sopenharmony_ci	ssize_t read = 0;
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci	DBG(23, "%s: reading up to %lu from buffer at %p, %lu available\n",
73141cc406Sopenharmony_ci		__func__, (u_long) wanted, (void *) s->netptr, (u_long) s->netlen);
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci	if ((size_t) wanted > s->netlen) {
76141cc406Sopenharmony_ci		*status = SANE_STATUS_IO_ERROR;
77141cc406Sopenharmony_ci		wanted = s->netlen;
78141cc406Sopenharmony_ci	}
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_ci	memcpy(buf, s->netptr, wanted);
81141cc406Sopenharmony_ci	read = wanted;
82141cc406Sopenharmony_ci
83141cc406Sopenharmony_ci	s->netptr += read;
84141cc406Sopenharmony_ci	s->netlen -= read;
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci	if (s->netlen == 0) {
87141cc406Sopenharmony_ci		DBG(23, "%s: freeing %p\n", __func__, (void *) s->netbuf);
88141cc406Sopenharmony_ci		free(s->netbuf);
89141cc406Sopenharmony_ci		s->netbuf = s->netptr = NULL;
90141cc406Sopenharmony_ci		s->netlen = 0;
91141cc406Sopenharmony_ci	}
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ci	return read;
94141cc406Sopenharmony_ci}
95141cc406Sopenharmony_ci
96141cc406Sopenharmony_cissize_t
97141cc406Sopenharmony_cisanei_epson_net_read(Epson_Scanner *s, unsigned char *buf, ssize_t wanted,
98141cc406Sopenharmony_ci		       SANE_Status * status)
99141cc406Sopenharmony_ci{
100141cc406Sopenharmony_ci	if (wanted < 0) {
101141cc406Sopenharmony_ci		*status = SANE_STATUS_INVAL;
102141cc406Sopenharmony_ci		return 0;
103141cc406Sopenharmony_ci	}
104141cc406Sopenharmony_ci
105141cc406Sopenharmony_ci	size_t size;
106141cc406Sopenharmony_ci	ssize_t read = 0;
107141cc406Sopenharmony_ci	unsigned char header[12];
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci	/* read from remainder of buffer */
110141cc406Sopenharmony_ci	if (s->netptr) {
111141cc406Sopenharmony_ci		return sanei_epson_net_read_buf(s, buf, wanted, status);
112141cc406Sopenharmony_ci	}
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci	/* receive net header */
115141cc406Sopenharmony_ci	read = sanei_epson_net_read_raw(s, header, 12, status);
116141cc406Sopenharmony_ci	if (read != 12) {
117141cc406Sopenharmony_ci		return 0;
118141cc406Sopenharmony_ci	}
119141cc406Sopenharmony_ci
120141cc406Sopenharmony_ci	/* validate header */
121141cc406Sopenharmony_ci	if (header[0] != 'I' || header[1] != 'S') {
122141cc406Sopenharmony_ci		DBG(1, "header mismatch: %02X %02x\n", header[0], header[1]);
123141cc406Sopenharmony_ci		*status = SANE_STATUS_IO_ERROR;
124141cc406Sopenharmony_ci		return 0;
125141cc406Sopenharmony_ci	}
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ci	/* parse payload size */
128141cc406Sopenharmony_ci	size = be32atoh(&header[6]);
129141cc406Sopenharmony_ci
130141cc406Sopenharmony_ci	*status = SANE_STATUS_GOOD;
131141cc406Sopenharmony_ci
132141cc406Sopenharmony_ci	if (!s->netbuf) {
133141cc406Sopenharmony_ci		DBG(15, "%s: direct read\n", __func__);
134141cc406Sopenharmony_ci		DBG(23, "%s: wanted = %lu, available = %lu\n", __func__,
135141cc406Sopenharmony_ci			(u_long) wanted, (u_long) size);
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci		if ((size_t) wanted > size) {
138141cc406Sopenharmony_ci			wanted = size;
139141cc406Sopenharmony_ci		}
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_ci		read = sanei_epson_net_read_raw(s, buf, wanted, status);
142141cc406Sopenharmony_ci	} else {
143141cc406Sopenharmony_ci		DBG(15, "%s: buffered read\n", __func__);
144141cc406Sopenharmony_ci		DBG(23, "%s: bufferable = %lu, available = %lu\n", __func__,
145141cc406Sopenharmony_ci			(u_long) s->netlen, (u_long) size);
146141cc406Sopenharmony_ci
147141cc406Sopenharmony_ci		if (s->netlen > size) {
148141cc406Sopenharmony_ci			s->netlen = size;
149141cc406Sopenharmony_ci		}
150141cc406Sopenharmony_ci
151141cc406Sopenharmony_ci		/* fill buffer */
152141cc406Sopenharmony_ci		read = sanei_epson_net_read_raw(s, s->netbuf, s->netlen, status);
153141cc406Sopenharmony_ci		s->netptr = s->netbuf;
154141cc406Sopenharmony_ci		s->netlen = (read > 0 ? read : 0);
155141cc406Sopenharmony_ci
156141cc406Sopenharmony_ci		/* copy wanted part */
157141cc406Sopenharmony_ci		read = sanei_epson_net_read_buf(s, buf, wanted, status);
158141cc406Sopenharmony_ci	}
159141cc406Sopenharmony_ci
160141cc406Sopenharmony_ci	return read;
161141cc406Sopenharmony_ci}
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_cisize_t
164141cc406Sopenharmony_cisanei_epson_net_write(Epson_Scanner *s, unsigned int cmd, const unsigned char *buf,
165141cc406Sopenharmony_ci			size_t buf_size, size_t reply_len, SANE_Status *status)
166141cc406Sopenharmony_ci{
167141cc406Sopenharmony_ci	unsigned char *h1, *h2, *payload;
168141cc406Sopenharmony_ci	unsigned char *packet = malloc(12 + 8 + buf_size);
169141cc406Sopenharmony_ci
170141cc406Sopenharmony_ci	if (!packet) {
171141cc406Sopenharmony_ci		*status = SANE_STATUS_NO_MEM;
172141cc406Sopenharmony_ci		return 0;
173141cc406Sopenharmony_ci	}
174141cc406Sopenharmony_ci
175141cc406Sopenharmony_ci	h1 = packet;
176141cc406Sopenharmony_ci	h2 = packet + 12;
177141cc406Sopenharmony_ci	payload = packet + 12 + 8;
178141cc406Sopenharmony_ci
179141cc406Sopenharmony_ci	if (reply_len) {
180141cc406Sopenharmony_ci		if (s->netbuf) {
181141cc406Sopenharmony_ci			DBG(23, "%s, freeing %p, %ld bytes unprocessed\n",
182141cc406Sopenharmony_ci				__func__, (void *) s->netbuf, (u_long) s->netlen);
183141cc406Sopenharmony_ci			free(s->netbuf);
184141cc406Sopenharmony_ci			s->netbuf = s->netptr = NULL;
185141cc406Sopenharmony_ci			s->netlen = 0;
186141cc406Sopenharmony_ci		}
187141cc406Sopenharmony_ci		s->netbuf = malloc(reply_len);
188141cc406Sopenharmony_ci		if (!s->netbuf) {
189141cc406Sopenharmony_ci			free(packet);
190141cc406Sopenharmony_ci			*status = SANE_STATUS_NO_MEM;
191141cc406Sopenharmony_ci			return 0;
192141cc406Sopenharmony_ci		}
193141cc406Sopenharmony_ci		s->netlen = reply_len;
194141cc406Sopenharmony_ci		DBG(24, "%s: allocated %lu bytes at %p\n", __func__,
195141cc406Sopenharmony_ci			(u_long) s->netlen, (void *) s->netbuf);
196141cc406Sopenharmony_ci	}
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_ci	DBG(24, "%s: cmd = %04x, buf = %p, buf_size = %lu, reply_len = %lu\n",
199141cc406Sopenharmony_ci		__func__, cmd, (void *) buf, (u_long) buf_size, (u_long) reply_len);
200141cc406Sopenharmony_ci
201141cc406Sopenharmony_ci	memset(h1, 0x00, 12);
202141cc406Sopenharmony_ci	memset(h2, 0x00, 8);
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_ci	h1[0] = 'I';
205141cc406Sopenharmony_ci	h1[1] = 'S';
206141cc406Sopenharmony_ci
207141cc406Sopenharmony_ci	h1[2] = cmd >> 8;
208141cc406Sopenharmony_ci	h1[3] = cmd;
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_ci	h1[4] = 0x00;
211141cc406Sopenharmony_ci	h1[5] = 0x0C; /* Don't know what's that */
212141cc406Sopenharmony_ci
213141cc406Sopenharmony_ci	DBG(24, "H1[0]: %02x %02x %02x %02x\n", h1[0], h1[1], h1[2], h1[3]);
214141cc406Sopenharmony_ci
215141cc406Sopenharmony_ci	if((cmd >> 8) == 0x20) {
216141cc406Sopenharmony_ci		htobe32a(&h1[6], buf_size + 8);
217141cc406Sopenharmony_ci
218141cc406Sopenharmony_ci		htobe32a(&h2[0], buf_size);
219141cc406Sopenharmony_ci		htobe32a(&h2[4], reply_len);
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_ci		DBG(24, "H1[6]: %02x %02x %02x %02x (%lu)\n", h1[6], h1[7], h1[8], h1[9], (u_long) (buf_size + 8));
222141cc406Sopenharmony_ci		DBG(24, "H2[0]: %02x %02x %02x %02x (%lu)\n", h2[0], h2[1], h2[2], h2[3], (u_long) buf_size);
223141cc406Sopenharmony_ci		DBG(24, "H2[4]: %02x %02x %02x %02x (%lu)\n", h2[4], h2[5], h2[6], h2[7], (u_long) reply_len);
224141cc406Sopenharmony_ci	}
225141cc406Sopenharmony_ci
226141cc406Sopenharmony_ci	if ((cmd >> 8) == 0x20 && (buf_size || reply_len)) {
227141cc406Sopenharmony_ci		if (buf_size)
228141cc406Sopenharmony_ci			memcpy(payload, buf, buf_size);
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_ci		sanei_tcp_write(s->fd, packet, 12 + 8 + buf_size);
231141cc406Sopenharmony_ci	}
232141cc406Sopenharmony_ci	else
233141cc406Sopenharmony_ci		sanei_tcp_write(s->fd, packet, 12);
234141cc406Sopenharmony_ci
235141cc406Sopenharmony_ci	free(packet);
236141cc406Sopenharmony_ci
237141cc406Sopenharmony_ci	*status = SANE_STATUS_GOOD;
238141cc406Sopenharmony_ci	return buf_size;
239141cc406Sopenharmony_ci}
240141cc406Sopenharmony_ci
241141cc406Sopenharmony_ciSANE_Status
242141cc406Sopenharmony_cisanei_epson_net_lock(struct Epson_Scanner *s)
243141cc406Sopenharmony_ci{
244141cc406Sopenharmony_ci	SANE_Status status;
245141cc406Sopenharmony_ci	unsigned char buf[1];
246141cc406Sopenharmony_ci
247141cc406Sopenharmony_ci	DBG(1, "%s\n", __func__);
248141cc406Sopenharmony_ci
249141cc406Sopenharmony_ci	sanei_epson_net_write(s, 0x2100, NULL, 0, 0, &status);
250141cc406Sopenharmony_ci	sanei_epson_net_read(s, buf, 1, &status);
251141cc406Sopenharmony_ci	return status;
252141cc406Sopenharmony_ci}
253141cc406Sopenharmony_ci
254141cc406Sopenharmony_ciSANE_Status
255141cc406Sopenharmony_cisanei_epson_net_unlock(struct Epson_Scanner *s)
256141cc406Sopenharmony_ci{
257141cc406Sopenharmony_ci	SANE_Status status;
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci	DBG(1, "%s\n", __func__);
260141cc406Sopenharmony_ci
261141cc406Sopenharmony_ci	sanei_epson_net_write(s, 0x2101, NULL, 0, 0, &status);
262141cc406Sopenharmony_ci/*	sanei_epson_net_read(s, buf, 1, &status); */
263141cc406Sopenharmony_ci	return status;
264141cc406Sopenharmony_ci}
265