ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/serial_unix.cpp
Revision: 1.13
Committed: 2004-01-12T15:29:25Z (20 years, 10 months ago) by cebix
Branch: MAIN
CVS Tags: nigel-build-16, nigel-build-15
Changes since 1.12: +1 -1 lines
Log Message:
Happy New Year! :)

File Contents

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