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 
35 static ssize_t
sanei_epson_net_read_raw(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, SANE_Status *status)36 sanei_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 
66 static ssize_t
sanei_epson_net_read_buf(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, SANE_Status * status)67 sanei_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 
96 ssize_t
sanei_epson_net_read(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, SANE_Status * status)97 sanei_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 
163 size_t
sanei_epson_net_write(Epson_Scanner *s, unsigned int cmd, const unsigned char *buf, size_t buf_size, size_t reply_len, SANE_Status *status)164 sanei_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 
241 SANE_Status
sanei_epson_net_lock(struct Epson_Scanner *s)242 sanei_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 
254 SANE_Status
sanei_epson_net_unlock(struct Epson_Scanner *s)255 sanei_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