ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/serial_unix.cpp
Revision: 1.17
Committed: 2010-10-19T03:30:20Z (14 years, 1 month ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +1 -1 lines
Log Message:
fix sentinel warning

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * serial_unix.cpp - Serial device driver, Unix specific stuff
3     *
4 gbeauche 1.16 * Basilisk II (C) 1997-2008 Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22    
23     #include <sys/ioctl.h>
24     #include <sys/stat.h>
25 cebix 1.12 #include <sys/wait.h>
26 cebix 1.1 #include <pthread.h>
27     #include <semaphore.h>
28     #include <termios.h>
29 cebix 1.12 #include <errno.h>
30 cebix 1.1 #ifdef __linux__
31     #include <linux/lp.h>
32     #include <linux/major.h>
33     #include <linux/kdev_t.h>
34     #endif
35    
36     #include "cpu_emulation.h"
37     #include "main.h"
38     #include "macos_util.h"
39     #include "prefs.h"
40     #include "serial.h"
41     #include "serial_defs.h"
42    
43 cebix 1.12 extern "C" {
44     #include "sshpty.h"
45     }
46    
47    
48 cebix 1.1 #define DEBUG 0
49     #include "debug.h"
50    
51     #define MONITOR 0
52    
53    
54 gbeauche 1.15 // IRIX missing or unsupported defines
55     #ifdef sgi
56     #ifndef CRTSCTS
57     #define CRTSCTS CNEW_RTSCTS
58     #endif
59     #ifndef B230400
60     #define B230400 B115200
61     #endif
62     #endif
63    
64    
65 cebix 1.1 // Missing functions
66     #ifndef HAVE_CFMAKERAW
67     static int cfmakeraw(struct termios *termios_p)
68     {
69     termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
70     termios_p->c_oflag &= ~OPOST;
71     termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
72     termios_p->c_cflag &= ~(CSIZE|PARENB);
73     termios_p->c_cflag |= CS8;
74 cebix 1.11 return 0;
75 cebix 1.1 }
76     #endif
77    
78    
79     // Driver private variables
80     class XSERDPort : public SERDPort {
81     public:
82     XSERDPort(const char *dev)
83     {
84     device_name = dev;
85 cebix 1.12 protocol = serial;
86 cebix 1.1 fd = -1;
87 cebix 1.12 pid = 0;
88 cebix 1.1 input_thread_active = output_thread_active = false;
89    
90 cebix 1.10 Set_pthread_attr(&thread_attr, 2);
91 cebix 1.1 }
92    
93     virtual ~XSERDPort()
94     {
95     if (input_thread_active) {
96     input_thread_cancel = true;
97     #ifdef HAVE_PTHREAD_CANCEL
98     pthread_cancel(input_thread);
99     #endif
100     pthread_join(input_thread, NULL);
101     sem_destroy(&input_signal);
102     input_thread_active = false;
103     }
104     if (output_thread_active) {
105     output_thread_cancel = true;
106     #ifdef HAVE_PTHREAD_CANCEL
107     pthread_cancel(output_thread);
108     #endif
109     pthread_join(output_thread, NULL);
110     sem_destroy(&output_signal);
111     output_thread_active = false;
112     }
113     }
114    
115 cebix 1.3 virtual int16 open(uint16 config);
116     virtual int16 prime_in(uint32 pb, uint32 dce);
117     virtual int16 prime_out(uint32 pb, uint32 dce);
118     virtual int16 control(uint32 pb, uint32 dce, uint16 code);
119     virtual int16 status(uint32 pb, uint32 dce, uint16 code);
120     virtual int16 close(void);
121 cebix 1.1
122     private:
123 cebix 1.12 bool open_pty(void);
124 cebix 1.1 bool configure(uint16 config);
125     void set_handshake(uint32 s, bool with_dtr);
126     static void *input_func(void *arg);
127     static void *output_func(void *arg);
128    
129     const char *device_name; // Device name
130 cebix 1.12 enum {serial, parallel, pty, midi}
131     protocol; // Type of device
132 cebix 1.1 int fd; // FD of device
133 cebix 1.12 pid_t pid; // PID of child process
134 cebix 1.1
135     bool io_killed; // Flag: KillIO called, I/O threads must not call deferred tasks
136     bool quitting; // Flag: Quit threads
137    
138     pthread_attr_t thread_attr; // Input/output thread attributes
139    
140     bool input_thread_active; // Flag: Input thread installed
141     volatile bool input_thread_cancel; // Flag: Cancel input thread
142     pthread_t input_thread; // Data input thread
143     sem_t input_signal; // Signal for input thread: execute command
144     uint32 input_pb; // Command parameter for input thread
145    
146     bool output_thread_active; // Flag: Output thread installed
147     volatile bool output_thread_cancel; // Flag: Cancel output thread
148     pthread_t output_thread; // Data output thread
149     sem_t output_signal; // Signal for output thread: execute command
150     uint32 output_pb; // Command parameter for output thread
151    
152     struct termios mode; // Terminal configuration
153     };
154    
155    
156     /*
157     * Initialization
158     */
159    
160     void SerialInit(void)
161     {
162     // Read serial preferences and create structs for both ports
163     the_serd_port[0] = new XSERDPort(PrefsFindString("seriala"));
164     the_serd_port[1] = new XSERDPort(PrefsFindString("serialb"));
165     }
166    
167    
168     /*
169     * Deinitialization
170     */
171    
172     void SerialExit(void)
173     {
174     delete (XSERDPort *)the_serd_port[0];
175     delete (XSERDPort *)the_serd_port[1];
176     }
177    
178    
179     /*
180     * Open serial port
181     */
182    
183 cebix 1.3 int16 XSERDPort::open(uint16 config)
184 cebix 1.1 {
185     // Don't open NULL name devices
186     if (device_name == NULL)
187     return openErr;
188    
189     // Init variables
190     io_killed = false;
191     quitting = false;
192    
193 cebix 1.12 // Open port, according to the syntax of the path
194     if (device_name[0] == '|') {
195     // Open a process via ptys
196     if (!open_pty())
197     goto open_error;
198     }
199     else if (!strcmp(device_name, "midi")) {
200     // MIDI: not yet implemented
201     return openErr;
202     }
203     else {
204     // Device special file
205     fd = ::open(device_name, O_RDWR);
206     if (fd < 0)
207     goto open_error;
208 cebix 1.1
209 cebix 1.2 #if defined(__linux__)
210 cebix 1.12 // Parallel port?
211     struct stat st;
212     if (fstat(fd, &st) == 0)
213     if (S_ISCHR(st.st_mode))
214     protocol = ((MAJOR(st.st_rdev) == LP_MAJOR) ? parallel : serial);
215 cebix 1.2 #elif defined(__FreeBSD__) || defined(__NetBSD__)
216 cebix 1.12 // Parallel port?
217     struct stat st;
218     if (fstat(fd, &st) == 0)
219     if (S_ISCHR(st.st_mode))
220     protocol = (((st.st_rdev >> 16) == 16) ? parallel : serial);
221 cebix 1.1 #endif
222 cebix 1.12 }
223 cebix 1.1
224     // Configure port for raw mode
225 cebix 1.12 if (protocol == serial) {
226 cebix 1.1 if (tcgetattr(fd, &mode) < 0)
227     goto open_error;
228     cfmakeraw(&mode);
229     mode.c_cflag |= HUPCL;
230     mode.c_cc[VMIN] = 1;
231     mode.c_cc[VTIME] = 0;
232     tcsetattr(fd, TCSAFLUSH, &mode);
233     }
234     configure(config);
235    
236     // Start input/output threads
237 cebix 1.8 input_thread_cancel = false;
238     output_thread_cancel = false;
239 cebix 1.1 if (sem_init(&input_signal, 0, 0) < 0)
240     goto open_error;
241     if (sem_init(&output_signal, 0, 0) < 0)
242     goto open_error;
243     input_thread_active = (pthread_create(&input_thread, &thread_attr, input_func, this) == 0);
244     output_thread_active = (pthread_create(&output_thread, &thread_attr, output_func, this) == 0);
245     if (!input_thread_active || !output_thread_active)
246     goto open_error;
247     return noErr;
248    
249     open_error:
250     if (input_thread_active) {
251     input_thread_cancel = true;
252     #ifdef HAVE_PTHREAD_CANCEL
253     pthread_cancel(input_thread);
254     #endif
255     pthread_join(input_thread, NULL);
256     sem_destroy(&input_signal);
257     input_thread_active = false;
258     }
259     if (output_thread_active) {
260     output_thread_cancel = true;
261     #ifdef HAVE_PTHREAD_CANCEL
262     pthread_cancel(output_thread);
263     #endif
264     pthread_join(output_thread, NULL);
265     sem_destroy(&output_signal);
266     output_thread_active = false;
267     }
268     if (fd > 0) {
269 cebix 1.4 ::close(fd);
270 cebix 1.1 fd = -1;
271     }
272     return openErr;
273     }
274    
275    
276     /*
277     * Read data from port
278     */
279    
280 cebix 1.3 int16 XSERDPort::prime_in(uint32 pb, uint32 dce)
281 cebix 1.1 {
282     // Send input command to input_thread
283     read_done = false;
284     read_pending = true;
285     input_pb = pb;
286     WriteMacInt32(input_dt + serdtDCE, dce);
287     sem_post(&input_signal);
288     return 1; // Command in progress
289     }
290    
291    
292     /*
293     * Write data to port
294     */
295    
296 cebix 1.3 int16 XSERDPort::prime_out(uint32 pb, uint32 dce)
297 cebix 1.1 {
298     // Send output command to output_thread
299     write_done = false;
300     write_pending = true;
301     output_pb = pb;
302     WriteMacInt32(output_dt + serdtDCE, dce);
303     sem_post(&output_signal);
304     return 1; // Command in progress
305     }
306    
307    
308     /*
309     * Control calls
310     */
311    
312 cebix 1.3 int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
313 cebix 1.1 {
314     switch (code) {
315     case 1: // KillIO
316     io_killed = true;
317 cebix 1.12 if (protocol == serial)
318 cebix 1.1 tcflush(fd, TCIOFLUSH);
319     while (read_pending || write_pending)
320     usleep(10000);
321     io_killed = false;
322     return noErr;
323    
324     case kSERDConfiguration:
325     if (configure(ReadMacInt16(pb + csParam)))
326     return noErr;
327     else
328     return paramErr;
329    
330     case kSERDInputBuffer:
331     return noErr; // Not supported under Unix
332    
333     case kSERDSerHShake:
334     set_handshake(pb + csParam, false);
335     return noErr;
336    
337     case kSERDSetBreak:
338 cebix 1.12 if (protocol == serial)
339 cebix 1.1 tcsendbreak(fd, 0);
340     return noErr;
341    
342     case kSERDClearBreak:
343     return noErr;
344    
345     case kSERDBaudRate: {
346 cebix 1.12 if (protocol != serial)
347 cebix 1.1 return noErr;
348     uint16 rate = ReadMacInt16(pb + csParam);
349     speed_t baud_rate;
350     if (rate <= 50) {
351     rate = 50; baud_rate = B50;
352     } else if (rate <= 75) {
353     rate = 75; baud_rate = B75;
354     } else if (rate <= 110) {
355     rate = 110; baud_rate = B110;
356     } else if (rate <= 134) {
357     rate = 134; baud_rate = B134;
358     } else if (rate <= 150) {
359     rate = 150; baud_rate = B150;
360     } else if (rate <= 200) {
361     rate = 200; baud_rate = B200;
362     } else if (rate <= 300) {
363     rate = 300; baud_rate = B300;
364     } else if (rate <= 600) {
365     rate = 600; baud_rate = B600;
366     } else if (rate <= 1200) {
367     rate = 1200; baud_rate = B1200;
368     } else if (rate <= 1800) {
369     rate = 1800; baud_rate = B1800;
370     } else if (rate <= 2400) {
371     rate = 2400; baud_rate = B2400;
372     } else if (rate <= 4800) {
373     rate = 4800; baud_rate = B4800;
374     } else if (rate <= 9600) {
375     rate = 9600; baud_rate = B9600;
376     } else if (rate <= 19200) {
377     rate = 19200; baud_rate = B19200;
378     } else if (rate <= 38400) {
379     rate = 38400; baud_rate = B38400;
380     } else if (rate <= 57600) {
381     rate = 57600; baud_rate = B57600;
382     } else {
383     // Just for safety in case someone wants a rate between 57600 and 65535
384     rate = 57600; baud_rate = B57600;
385     }
386     WriteMacInt16(pb + csParam, rate);
387 cebix 1.12 cfsetispeed(&mode, baud_rate);
388     cfsetospeed(&mode, baud_rate);
389 cebix 1.1 tcsetattr(fd, TCSANOW, &mode);
390     return noErr;
391     }
392    
393     case kSERDHandshake:
394     case kSERDHandshakeRS232:
395     set_handshake(pb + csParam, true);
396     return noErr;
397    
398     case kSERDMiscOptions:
399 cebix 1.12 if (protocol != serial)
400 cebix 1.1 return noErr;
401     if (ReadMacInt8(pb + csParam) & kOptionPreserveDTR)
402     mode.c_cflag &= ~HUPCL;
403     else
404     mode.c_cflag |= HUPCL;
405     tcsetattr(fd, TCSANOW, &mode);
406     return noErr;
407    
408     case kSERDAssertDTR: {
409 cebix 1.12 if (protocol != serial)
410 cebix 1.1 return noErr;
411     unsigned int status = TIOCM_DTR;
412     ioctl(fd, TIOCMBIS, &status);
413     return noErr;
414     }
415    
416     case kSERDNegateDTR: {
417 cebix 1.12 if (protocol != serial)
418 cebix 1.1 return noErr;
419     unsigned int status = TIOCM_DTR;
420     ioctl(fd, TIOCMBIC, &status);
421     return noErr;
422     }
423    
424     case kSERDSetPEChar:
425     case kSERDSetPEAltChar:
426     return noErr; // Not supported under Unix
427    
428     case kSERDResetChannel:
429 cebix 1.12 if (protocol == serial)
430 cebix 1.1 tcflush(fd, TCIOFLUSH);
431     return noErr;
432    
433     case kSERDAssertRTS: {
434 cebix 1.12 if (protocol != serial)
435 cebix 1.1 return noErr;
436     unsigned int status = TIOCM_RTS;
437     ioctl(fd, TIOCMBIS, &status);
438     return noErr;
439     }
440    
441     case kSERDNegateRTS: {
442 cebix 1.12 if (protocol != serial)
443 cebix 1.1 return noErr;
444     unsigned int status = TIOCM_RTS;
445     ioctl(fd, TIOCMBIC, &status);
446     return noErr;
447     }
448    
449     case kSERD115KBaud:
450 cebix 1.12 if (protocol != serial)
451 cebix 1.1 return noErr;
452     cfsetispeed(&mode, B115200);
453     cfsetospeed(&mode, B115200);
454     tcsetattr(fd, TCSANOW, &mode);
455     return noErr;
456    
457     case kSERD230KBaud:
458     case kSERDSetHighSpeed:
459 cebix 1.12 if (protocol != serial)
460 cebix 1.1 return noErr;
461     cfsetispeed(&mode, B230400);
462     cfsetospeed(&mode, B230400);
463     tcsetattr(fd, TCSANOW, &mode);
464     return noErr;
465    
466     default:
467     printf("WARNING: SerialControl(): unimplemented control code %d\n", code);
468     return controlErr;
469     }
470     }
471    
472    
473     /*
474     * Status calls
475     */
476    
477 cebix 1.3 int16 XSERDPort::status(uint32 pb, uint32 dce, uint16 code)
478 cebix 1.1 {
479     switch (code) {
480     case kSERDInputCount: {
481     int num;
482     ioctl(fd, FIONREAD, &num);
483     WriteMacInt32(pb + csParam, num);
484     return noErr;
485     }
486    
487     case kSERDStatus: {
488     uint32 p = pb + csParam;
489     WriteMacInt8(p + staCumErrs, cum_errors);
490     cum_errors = 0;
491     WriteMacInt8(p + staXOffSent, 0);
492     WriteMacInt8(p + staXOffHold, 0);
493     WriteMacInt8(p + staRdPend, read_pending);
494     WriteMacInt8(p + staWrPend, write_pending);
495 cebix 1.12 if (protocol != serial) {
496 cebix 1.1 WriteMacInt8(p + staCtsHold, 0);
497     WriteMacInt8(p + staDsrHold, 0);
498     WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent);
499     } else {
500     unsigned int status;
501     ioctl(fd, TIOCMGET, &status);
502     WriteMacInt8(p + staCtsHold, status & TIOCM_CTS ? 0 : 1);
503     WriteMacInt8(p + staDsrHold, status & TIOCM_DTR ? 0 : 1);
504     WriteMacInt8(p + staModemStatus,
505     (status & TIOCM_DSR ? dsrEvent : 0)
506     | (status & TIOCM_RI ? riEvent : 0)
507     | (status & TIOCM_CD ? dcdEvent : 0)
508     | (status & TIOCM_CTS ? ctsEvent : 0));
509     }
510     return noErr;
511     }
512    
513     default:
514     printf("WARNING: SerialStatus(): unimplemented status code %d\n", code);
515     return statusErr;
516     }
517     }
518    
519    
520     /*
521     * Close serial port
522     */
523    
524 cebix 1.3 int16 XSERDPort::close()
525 cebix 1.1 {
526     // Kill threads
527     if (input_thread_active) {
528     quitting = true;
529     sem_post(&input_signal);
530     pthread_join(input_thread, NULL);
531     input_thread_active = false;
532     sem_destroy(&input_signal);
533     }
534     if (output_thread_active) {
535     quitting = true;
536     sem_post(&output_signal);
537     pthread_join(output_thread, NULL);
538     output_thread_active = false;
539     sem_destroy(&output_signal);
540     }
541    
542     // Close port
543     if (fd > 0)
544 cebix 1.4 ::close(fd);
545 cebix 1.1 fd = -1;
546 cebix 1.12
547     // Wait for the subprocess to exit
548     if (pid)
549     waitpid(pid, NULL, 0);
550     pid = 0;
551    
552 cebix 1.1 return noErr;
553     }
554    
555    
556     /*
557 cebix 1.12 * Open a process via ptys
558     */
559    
560     bool XSERDPort::open_pty(void)
561     {
562     // Talk to a process via a pty
563     char slave[128];
564     int slavefd;
565    
566     protocol = pty;
567     if (!pty_allocate(&fd, &slavefd, slave, sizeof(slave)))
568     return false;
569    
570     fflush(stdout);
571     fflush(stderr);
572     switch (pid = fork()) {
573     case -1: // error
574     return false;
575     break;
576     case 0: // child
577     ::close(fd);
578    
579     /* Make the pseudo tty our controlling tty. */
580     pty_make_controlling_tty(&slavefd, slave);
581    
582     ::close(0); dup(slavefd); // Use the slave fd for stdin,
583     ::close(1); dup(slavefd); // stdout,
584     ::close(2); dup(slavefd); // and stderr.
585    
586     // <should we be more paranoid about closing unused fds?>
587     // <should we drop privileges if running setuid?>
588    
589     // Let the shell do the dirty work
590 asvitkine 1.17 execlp("/bin/sh", "/bin/sh", "-c", ++device_name, (char *)NULL);
591 cebix 1.12
592     // exec failed!
593     printf("serial_open: could not exec %s: %s\n",
594     "/bin/sh", strerror(errno));
595     exit(1);
596     break;
597     default: // parent
598     // Pid was stored above
599     break;
600     }
601    
602     return true;
603     }
604    
605    
606     /*
607 cebix 1.1 * Configure serial port with MacOS config word
608     */
609    
610     bool XSERDPort::configure(uint16 config)
611     {
612     D(bug(" configure %04x\n", config));
613 cebix 1.12 if (protocol != serial)
614 cebix 1.1 return true;
615    
616     // Set number of stop bits
617     switch (config & 0xc000) {
618     case stop10:
619     mode.c_cflag &= ~CSTOPB;
620     break;
621     case stop20:
622     mode.c_cflag |= CSTOPB;
623     break;
624     default:
625     return false;
626     }
627    
628     // Set parity mode
629     switch (config & 0x3000) {
630     case noParity:
631     mode.c_iflag &= ~INPCK;
632     mode.c_oflag &= ~PARENB;
633     break;
634     case oddParity:
635     mode.c_iflag |= INPCK;
636     mode.c_oflag |= PARENB;
637     mode.c_oflag |= PARODD;
638     break;
639     case evenParity:
640     mode.c_iflag |= INPCK;
641     mode.c_oflag |= PARENB;
642     mode.c_oflag &= ~PARODD;
643     break;
644     default:
645     return false;
646     }
647    
648     // Set number of data bits
649     switch (config & 0x0c00) {
650     case data5:
651     mode.c_cflag = mode.c_cflag & ~CSIZE | CS5;
652     break;
653     case data6:
654     mode.c_cflag = mode.c_cflag & ~CSIZE | CS6;
655     break;
656     case data7:
657     mode.c_cflag = mode.c_cflag & ~CSIZE | CS7;
658     break;
659     case data8:
660     mode.c_cflag = mode.c_cflag & ~CSIZE | CS8;
661     break;
662     }
663    
664     // Set baud rate
665     speed_t baud_rate;
666     switch (config & 0x03ff) {
667     case baud150: baud_rate = B150; break;
668     case baud300: baud_rate = B300; break;
669     case baud600: baud_rate = B600; break;
670     case baud1200: baud_rate = B1200; break;
671     case baud1800: baud_rate = B1800; break;
672     case baud2400: baud_rate = B2400; break;
673     case baud4800: baud_rate = B4800; break;
674     case baud9600: baud_rate = B9600; break;
675     case baud19200: baud_rate = B19200; break;
676     case baud38400: baud_rate = B38400; break;
677     case baud57600: baud_rate = B57600; break;
678     default:
679     return false;
680     }
681     cfsetispeed(&mode, baud_rate);
682     cfsetospeed(&mode, baud_rate);
683     tcsetattr(fd, TCSANOW, &mode);
684     return true;
685     }
686    
687    
688     /*
689     * Set serial handshaking
690     */
691    
692     void XSERDPort::set_handshake(uint32 s, bool with_dtr)
693     {
694     D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n",
695     ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3),
696     ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7)));
697 cebix 1.12 if (protocol != serial)
698 cebix 1.1 return;
699    
700     if (with_dtr) {
701     if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR))
702     mode.c_cflag |= CRTSCTS;
703     else
704     mode.c_cflag &= ~CRTSCTS;
705     } else {
706     if (ReadMacInt8(s + shkFCTS))
707     mode.c_cflag |= CRTSCTS;
708     else
709     mode.c_cflag &= ~CRTSCTS;
710     }
711    
712     D(bug(" %sware flow control\n", mode.c_cflag & CRTSCTS ? "hard" : "soft"));
713     tcsetattr(fd, TCSANOW, &mode);
714     }
715    
716    
717     /*
718     * Data input thread
719     */
720    
721     void *XSERDPort::input_func(void *arg)
722     {
723     XSERDPort *s = (XSERDPort *)arg;
724     while (!s->input_thread_cancel) {
725    
726     // Wait for commands
727     sem_wait(&s->input_signal);
728     if (s->quitting)
729     break;
730    
731     // Execute command
732     void *buf = Mac2HostAddr(ReadMacInt32(s->input_pb + ioBuffer));
733     uint32 length = ReadMacInt32(s->input_pb + ioReqCount);
734     D(bug("input_func waiting for %ld bytes of data...\n", length));
735     int32 actual = read(s->fd, buf, length);
736     D(bug(" %ld bytes received\n", actual));
737    
738     #if MONITOR
739     bug("Receiving serial data:\n");
740     uint8 *adr = (uint8 *)buf;
741     for (int i=0; i<actual; i++) {
742     bug("%02x ", adr[i]);
743     }
744     bug("\n");
745     #endif
746    
747     // KillIO called? Then simply return
748     if (s->io_killed) {
749    
750 cebix 1.6 WriteMacInt16(s->input_pb + ioResult, uint16(abortErr));
751 cebix 1.1 WriteMacInt32(s->input_pb + ioActCount, 0);
752     s->read_pending = s->read_done = false;
753    
754     } else {
755    
756     // Set error code
757     if (actual >= 0) {
758     WriteMacInt32(s->input_pb + ioActCount, actual);
759     WriteMacInt32(s->input_dt + serdtResult, noErr);
760     } else {
761     WriteMacInt32(s->input_pb + ioActCount, 0);
762 cebix 1.6 WriteMacInt32(s->input_dt + serdtResult, uint16(readErr));
763 cebix 1.1 }
764 cebix 1.12
765 cebix 1.1 // Trigger serial interrupt
766     D(bug(" triggering serial interrupt\n"));
767     s->read_done = true;
768     SetInterruptFlag(INTFLAG_SERIAL);
769     TriggerInterrupt();
770     }
771     }
772     return NULL;
773     }
774    
775    
776     /*
777     * Data output thread
778     */
779    
780     void *XSERDPort::output_func(void *arg)
781     {
782     XSERDPort *s = (XSERDPort *)arg;
783     while (!s->output_thread_cancel) {
784    
785     // Wait for commands
786     sem_wait(&s->output_signal);
787     if (s->quitting)
788     break;
789    
790     // Execute command
791     void *buf = Mac2HostAddr(ReadMacInt32(s->output_pb + ioBuffer));
792     uint32 length = ReadMacInt32(s->output_pb + ioReqCount);
793     D(bug("output_func transmitting %ld bytes of data...\n", length));
794    
795     #if MONITOR
796     bug("Sending serial data:\n");
797     uint8 *adr = (uint8 *)buf;
798     for (int i=0; i<length; i++) {
799     bug("%02x ", adr[i]);
800     }
801     bug("\n");
802     #endif
803    
804     int32 actual = write(s->fd, buf, length);
805     D(bug(" %ld bytes transmitted\n", actual));
806    
807     // KillIO called? Then simply return
808     if (s->io_killed) {
809    
810 cebix 1.6 WriteMacInt16(s->output_pb + ioResult, uint16(abortErr));
811 cebix 1.1 WriteMacInt32(s->output_pb + ioActCount, 0);
812     s->write_pending = s->write_done = false;
813    
814     } else {
815    
816     // Set error code
817     if (actual >= 0) {
818     WriteMacInt32(s->output_pb + ioActCount, actual);
819     WriteMacInt32(s->output_dt + serdtResult, noErr);
820     } else {
821     WriteMacInt32(s->output_pb + ioActCount, 0);
822 cebix 1.6 WriteMacInt32(s->output_dt + serdtResult, uint16(writErr));
823 cebix 1.1 }
824    
825     // Trigger serial interrupt
826     D(bug(" triggering serial interrupt\n"));
827     s->write_done = true;
828     SetInterruptFlag(INTFLAG_SERIAL);
829     TriggerInterrupt();
830     }
831     }
832     return NULL;
833     }