xref: /third_party/backends/backend/epson2_net.c (revision 141cc406)
1/*
2 * epson2_net.c - SANE library for Epson scanners.
3 *
4 * Copyright (C) 2006 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
18#ifdef HAVE_SYS_SELECT_H
19#include <sys/select.h>
20#endif
21
22#include "sane/sane.h"
23#include "sane/saneopts.h"
24#include "sane/sanei_tcp.h"
25#include "sane/sanei_config.h"
26#include "sane/sanei_backend.h"
27
28#include "epson2.h"
29#include "epson2_net.h"
30
31#include "byteorder.h"
32
33#include "sane/sanei_debug.h"
34
35static ssize_t
36sanei_epson_net_read_raw(Epson_Scanner *s, unsigned char *buf, ssize_t wanted,
37		       SANE_Status *status)
38{
39	int ready;
40	ssize_t read = -1;
41	fd_set readable;
42	struct timeval tv;
43
44	tv.tv_sec = 10;
45	tv.tv_usec = 0;
46
47	FD_ZERO(&readable);
48	FD_SET(s->fd, &readable);
49
50	ready = select(s->fd + 1, &readable, NULL, NULL, &tv);
51	if (ready > 0) {
52		read = sanei_tcp_read(s->fd, buf, wanted);
53	} else {
54		DBG(15, "%s: select failed: %d\n", __func__, ready);
55	}
56
57	*status = SANE_STATUS_GOOD;
58
59	if (read < wanted) {
60		*status = SANE_STATUS_IO_ERROR;
61	}
62
63	return read;
64}
65
66static ssize_t
67sanei_epson_net_read_buf(Epson_Scanner *s, unsigned char *buf, ssize_t wanted,
68		       SANE_Status * status)
69{
70	ssize_t read = 0;
71
72	DBG(23, "%s: reading up to %lu from buffer at %p, %lu available\n",
73		__func__, (u_long) wanted, (void *) s->netptr, (u_long) s->netlen);
74
75	if ((size_t) wanted > s->netlen) {
76		*status = SANE_STATUS_IO_ERROR;
77		wanted = s->netlen;
78	}
79
80	memcpy(buf, s->netptr, wanted);
81	read = wanted;
82
83	s->netptr += read;
84	s->netlen -= read;
85
86	if (s->netlen == 0) {
87		DBG(23, "%s: freeing %p\n", __func__, (void *) s->netbuf);
88		free(s->netbuf);
89		s->netbuf = s->netptr = NULL;
90		s->netlen = 0;
91	}
92
93	return read;
94}
95
96ssize_t
97sanei_epson_net_read(Epson_Scanner *s, unsigned char *buf, ssize_t wanted,
98		       SANE_Status * status)
99{
100	if (wanted < 0) {
101		*status = SANE_STATUS_INVAL;
102		return 0;
103	}
104
105	size_t size;
106	ssize_t read = 0;
107	unsigned char header[12];
108
109	/* read from remainder of buffer */
110	if (s->netptr) {
111		return sanei_epson_net_read_buf(s, buf, wanted, status);
112	}
113
114	/* receive net header */
115	read = sanei_epson_net_read_raw(s, header, 12, status);
116	if (read != 12) {
117		return 0;
118	}
119
120	/* validate header */
121	if (header[0] != 'I' || header[1] != 'S') {
122		DBG(1, "header mismatch: %02X %02x\n", header[0], header[1]);
123		*status = SANE_STATUS_IO_ERROR;
124		return 0;
125	}
126
127	/* parse payload size */
128	size = be32atoh(&header[6]);
129
130	*status = SANE_STATUS_GOOD;
131
132	if (!s->netbuf) {
133		DBG(15, "%s: direct read\n", __func__);
134		DBG(23, "%s: wanted = %lu, available = %lu\n", __func__,
135			(u_long) wanted, (u_long) size);
136
137		if ((size_t) wanted > size) {
138			wanted = size;
139		}
140
141		read = sanei_epson_net_read_raw(s, buf, wanted, status);
142	} else {
143		DBG(15, "%s: buffered read\n", __func__);
144		DBG(23, "%s: bufferable = %lu, available = %lu\n", __func__,
145			(u_long) s->netlen, (u_long) size);
146
147		if (s->netlen > size) {
148			s->netlen = size;
149		}
150
151		/* fill buffer */
152		read = sanei_epson_net_read_raw(s, s->netbuf, s->netlen, status);
153		s->netptr = s->netbuf;
154		s->netlen = (read > 0 ? read : 0);
155
156		/* copy wanted part */
157		read = sanei_epson_net_read_buf(s, buf, wanted, status);
158	}
159
160	return read;
161}
162
163size_t
164sanei_epson_net_write(Epson_Scanner *s, unsigned int cmd, const unsigned char *buf,
165			size_t buf_size, size_t reply_len, SANE_Status *status)
166{
167	unsigned char *h1, *h2, *payload;
168	unsigned char *packet = malloc(12 + 8 + buf_size);
169
170	if (!packet) {
171		*status = SANE_STATUS_NO_MEM;
172		return 0;
173	}
174
175	h1 = packet;
176	h2 = packet + 12;
177	payload = packet + 12 + 8;
178
179	if (reply_len) {
180		if (s->netbuf) {
181			DBG(23, "%s, freeing %p, %ld bytes unprocessed\n",
182				__func__, (void *) s->netbuf, (u_long) s->netlen);
183			free(s->netbuf);
184			s->netbuf = s->netptr = NULL;
185			s->netlen = 0;
186		}
187		s->netbuf = malloc(reply_len);
188		if (!s->netbuf) {
189			free(packet);
190			*status = SANE_STATUS_NO_MEM;
191			return 0;
192		}
193		s->netlen = reply_len;
194		DBG(24, "%s: allocated %lu bytes at %p\n", __func__,
195			(u_long) s->netlen, (void *) s->netbuf);
196	}
197
198	DBG(24, "%s: cmd = %04x, buf = %p, buf_size = %lu, reply_len = %lu\n",
199		__func__, cmd, (void *) buf, (u_long) buf_size, (u_long) reply_len);
200
201	memset(h1, 0x00, 12);
202	memset(h2, 0x00, 8);
203
204	h1[0] = 'I';
205	h1[1] = 'S';
206
207	h1[2] = cmd >> 8;
208	h1[3] = cmd;
209
210	h1[4] = 0x00;
211	h1[5] = 0x0C; /* Don't know what's that */
212
213	DBG(24, "H1[0]: %02x %02x %02x %02x\n", h1[0], h1[1], h1[2], h1[3]);
214
215	if((cmd >> 8) == 0x20) {
216		htobe32a(&h1[6], buf_size + 8);
217
218		htobe32a(&h2[0], buf_size);
219		htobe32a(&h2[4], reply_len);
220
221		DBG(24, "H1[6]: %02x %02x %02x %02x (%lu)\n", h1[6], h1[7], h1[8], h1[9], (u_long) (buf_size + 8));
222		DBG(24, "H2[0]: %02x %02x %02x %02x (%lu)\n", h2[0], h2[1], h2[2], h2[3], (u_long) buf_size);
223		DBG(24, "H2[4]: %02x %02x %02x %02x (%lu)\n", h2[4], h2[5], h2[6], h2[7], (u_long) reply_len);
224	}
225
226	if ((cmd >> 8) == 0x20 && (buf_size || reply_len)) {
227		if (buf_size)
228			memcpy(payload, buf, buf_size);
229
230		sanei_tcp_write(s->fd, packet, 12 + 8 + buf_size);
231	}
232	else
233		sanei_tcp_write(s->fd, packet, 12);
234
235	free(packet);
236
237	*status = SANE_STATUS_GOOD;
238	return buf_size;
239}
240
241SANE_Status
242sanei_epson_net_lock(struct Epson_Scanner *s)
243{
244	SANE_Status status;
245	unsigned char buf[1];
246
247	DBG(1, "%s\n", __func__);
248
249	sanei_epson_net_write(s, 0x2100, NULL, 0, 0, &status);
250	sanei_epson_net_read(s, buf, 1, &status);
251	return status;
252}
253
254SANE_Status
255sanei_epson_net_unlock(struct Epson_Scanner *s)
256{
257	SANE_Status status;
258
259	DBG(1, "%s\n", __func__);
260
261	sanei_epson_net_write(s, 0x2101, NULL, 0, 0, &status);
262/*	sanei_epson_net_read(s, buf, 1, &status); */
263	return status;
264}
265