fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/devices/slip.c *
7 * Created: 2004-12-15 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2004-2009 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include <config.h>
24
25#include <stdio.h>
26#include <stdlib.h>
27
28#ifdef PCE_ENABLE_TUN
29#include <lib/tun.h>
30#endif
31
32#include "slip.h"
33
34
35/* #define SLIP_DEBUG 1 */
36
37/* receive packet buffer */
38#define SLIP_PACKET_BUFFER 8
39
40
41void slip_init (slip_t *slip)
42{
43 slip->out_cnt = 0;
44 slip->out_esc = 0;
45
46 slip->inp_hd = NULL;
47 slip->inp_tl = NULL;
48 slip->inp_cnt = 0;
49
50 slip->tun_fd = -1;
51
52 slip->checking = 0;
53
54 slip->get_uint8 = NULL;
55 slip->get_uint8_ext = NULL;
56
57 slip->set_uint8 = NULL;
58 slip->set_uint8_ext = NULL;
59}
60
61void slip_free (slip_t *slip)
62{
63#ifdef PCE_ENABLE_TUN
64 if (slip->tun_fd >= 0) {
65 tun_close (slip->tun_fd);
66 }
67#endif
68}
69
70slip_t *slip_new (void)
71{
72 slip_t *slip;
73
74 slip = malloc (sizeof (slip_t));
75 if (slip == NULL) {
76 return (NULL);
77 }
78
79 slip_init (slip);
80
81 return (slip);
82}
83
84void slip_del (slip_t *slip)
85{
86 if (slip != NULL) {
87 slip_free (slip);
88 free (slip);
89 }
90}
91
92void slip_set_set_uint8_fct (slip_t *slip, void *ext, void *fct)
93{
94 slip->set_uint8 = fct;
95 slip->set_uint8_ext = ext;
96}
97
98void slip_set_get_uint8_fct (slip_t *slip, void *ext, void *fct)
99{
100 slip->get_uint8 = fct;
101 slip->get_uint8_ext = ext;
102}
103
104int slip_set_tun (slip_t *slip, const char *name)
105{
106#ifdef PCE_ENABLE_TUN
107 if (slip->tun_fd >= 0) {
108 tun_close (slip->tun_fd);
109 }
110
111 slip->tun_fd = tun_open (name);
112 if (slip->tun_fd < 0) {
113 return (1);
114 }
115
116 return (0);
117#else
118 return (1);
119#endif
120}
121
122
123static
124int slip_get_uint8 (slip_t *slip, unsigned char *val)
125{
126 if (slip->get_uint8 != NULL) {
127 return (slip->get_uint8 (slip->get_uint8_ext, val));
128 }
129
130 return (1);
131}
132
133static
134int slip_set_uint8 (slip_t *slip, unsigned char val)
135{
136 if (slip->set_uint8 != NULL) {
137 return (slip->set_uint8 (slip->set_uint8_ext, val));
138 }
139
140 return (1);
141}
142
143
144static
145slip_buf_t *slip_buf_alloc (slip_t *slip)
146{
147 slip_buf_t *buf;
148
149 buf = malloc (sizeof (slip_buf_t));
150 if (buf == NULL) {
151 return (0);
152 }
153
154 buf->next = NULL;
155 buf->i = 0;
156 buf->n = 0;
157
158 return (buf);
159}
160
161static
162void slip_buf_free (slip_t *slip, slip_buf_t *buf)
163{
164 free (buf);
165}
166
167static
168void slip_send_packet (slip_t *slip)
169{
170#ifdef PCE_ENABLE_TUN
171 if (slip->tun_fd >= 0) {
172#ifdef SLIP_DEBUG
173 fprintf (stderr, "slip: send tun S=%u\n", slip->out_cnt);
174 fflush (stderr);
175#endif
176
177 if (tun_set_packet (slip->tun_fd, slip->out, slip->out_cnt)) {
178 fprintf (stderr, "slip: packet drop\n");
179 }
180 }
181#endif
182}
183
184static
185int slip_receive_packet (slip_t *slip)
186{
187#ifdef PCE_ENABLE_TUN
188 unsigned i, j, n;
189 unsigned char tmp[PCE_SLIP_BUF_MAX];
190 slip_buf_t *buf;
191
192 if (tun_check_packet (slip->tun_fd) == 0) {
193 return (1);
194 }
195
196 n = PCE_SLIP_BUF_MAX;
197
198 if (tun_get_packet (slip->tun_fd, tmp, &n)) {
199 return (1);
200 }
201
202 buf = slip_buf_alloc (slip);
203 if (buf == NULL) {
204 return (1);
205 }
206
207 j = 0;
208 buf->buf[j++] = 192;
209
210 for (i = 0; i < n; i++) {
211 if (tmp[i] == 192) {
212 if (j < PCE_SLIP_BUF_MAX) {
213 buf->buf[j++] = 219;
214 }
215 if (j < PCE_SLIP_BUF_MAX) {
216 buf->buf[j++] = 220;
217 }
218 }
219 else if (tmp[i] == 219) {
220 if (j < PCE_SLIP_BUF_MAX) {
221 buf->buf[j++] = 219;
222 }
223 if (j < PCE_SLIP_BUF_MAX) {
224 buf->buf[j++] = 221;
225 }
226 }
227 else {
228 if (j < PCE_SLIP_BUF_MAX) {
229 buf->buf[j++] = tmp[i];
230 }
231 }
232 }
233
234 if (j < PCE_SLIP_BUF_MAX) {
235 buf->buf[j++] = 192;
236 }
237
238#ifdef SLIP_DEBUG
239 fprintf (stderr, "slip: recv tun S=%u+%u Q=%u\n",
240 n, j - n, slip->inp_cnt + 1
241 );
242#endif
243
244 buf->n = j;
245
246 if (slip->inp_hd == NULL) {
247 slip->inp_hd = buf;
248 }
249 else {
250 slip->inp_tl->next = buf;
251 }
252
253 slip->inp_tl = buf;
254 slip->inp_cnt += 1;
255
256 return (0);
257#else
258 return (1);
259#endif
260}
261
262static
263void slip_set_out (slip_t *slip, unsigned char c)
264{
265 if (c == 192) {
266 if (slip->out_cnt > 0) {
267 slip_send_packet (slip);
268 }
269
270 slip->out_cnt = 0;
271 slip->out_esc = 0;
272
273 return;
274 }
275
276 if (slip->out_esc) {
277 slip->out_esc = 0;
278
279 if (c == 220) {
280 c = 192;
281 }
282 else if (c == 221) {
283 c = 219;
284 }
285 else {
286 fprintf (stderr, "slip: unknown escape (%02X)\n",
287 (unsigned) c
288 );
289 return;
290 }
291 }
292 else {
293 if (c == 219) {
294 slip->out_esc = 1;
295 return;
296 }
297 }
298
299 if (slip->out_cnt >= PCE_SLIP_BUF_MAX) {
300 fprintf (stderr, "slip: send buffer overrun\n");
301 return;
302 }
303
304 slip->out[slip->out_cnt++] = c;
305}
306
307void slip_uart_check_out (slip_t *slip, unsigned char val)
308{
309 unsigned char c;
310
311 if (slip->checking) {
312 return;
313 }
314
315 slip->checking = 1;
316
317 while (1) {
318 if (slip_get_uint8 (slip, &c)) {
319 break;
320 }
321
322 slip_set_out (slip, c);
323 }
324
325 slip->checking = 0;
326}
327
328void slip_uart_check_inp (slip_t *slip, unsigned char val)
329{
330 if (slip->checking) {
331 return;
332 }
333
334 slip->checking = 1;
335
336 while (slip->inp_hd != NULL) {
337 slip_buf_t *buf;
338
339 buf = slip->inp_hd;
340
341 while (buf->i < buf->n) {
342 if (slip_set_uint8 (slip, buf->buf[buf->i])) {
343 break;
344 }
345
346 buf->i += 1;
347 }
348
349 if (buf->i < buf->n) {
350 break;
351 }
352
353#ifdef SLIP_DEBUG
354 fprintf (stderr, "slip: recv uart S=%u Q=%u\n",
355 buf->n, slip->inp_cnt - 1
356 );
357#endif
358
359 if (buf->next == NULL) {
360 slip->inp_hd = NULL;
361 slip->inp_tl = NULL;
362 }
363 else {
364 slip->inp_hd = buf->next;
365 }
366
367 slip_buf_free (slip, buf);
368
369 slip->inp_cnt -= 1;
370 }
371
372 while (slip->inp_cnt < SLIP_PACKET_BUFFER) {
373 if (slip_receive_packet (slip)) {
374 break;
375 }
376 }
377
378 slip->checking = 0;
379}
380
381void slip_clock (slip_t *slip, unsigned n)
382{
383 slip_uart_check_inp (slip, 1);
384 slip_uart_check_out (slip, 1);
385}