home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / Unix / serial_unix.cpp < prev    next >
C/C++ Source or Header  |  1999-10-19  |  18KB  |  750 lines

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