1 /*
2 * KCemu -- The emulator for the KC85 homecomputer series and much more.
3 * Copyright (C) 1997-2010 Torsten Paul
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <fcntl.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <signal.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/poll.h>
29 #include <sys/un.h>
30 #include <sys/signal.h>
31
32 #include "kc/system.h"
33
34 #include "kc/kc.h"
35 #include "kc/z80.h"
36 #include "kc/mod_v24.h"
37 #include "kc/prefs/prefs.h"
38
39 #include "libdbg/dbg.h"
40
41 using namespace std;
42
43 static ModuleV24 *self;
44
ModuleV24(ModuleV24 & tmpl)45 ModuleV24::ModuleV24(ModuleV24 &tmpl) :
46 ModuleInterface(tmpl.get_name(), tmpl.get_id(), tmpl.get_type()),
47 InterfaceCircuit("ModuleV24")
48 {
49 _reg[A] = 0;
50 _reg[B] = 0;
51 _data_in[A] = 0;
52 _data_in[B] = 0;
53 _reg_rd[A][0] = 0xff;
54 _reg_rd[A][1] = 0xff;
55 _reg_rd[A][2] = 0xff;
56 _reg_rd[B][0] = 0xff;
57 _reg_rd[B][1] = 0xff;
58 _reg_rd[B][2] = 0xff;
59
60 _irq_active[A] = 0;
61 _irq_active[B] = 0;
62 _irq_pending[A] = 0;
63 _irq_pending[B] = 0;
64
65 _fd_in[A] = 0;
66 _fd_in[B] = 0;
67 _fd_out[A] = 0;
68 _fd_out[B] = 0;
69 _in_buf_ptr = 0;
70 _socket_name = 0;
71 }
72
ModuleV24(const char * name,byte_t id)73 ModuleV24::ModuleV24(const char *name, byte_t id) :
74 ModuleInterface(name, id, KC_MODULE_KC_85_3),
75 InterfaceCircuit("ModuleV24")
76 {
77 _fd_in[A] = 0;
78 _fd_in[B] = 0;
79 _fd_out[A] = 0;
80 _fd_out[B] = 0;
81 _in_buf_ptr = 0;
82 _socket_name = 0;
83 }
84
~ModuleV24(void)85 ModuleV24::~ModuleV24(void)
86 {
87 close_device();
88 }
89
90 byte_t
in(word_t addr)91 ModuleV24::in(word_t addr)
92 {
93 byte_t val;
94 int port = addr & 0xff;
95
96 val = 0xff;
97 switch (port)
98 {
99 case 0x80:
100 return get_id();
101 break;
102 case 0x08:
103 /* SIO channel A - data */
104 val = _data_in[A];
105 DBG(2, form("KCemu/ModuleV24/in/data/A",
106 "%04x: in_data: <- sio A 08h <- %0xh\n",
107 z80->getPC(), val));
108 break;
109 case 0x09:
110 /* SIO channel B - data */
111 val = _data_in[B];
112 DBG(2, form("KCemu/ModuleV24/in/data/B",
113 "%04x: in_data: <- sio B 08h <- %0xh\n",
114 z80->getPC(), val));
115 break;
116 case 0x0a:
117 /* SIO channel A - control */
118 val = in_reg(A);
119 break;
120 case 0x0b:
121 /* SIO channel B - control */
122 val = in_reg(B);
123 break;
124 case 0x0c:
125 val = 0xff;
126 DBG(2, form("KCemu/ModuleV24/in",
127 "%04xh: in_reg: <- ctc 0 0ch <- %0xh\n",
128 z80->getPC(), val));
129 break;
130 case 0x0d:
131 val = 0xff;
132 DBG(2, form("KCemu/ModuleV24/in",
133 "%04x: in_reg: <- ctc 1 0dh <- %0xh\n",
134 z80->getPC(), val));
135 break;
136 case 0x0e:
137 val = 0xff;
138 DBG(2, form("KCemu/ModuleV24/in",
139 "%04x: in_reg: <- ctc 2 0eh <- %0xh\n",
140 z80->getPC(), val));
141 break;
142 case 0x0f:
143 val = 0xff;
144 DBG(2, form("KCemu/ModuleV24/in",
145 "%04x: in_reg: <- ctc 3 0eh <- %0xh\n",
146 z80->getPC(), val));
147 break;
148 }
149
150 DBG(3, form("KCemu/ModuleV24/in",
151 "%04x: %s: %04x, %02x\n",
152 z80->getPC(), __PRETTY_FUNCTION__, addr, val));
153 return val;
154 }
155
156 void
out(word_t addr,byte_t val)157 ModuleV24::out(word_t addr, byte_t val)
158 {
159 int port = addr & 0xff;
160
161 DBG(3, form("KCemu/ModuleV24/out",
162 "%s: %04x, %02x\n",
163 __PRETTY_FUNCTION__, addr, val));
164 switch (port)
165 {
166 case 0x80:
167 if (((_val & 1) ^ (val & 1)) != 1) return;
168 if (val & 1)
169 {
170 open_device();
171 _portg = ports->register_ports(get_name(), 8, 6, this, (addr >> 8));
172 }
173 else
174 close_device();
175
176 _val = val;
177 break;
178 case 0x08:
179 /* SIO channel A - data */
180 DBG(2, form("KCemu/ModuleV24/out/data/A",
181 "out_data: sio A 08h: %0xh (io_type = %d)\n",
182 val, _io_type));
183 if (_fd_out[A] && (_io_type != IO_NONE))
184 if (_io_type == IO_FILE)
185 write(_fd_out[A], &val, 1);
186 else
187 send(_fd_out[A], &val, 1, 0);
188 break;
189 case 0x09:
190 /* SIO channel B - data */
191 DBG(2, form("KCemu/ModuleV24/out/data/B",
192 "out_data: sio B 09h: %0xh (io_type = %d)\n",
193 val, _io_type));
194 if (_fd_out[B] && (_io_type != IO_NONE))
195 if (_io_type == IO_FILE)
196 write(_fd_out[B], &val, 1);
197 else
198 send(_fd_out[B], &val, 1, 0);
199 break;
200 case 0x0a:
201 /* SIO channel A - control */
202 out_reg(A, val);
203 break;
204 case 0x0b:
205 /* SIO channel B - control */
206 out_reg(B, val);
207 break;
208 case 0x0c:
209 DBG(2, form("KCemu/ModuleV24/out/ctc/0",
210 "out_reg: -> ctc 0 0ch -> %0xh\n",
211 val));
212 break;
213 case 0x0d:
214 DBG(2, form("KCemu/ModuleV24/out/ctc/1",
215 "out_reg: -> ctc 1 0dh -> %0xh\n",
216 val));
217 break;
218 case 0x0e:
219 DBG(2, form("KCemu/ModuleV24/out/ctc/2",
220 "out_reg: -> ctc 2 0eh -> %0xh\n",
221 val));
222 break;
223 case 0x0f:
224 DBG(2, form("KCemu/ModuleV24/out/ctc/3",
225 "out_reg: -> ctc 3 0eh -> %0xh\n",
226 val));
227 break;
228 }
229 }
230
231 byte_t
in_reg(int c)232 ModuleV24::in_reg(int c)
233 {
234 DBG(2, form("KCemu/ModuleV24/in_reg/raw",
235 "in_reg: <- [%d] %02xh <- %d\n",
236 c, _reg_rd[c][_reg[c]], _reg[c]));
237 return _reg_rd[c][_reg[c]];
238 }
239
240 void
out_reg(int c,byte_t val)241 ModuleV24::out_reg(int c, byte_t val)
242 {
243 static const char *wr0_0[] = {
244 "",
245 " next write to register 1\n",
246 " next write to register 2\n",
247 " next write to register 3\n",
248 " next write to register 4\n",
249 " next write to register 5\n",
250 " next write to register 6\n",
251 " next write to register 7\n",
252 };
253 static const char *wr0_1[] = {
254 "",
255 " send break (SDLC)\n",
256 " reset external and status interrupts\n",
257 " reset channel\n",
258 " reset receive interrupt on first character\n",
259 " reset send interrupt\n",
260 " reset error condition\n",
261 " interrupt return (channel A)\n",
262 };
263 static const char *wr0_2[] = {
264 "",
265 " reset receiver CRC\n",
266 " reset sender CRC\n",
267 " reset CRC/SYNC status memory\n",
268 };
269
270 DBG(2, form("KCemu/ModuleV24/out_reg/raw",
271 "out_reg: -> [%d] %02xh -> %d\n",
272 c, val, _reg[c]));
273 _reg_wr[c][_reg[c]] = val;
274 switch (_reg[c])
275 {
276 case 0:
277 DBG(1, form("KCemu/ModuleV24/out_reg/reg/wr0",
278 "wr0: [%d] %02xh -> %d\n%s%s%s",
279 c, val, _reg[c],
280 wr0_0[val & 7],
281 wr0_1[(val >> 3) & 7],
282 wr0_2[(val >> 6) & 3]));
283 break;
284 case 1:
285 DBG(1, form("KCemu/ModuleV24/out_reg/reg/wr1",
286 "wr1: [%d] %02xh -> %d\n",
287 c, val, _reg[c]));
288 break;
289 case 2:
290 DBG(1, form("KCemu/ModuleV24/out_reg/reg/wr2",
291 "wr2: [%d] %02xh -> %d\n new interrupt vector: %02x\n",
292 c, val, _reg[c], val));
293 break;
294 case 3:
295 DBG(1, form("KCemu/ModuleV24/out_reg/reg/wr3",
296 "wr3: [%d] %02xh -> %d\n",
297 c, val, _reg[c]));
298 break;
299 case 4:
300 DBG(1, form("KCemu/ModuleV24/out_reg/reg/wr4",
301 "wr4: [%d] %02xh -> %d\n",
302 c, val, _reg[c]));
303 break;
304 case 5:
305 DBG(1, form("KCemu/ModuleV24/out_reg/reg/wr5",
306 "wr5: [%d] %02xh -> %d\n",
307 c, val, _reg[c]));
308 break;
309 case 6:
310 DBG(1, form("KCemu/ModuleV24/out_reg/reg/wr6",
311 "wr6: [%d] %02xh -> %d\n",
312 c, val, _reg[c]));
313 break;
314 case 7:
315 DBG(1, form("KCemu/ModuleV24/out_reg/reg/wr7",
316 "wr7: [%d] %02xh -> %d\n",
317 c, val, _reg[c]));
318 break;
319 }
320 if (_reg[c] == 0)
321 _reg[c] = val & 7;
322 else
323 _reg[c] = 0;
324 }
325
326 ModuleInterface *
clone(void)327 ModuleV24::clone(void)
328 {
329 return new ModuleV24(*this);
330 }
331
332 void
reset(bool power_on)333 ModuleV24::reset(bool power_on)
334 {
335 _irq_active[A] = 0;
336 _irq_active[B] = 0;
337 }
338
339 void
reti(void)340 ModuleV24::reti(void)
341 {
342 _irq_active[B] = 0;
343 _irq_pending[B] = 0;
344
345 if (!_in_buf_ptr)
346 return;
347
348 // if (z80->triggerIrq(_reg_wr[B][2]))
349 // {
350 // _irq_active[B] = 1;
351 // _data_in[B] = *_in_buf_ptr++;
352 // if (*_in_buf_ptr == 0) _in_buf_ptr = 0;
353 // z80->handleIrq(_reg_wr[B][2]);
354 // return;
355 // }
356 // else
357 // _irq_pending[B] = 1;
358 }
359
360 void
push_data(char * buf,int len)361 ModuleV24::push_data(char *buf, int len)
362 {
363 if (_in_buf_ptr)
364 {
365 cerr << "data ignored! ***" << endl;
366 return;
367 }
368
369 if (_irq_active[B])
370 {
371 cout << "irq still active!" << endl;
372 return;
373 }
374
375 strcpy((char *)_in_buf, buf);
376 _in_buf_ptr = _in_buf;
377
378 // if (z80->triggerIrq(_reg_wr[B][2]))
379 // {
380 // _irq_active[B] = 1;
381 // _data_in[B] = *_in_buf_ptr++;
382 // if (*_in_buf_ptr == 0) _in_buf_ptr = 0;
383 // z80->handleIrq(_reg_wr[B][2]);
384 // return;
385 // }
386 // else
387 // _irq_pending[B] = 1;
388 }
389
390 void
signal_handler_IO_read(int status)391 ModuleV24::signal_handler_IO_read(int status)
392 {
393 int a;
394
395 static char buf[INBUF_LEN];
396
397 DBG(1, form("KCemu/ModuleV24/signal",
398 "signal_handler_IO_read\n"));
399 a = read(self->_fd_in[B], buf, INBUF_LEN - 1);
400 buf[a] = '\0';
401 DBG(2, form("KCemu/ModuleV24/signal/data",
402 "got %d bytes: '%s'\n",
403 a, buf));
404 self->push_data(&buf[0], a);
405 }
406
407 void
signal_handler_IO_recv(int status)408 ModuleV24::signal_handler_IO_recv(int status)
409 {
410 int a;
411
412 static char buf[INBUF_LEN];
413
414 DBG(1, form("KCemu/ModuleV24/signal",
415 "signal_handler_IO_recv\n"));
416 a = recv(self->_fd_in[B], buf, INBUF_LEN, 0);
417 buf[a] = '\0';
418 DBG(2, form("KCemu/ModuleV24/signal/data",
419 "got %d bytes: '%s'\n",
420 a, buf));
421 self->push_data(&buf[0], a);
422 }
423
424 void
set_signal_handler(int fd,void (* sig_func)(int))425 ModuleV24::set_signal_handler(int fd, void (*sig_func)(int))
426 {
427 struct sigaction saio;
428
429 DBG(1, form("KCemu/ModuleV24/signal",
430 "setting signal handler for fd = %d\n", fd));
431
432 memset(&saio, 0, sizeof(saio));
433
434 if (fcntl(fd, F_SETOWN, getpid()) < 0)
435 cerr << "can't set owner on filedescriptor " << fd << " to " << getpid() << endl;
436 if (fcntl(fd, F_SETFL, FASYNC) < 0)
437 cerr << "can't set FASYNC flag on filedescriptor " << fd << endl;
438
439 self = this;
440 saio.sa_handler = sig_func;
441 sigemptyset(&saio.sa_mask);
442 saio.sa_flags = 0;
443
444 sigaction(SIGIO, &saio, (struct sigaction *)NULL);
445 }
446
447 bool
open_device_serial(int dev,const char * dev_name)448 ModuleV24::open_device_serial(int dev, const char *dev_name)
449 {
450 int baudrate = Preferences::instance()->get_int_value("v24_baudrate", 2400);
451
452 _fd_in[dev] = open(dev_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
453 if (_fd_in[dev] == 0)
454 return false;
455 _fd_out[dev] = _fd_in[dev];
456
457 set_signal_handler(_fd_in[dev], signal_handler_IO_read);
458
459 tcgetattr(_fd_in[dev], &_tio_old[dev]);
460 bzero(&_tio_new[dev], sizeof(_tio_new[dev]));
461
462 /*
463 * BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
464 * CRTSCTS : output hardware flow control (only used if the cable has
465 * all necessary lines. See sect. 7 of Serial-HOWTO)
466 * CS8 : 8n1 (8bit,no parity,1 stopbit)
467 * CLOCAL : local connection, no modem contol
468 * CREAD : enable receiving characters
469 */
470 _tio_new[dev].c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD;
471 switch (baudrate)
472 {
473 case 50: _tio_new[dev].c_cflag |= B50 ; break;
474 case 75: _tio_new[dev].c_cflag |= B75 ; break;
475 case 110: _tio_new[dev].c_cflag |= B110 ; break;
476 case 134: _tio_new[dev].c_cflag |= B134 ; break;
477 case 150: _tio_new[dev].c_cflag |= B150 ; break;
478 case 200: _tio_new[dev].c_cflag |= B200 ; break;
479 case 300: _tio_new[dev].c_cflag |= B300 ; break;
480 case 600: _tio_new[dev].c_cflag |= B600 ; break;
481 case 1200: _tio_new[dev].c_cflag |= B1200 ; break;
482 case 1800: _tio_new[dev].c_cflag |= B1800 ; break;
483 case 2400: _tio_new[dev].c_cflag |= B2400 ; break;
484 case 4800: _tio_new[dev].c_cflag |= B4800 ; break;
485 case 9600: _tio_new[dev].c_cflag |= B9600 ; break;
486 case 19200: _tio_new[dev].c_cflag |= B19200; break;
487 case 38400: _tio_new[dev].c_cflag |= B38400; break;
488 default:
489 baudrate = 9600;
490 _tio_new[dev].c_cflag |= B9600 ;
491 break;
492 }
493
494 DBG(1, form("KCemu/ModuleV24/open",
495 "ModuleV24::open_device_serial(): device = '%s', baudrate = %d\n",
496 dev_name, baudrate));
497
498
499 /*
500 * IGNPAR : ignore bytes with parity errors
501 * ICRNL : map CR to NL (otherwise a CR input on the other computer
502 * will not terminate input)
503 * otherwise make device raw (no other input processing)
504 */
505 _tio_new[dev].c_iflag = IGNPAR | ICRNL;
506 _tio_new[dev].c_iflag = IGNPAR;
507
508 /*
509 * Raw output.
510 */
511 _tio_new[dev].c_oflag = 0;
512
513 /*
514 * ICANON : enable canonical input
515 * disable all echo functionality, and don't send signals to calling program
516 */
517 _tio_new[dev].c_lflag = ICANON;
518 _tio_new[dev].c_lflag = 0;
519
520 _tio_new[dev].c_cc[VMIN]=1;
521 _tio_new[dev].c_cc[VTIME]=0;
522
523 tcflush(_fd_in[dev], TCIFLUSH);
524 tcsetattr(_fd_in[dev], TCSANOW, &_tio_new[dev]);
525
526 return true;
527 }
528
529 void
fifo_server(int fd)530 ModuleV24::fifo_server(int fd)
531 {
532 int ret, len, fd_read, fd_read_w, fd_write, fd_write_r;
533 struct pollfd pollfds[1];
534 char buf[1025];
535
536 DBG(1, form("KCemu/ModuleV24/server",
537 "ModuleV24::fifo_server() fd = %d\n",
538 fd));
539
540 if (unlink("/tmp/KCemu-FIFO-in") != 0)
541 perror("unlink");
542 if (unlink("/tmp/KCemu-FIFO-out") != 0)
543 perror("unlink");
544
545 if (mkfifo("/tmp/KCemu-FIFO-in", 0600) != 0)
546 {
547 perror("can't create FIFO");
548 exit(1);
549 }
550 if (mkfifo("/tmp/KCemu-FIFO-out", 0600) != 0)
551 {
552 perror("can't create FIFO");
553 exit(1);
554 }
555
556 fd_read = open("/tmp/KCemu-FIFO-in", O_RDONLY | O_NONBLOCK);
557 if (fd_read < 0)
558 {
559 perror("open (read)");
560 exit(1);
561 }
562 /*
563 * open the fifo for writing too to keep it open if the
564 * external writer closes it's side of the fifo
565 */
566 fd_read_w = open("/tmp/KCemu-FIFO-in", O_WRONLY | O_NONBLOCK);
567
568 fd_write_r = open("/tmp/KCemu-FIFO-out", O_RDONLY | O_NONBLOCK);
569 fd_write = open("/tmp/KCemu-FIFO-out", O_WRONLY | O_NONBLOCK);
570 if (fd_write < 0)
571 {
572 perror("open (write)");
573 exit(1);
574 }
575
576 while (242)
577 {
578 pollfds[0].fd = fd_read;
579 pollfds[0].events = POLLIN;
580 pollfds[0].revents = 0;
581 pollfds[1].fd = fd;
582 pollfds[1].events = POLLIN;
583 pollfds[1].revents = 0;
584 if ((ret = poll(pollfds, 2, -1)) < 0)
585 exit(2);
586
587 if ((pollfds[0].revents & POLLIN) == POLLIN)
588 {
589 len = read(fd_read, buf, 1024);
590 if (len == 0)
591 {
592 cerr << "ModuleV24::fifo_server(): read error" << endl;
593 exit(1);
594 }
595 send(fd, buf, len, 0);
596 }
597 if ((pollfds[1].revents & POLLIN) == POLLIN)
598 {
599 len = read(fd, buf, 1024);
600 write(fd_write, buf, len);
601 }
602 }
603 }
604
605 void
socket_server(int fd)606 ModuleV24::socket_server(int fd)
607 {
608 int s, c, len;
609 char buf[1024];
610 unsigned int cli_addr_len;
611 struct sockaddr_un unix_addr, cli_addr;
612
613 _socket_name = tempnam("/tmp", "KCemu");
614 if (_socket_name == NULL)
615 exit(1);
616 _socket_name = strdup("/tmp/KCemu-in");
617
618 s = socket(AF_UNIX, SOCK_STREAM, 0);
619 if (s < 0)
620 exit(2);
621
622 bzero((char *)&unix_addr, sizeof(unix_addr));
623 unix_addr.sun_family = AF_UNIX;
624 strcpy(unix_addr.sun_path, _socket_name);
625 len = strlen(unix_addr.sun_path) + sizeof(unix_addr.sun_family);
626
627 unlink(_socket_name);
628 if (bind(s, (struct sockaddr *)&unix_addr, len) != 0)
629 exit(3);
630
631 if (listen(s, 5) != 0)
632 exit(4);
633
634 while (242)
635 {
636 if ((c = accept(s, (struct sockaddr *)&cli_addr, &cli_addr_len)) < 0)
637 continue;
638
639 while (242)
640 {
641 len = recv(c, buf, 1024, 0);
642 if (len == 0)
643 break;
644 send(fd, buf, len, 0);
645 }
646 }
647 }
648
649 bool
open_device_socket_or_fifo(io_type_t io_type)650 ModuleV24::open_device_socket_or_fifo(io_type_t io_type)
651 {
652 int fd[2];
653
654 /*
655 * we use a pair of sockets for to communicate with the
656 * child process, fd[0] is used by the server, fd[1] by
657 * the child process
658 */
659 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0)
660 return false;
661
662 _pid = fork();
663
664 if (_pid < 0)
665 return false;
666
667 if (_pid > 0)
668 {
669 _fd_in[A] = fd[0];
670 _fd_out[A] = fd[0];
671 set_signal_handler(_fd_in[A], signal_handler_IO_recv);
672 return true;
673 }
674
675 if (io_type == IO_FIFO)
676 fifo_server(fd[1]);
677 else
678 socket_server(fd[1]);
679 return true;
680 }
681
682 void
open_device(void)683 ModuleV24::open_device(void)
684 {
685 bool ret;
686 char *s;
687 const char *dev_name;
688
689 dev_name = Preferences::instance()->get_string_value("v24_device", "/dev/ttyS1");
690
691 _io_type = IO_NONE;
692 if (strcmp(dev_name, "SOCKET") == 0)
693 {
694 _io_type = IO_SOCKET;
695 ret = open_device_socket_or_fifo(IO_SOCKET);
696 }
697 else if (strcmp(dev_name, "FIFO") == 0)
698 {
699 _io_type = IO_FIFO;
700 ret = open_device_socket_or_fifo(IO_FIFO);
701 }
702 else
703 {
704 _io_type = IO_FIFO;
705 ret = open_device_serial(B, dev_name);
706 }
707
708 if (!ret)
709 return;
710
711 z80->register_ic(this);
712
713 s = "\r\nKCemu v" KCEMU_VERSION " - V24 module active\r\n\r\n";
714 write(_fd_out[B], s, strlen(s));
715 }
716
717 void
close_device(void)718 ModuleV24::close_device(void)
719 {
720 if (_socket_name != 0)
721 {
722 unlink(_socket_name);
723 free(_socket_name);
724 }
725
726 if (_fd_in[A] != 0)
727 {
728 tcsetattr(_fd_in[A] , TCSANOW, &_tio_old[A]);
729 close(_fd_in[A]);
730 close(_fd_out[A]);
731 }
732
733 z80->unregister_ic(this);
734 }
735
736 void
m_out(word_t addr,byte_t val)737 ModuleV24::m_out(word_t addr, byte_t val)
738 {
739 }
740