home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / Unix / serial_unix.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-04-08  |  17.4 KB  |  752 lines

  1. /*
  2.  *  serial_unix.cpp - Serial device driver, Unix specific stuff
  3.  *
  4.  *  Basilisk II (C) 1997-2001 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.     input_thread_cancel = false;
  212.     output_thread_cancel = false;
  213.     if (sem_init(&input_signal, 0, 0) < 0)
  214.         goto open_error;
  215.     if (sem_init(&output_signal, 0, 0) < 0)
  216.         goto open_error; 
  217.     input_thread_active = (pthread_create(&input_thread, &thread_attr, input_func, this) == 0);
  218.     output_thread_active = (pthread_create(&output_thread, &thread_attr, output_func, this) == 0);
  219.     if (!input_thread_active || !output_thread_active)
  220.         goto open_error;
  221.     return noErr;
  222.  
  223. open_error:
  224.     if (input_thread_active) {
  225.         input_thread_cancel = true;
  226. #ifdef HAVE_PTHREAD_CANCEL
  227.         pthread_cancel(input_thread);
  228. #endif
  229.         pthread_join(input_thread, NULL);
  230.         sem_destroy(&input_signal);
  231.         input_thread_active = false;
  232.     }
  233.     if (output_thread_active) {
  234.         output_thread_cancel = true;
  235. #ifdef HAVE_PTHREAD_CANCEL
  236.         pthread_cancel(output_thread);
  237. #endif
  238.         pthread_join(output_thread, NULL);
  239.         sem_destroy(&output_signal);
  240.         output_thread_active = false;
  241.     }
  242.     if (fd > 0) {
  243.         ::close(fd);
  244.         fd = -1;
  245.     }
  246.     return openErr;
  247. }
  248.  
  249.  
  250. /*
  251.  *  Read data from port
  252.  */
  253.  
  254. int16 XSERDPort::prime_in(uint32 pb, uint32 dce)
  255. {
  256.     // Send input command to input_thread
  257.     read_done = false;
  258.     read_pending = true;
  259.     input_pb = pb;
  260.     WriteMacInt32(input_dt + serdtDCE, dce);
  261.     sem_post(&input_signal);
  262.     return 1;    // Command in progress
  263. }
  264.  
  265.  
  266. /*
  267.  *  Write data to port
  268.  */
  269.  
  270. int16 XSERDPort::prime_out(uint32 pb, uint32 dce)
  271. {
  272.     // Send output command to output_thread
  273.     write_done = false;
  274.     write_pending = true;
  275.     output_pb = pb;
  276.     WriteMacInt32(output_dt + serdtDCE, dce);
  277.     sem_post(&output_signal);
  278.     return 1;    // Command in progress
  279. }
  280.  
  281.  
  282. /*
  283.  *    Control calls
  284.  */
  285.  
  286. int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
  287. {
  288.     switch (code) {
  289.         case 1:            // KillIO
  290.             io_killed = true;
  291.             if (!is_parallel)
  292.                 tcflush(fd, TCIOFLUSH);
  293.             while (read_pending || write_pending)
  294.                 usleep(10000);
  295.             io_killed = false;
  296.             return noErr;
  297.  
  298.         case kSERDConfiguration:
  299.             if (configure(ReadMacInt16(pb + csParam)))
  300.                 return noErr;
  301.             else
  302.                 return paramErr;
  303.  
  304.         case kSERDInputBuffer:
  305.             return noErr;    // Not supported under Unix
  306.  
  307.         case kSERDSerHShake:
  308.             set_handshake(pb + csParam, false);
  309.             return noErr;
  310.  
  311.         case kSERDSetBreak:
  312.             if (!is_parallel)
  313.                 tcsendbreak(fd, 0);
  314.             return noErr;
  315.  
  316.         case kSERDClearBreak:
  317.             return noErr;
  318.  
  319.         case kSERDBaudRate: {
  320.             if (is_parallel)
  321.                 return noErr;
  322.             uint16 rate = ReadMacInt16(pb + csParam);
  323.             speed_t baud_rate;
  324.             if (rate <= 50) {
  325.                 rate = 50; baud_rate = B50;
  326.             } else if (rate <= 75) {
  327.                 rate = 75; baud_rate = B75;
  328.             } else if (rate <= 110) {
  329.                 rate = 110; baud_rate = B110;
  330.             } else if (rate <= 134) {
  331.                 rate = 134; baud_rate = B134;
  332.             } else if (rate <= 150) {
  333.                 rate = 150; baud_rate = B150;
  334.             } else if (rate <= 200) {
  335.                 rate = 200; baud_rate = B200;
  336.             } else if (rate <= 300) {
  337.                 rate = 300; baud_rate = B300;
  338.             } else if (rate <= 600) {
  339.                 rate = 600; baud_rate = B600;
  340.             } else if (rate <= 1200) {
  341.                 rate = 1200; baud_rate = B1200;
  342.             } else if (rate <= 1800) {
  343.                 rate = 1800; baud_rate = B1800;
  344.             } else if (rate <= 2400) {
  345.                 rate = 2400; baud_rate = B2400;
  346.             } else if (rate <= 4800) {
  347.                 rate = 4800; baud_rate = B4800;
  348.             } else if (rate <= 9600) {
  349.                 rate = 9600; baud_rate = B9600;
  350.             } else if (rate <= 19200) {
  351.                 rate = 19200; baud_rate = B19200;
  352.             } else if (rate <= 38400) {
  353.                 rate = 38400; baud_rate = B38400;
  354.             } else if (rate <= 57600) {
  355.                 rate = 57600; baud_rate = B57600;
  356.             } else {
  357.                 // Just for safety in case someone wants a rate between 57600 and 65535
  358.                 rate = 57600; baud_rate = B57600;
  359.             }
  360.             WriteMacInt16(pb + csParam, rate);
  361.             cfsetispeed(&mode, B115200);
  362.             cfsetospeed(&mode, B115200);
  363.             tcsetattr(fd, TCSANOW, &mode);
  364.             return noErr;
  365.         }
  366.  
  367.         case kSERDHandshake:
  368.         case kSERDHandshakeRS232:
  369.             set_handshake(pb + csParam, true);
  370.             return noErr;
  371.  
  372.         case kSERDMiscOptions:
  373.             if (is_parallel)
  374.                 return noErr;
  375.             if (ReadMacInt8(pb + csParam) & kOptionPreserveDTR)
  376.                 mode.c_cflag &= ~HUPCL;
  377.             else
  378.                 mode.c_cflag |= HUPCL;
  379.             tcsetattr(fd, TCSANOW, &mode);
  380.             return noErr;
  381.  
  382.         case kSERDAssertDTR: {
  383.             if (is_parallel)
  384.                 return noErr;
  385.             unsigned int status = TIOCM_DTR;
  386.             ioctl(fd, TIOCMBIS, &status);
  387.             return noErr;
  388.         }
  389.  
  390.         case kSERDNegateDTR: {
  391.             if (is_parallel)
  392.                 return noErr;
  393.             unsigned int status = TIOCM_DTR;
  394.             ioctl(fd, TIOCMBIC, &status);
  395.             return noErr;
  396.         }
  397.  
  398.         case kSERDSetPEChar:
  399.         case kSERDSetPEAltChar:
  400.             return noErr;    // Not supported under Unix
  401.  
  402.         case kSERDResetChannel:
  403.             if (!is_parallel)
  404.                 tcflush(fd, TCIOFLUSH);
  405.             return noErr;
  406.  
  407.         case kSERDAssertRTS: {
  408.             if (is_parallel)
  409.                 return noErr;
  410.             unsigned int status = TIOCM_RTS;
  411.             ioctl(fd, TIOCMBIS, &status);
  412.             return noErr;
  413.         }
  414.  
  415.         case kSERDNegateRTS: {
  416.             if (is_parallel)
  417.                 return noErr;
  418.             unsigned int status = TIOCM_RTS;
  419.             ioctl(fd, TIOCMBIC, &status);
  420.             return noErr;
  421.         }
  422.  
  423.         case kSERD115KBaud:
  424.             if (is_parallel)
  425.                 return noErr;
  426.             cfsetispeed(&mode, B115200);
  427.             cfsetospeed(&mode, B115200);
  428.             tcsetattr(fd, TCSANOW, &mode);
  429.             return noErr;
  430.  
  431.         case kSERD230KBaud:
  432.         case kSERDSetHighSpeed:
  433.             if (is_parallel)
  434.                 return noErr;
  435.             cfsetispeed(&mode, B230400);
  436.             cfsetospeed(&mode, B230400);
  437.             tcsetattr(fd, TCSANOW, &mode);
  438.             return noErr;
  439.  
  440.         default:
  441.             printf("WARNING: SerialControl(): unimplemented control code %d\n", code);
  442.             return controlErr;
  443.     }
  444. }
  445.  
  446.  
  447. /*
  448.  *    Status calls
  449.  */
  450.  
  451. int16 XSERDPort::status(uint32 pb, uint32 dce, uint16 code)
  452. {
  453.     switch (code) {
  454.         case kSERDInputCount: {
  455.             int num;
  456.             ioctl(fd, FIONREAD, &num);
  457.             WriteMacInt32(pb + csParam, num);
  458.             return noErr;
  459.         }
  460.  
  461.         case kSERDStatus: {
  462.             uint32 p = pb + csParam;
  463.             WriteMacInt8(p + staCumErrs, cum_errors);
  464.             cum_errors = 0;
  465.             WriteMacInt8(p + staXOffSent, 0);
  466.             WriteMacInt8(p + staXOffHold, 0);
  467.             WriteMacInt8(p + staRdPend, read_pending);
  468.             WriteMacInt8(p + staWrPend, write_pending);
  469.             if (is_parallel) {
  470.                 WriteMacInt8(p + staCtsHold, 0);
  471.                 WriteMacInt8(p + staDsrHold, 0);
  472.                 WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent);
  473.             } else {
  474.                 unsigned int status;
  475.                 ioctl(fd, TIOCMGET, &status);
  476.                 WriteMacInt8(p + staCtsHold, status & TIOCM_CTS ? 0 : 1);
  477.                 WriteMacInt8(p + staDsrHold, status & TIOCM_DTR ? 0 : 1);
  478.                 WriteMacInt8(p + staModemStatus,
  479.                     (status & TIOCM_DSR ? dsrEvent : 0)
  480.                     | (status & TIOCM_RI ? riEvent : 0)
  481.                     | (status & TIOCM_CD ? dcdEvent : 0)
  482.                     | (status & TIOCM_CTS ? ctsEvent : 0));
  483.             }
  484.             return noErr;
  485.         }
  486.  
  487.         default:
  488.             printf("WARNING: SerialStatus(): unimplemented status code %d\n", code);
  489.             return statusErr;
  490.     }
  491. }
  492.  
  493.  
  494. /*
  495.  *    Close serial port
  496.  */
  497.  
  498. int16 XSERDPort::close()
  499. {
  500.     // Kill threads
  501.     if (input_thread_active) {
  502.         quitting = true;
  503.         sem_post(&input_signal);
  504.         pthread_join(input_thread, NULL);
  505.         input_thread_active = false;
  506.         sem_destroy(&input_signal);
  507.     }
  508.     if (output_thread_active) {
  509.         quitting = true;
  510.         sem_post(&output_signal);
  511.         pthread_join(output_thread, NULL);
  512.         output_thread_active = false;
  513.         sem_destroy(&output_signal);
  514.     }
  515.  
  516.     // Close port
  517.     if (fd > 0)
  518.         ::close(fd);
  519.     fd = -1;
  520.     return noErr;
  521. }
  522.  
  523.  
  524. /*
  525.  *  Configure serial port with MacOS config word
  526.  */
  527.  
  528. bool XSERDPort::configure(uint16 config)
  529. {
  530.     D(bug(" configure %04x\n", config));
  531.     if (is_parallel)
  532.         return true;
  533.  
  534.     // Set number of stop bits
  535.     switch (config & 0xc000) {
  536.         case stop10:
  537.             mode.c_cflag &= ~CSTOPB;
  538.             break;
  539.         case stop20:
  540.             mode.c_cflag |= CSTOPB;
  541.             break;
  542.         default:
  543.             return false;
  544.     }
  545.  
  546.     // Set parity mode
  547.     switch (config & 0x3000) {
  548.         case noParity:
  549.             mode.c_iflag &= ~INPCK;
  550.             mode.c_oflag &= ~PARENB;
  551.             break;
  552.         case oddParity:
  553.             mode.c_iflag |= INPCK;
  554.             mode.c_oflag |= PARENB;
  555.             mode.c_oflag |= PARODD;
  556.             break;
  557.         case evenParity:
  558.             mode.c_iflag |= INPCK;
  559.             mode.c_oflag |= PARENB;
  560.             mode.c_oflag &= ~PARODD;
  561.             break;
  562.         default:
  563.             return false;
  564.     }
  565.  
  566.     // Set number of data bits
  567.     switch (config & 0x0c00) {
  568.         case data5:
  569.             mode.c_cflag = mode.c_cflag & ~CSIZE | CS5;
  570.             break;
  571.         case data6:
  572.             mode.c_cflag = mode.c_cflag & ~CSIZE | CS6;
  573.             break;
  574.         case data7:
  575.             mode.c_cflag = mode.c_cflag & ~CSIZE | CS7;
  576.             break;
  577.         case data8:
  578.             mode.c_cflag = mode.c_cflag & ~CSIZE | CS8;
  579.             break;
  580.     }
  581.  
  582.     // Set baud rate
  583.     speed_t baud_rate;
  584.     switch (config & 0x03ff) {
  585.         case baud150: baud_rate = B150; break;
  586.         case baud300: baud_rate = B300; break;
  587.         case baud600: baud_rate = B600; break;
  588.         case baud1200: baud_rate = B1200; break;
  589.         case baud1800: baud_rate = B1800; break;
  590.         case baud2400: baud_rate = B2400; break;
  591.         case baud4800: baud_rate = B4800; break;
  592.         case baud9600: baud_rate = B9600; break;
  593.         case baud19200: baud_rate = B19200; break;
  594.         case baud38400: baud_rate = B38400; break;
  595.         case baud57600: baud_rate = B57600; break;
  596.         default:
  597.             return false;
  598.     }
  599.     cfsetispeed(&mode, baud_rate);
  600.     cfsetospeed(&mode, baud_rate);
  601.     tcsetattr(fd, TCSANOW, &mode);
  602.     return true;
  603. }
  604.  
  605.  
  606. /*
  607.  *  Set serial handshaking
  608.  */
  609.  
  610. void XSERDPort::set_handshake(uint32 s, bool with_dtr)
  611. {
  612.     D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n",
  613.         ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3),
  614.         ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7)));
  615.     if (is_parallel)
  616.         return;
  617.  
  618.     if (with_dtr) {
  619.         if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR))
  620.             mode.c_cflag |= CRTSCTS;
  621.         else
  622.             mode.c_cflag &= ~CRTSCTS;
  623.     } else {
  624.         if (ReadMacInt8(s + shkFCTS))
  625.             mode.c_cflag |= CRTSCTS;
  626.         else
  627.             mode.c_cflag &= ~CRTSCTS;
  628.     }
  629.  
  630.     D(bug(" %sware flow control\n", mode.c_cflag & CRTSCTS ? "hard" : "soft"));
  631.     tcsetattr(fd, TCSANOW, &mode);
  632. }
  633.  
  634.  
  635. /*
  636.  *  Data input thread
  637.  */
  638.  
  639. void *XSERDPort::input_func(void *arg)
  640. {
  641.     XSERDPort *s = (XSERDPort *)arg;
  642.     while (!s->input_thread_cancel) {
  643.  
  644.         // Wait for commands
  645.         sem_wait(&s->input_signal);
  646.         if (s->quitting)
  647.             break;
  648.  
  649.         // Execute command
  650.         void *buf = Mac2HostAddr(ReadMacInt32(s->input_pb + ioBuffer));
  651.         uint32 length = ReadMacInt32(s->input_pb + ioReqCount);
  652.         D(bug("input_func waiting for %ld bytes of data...\n", length));
  653.         int32 actual = read(s->fd, buf, length);
  654.         D(bug(" %ld bytes received\n", actual));
  655.  
  656. #if MONITOR
  657.         bug("Receiving serial data:\n");
  658.         uint8 *adr = (uint8 *)buf;
  659.         for (int i=0; i<actual; i++) {
  660.             bug("%02x ", adr[i]);
  661.         }
  662.         bug("\n");
  663. #endif
  664.  
  665.         // KillIO called? Then simply return
  666.         if (s->io_killed) {
  667.  
  668.             WriteMacInt16(s->input_pb + ioResult, uint16(abortErr));
  669.             WriteMacInt32(s->input_pb + ioActCount, 0);
  670.             s->read_pending = s->read_done = false;
  671.  
  672.         } else {
  673.  
  674.             // Set error code
  675.             if (actual >= 0) {
  676.                 WriteMacInt32(s->input_pb + ioActCount, actual);
  677.                 WriteMacInt32(s->input_dt + serdtResult, noErr);
  678.             } else {
  679.                 WriteMacInt32(s->input_pb + ioActCount, 0);
  680.                 WriteMacInt32(s->input_dt + serdtResult, uint16(readErr));
  681.             }
  682.     
  683.             // Trigger serial interrupt
  684.             D(bug(" triggering serial interrupt\n"));
  685.             s->read_done = true;
  686.             SetInterruptFlag(INTFLAG_SERIAL);
  687.             TriggerInterrupt();
  688.         }
  689.     }
  690.     return NULL;
  691. }
  692.  
  693.  
  694. /*
  695.  *  Data output thread
  696.  */
  697.  
  698. void *XSERDPort::output_func(void *arg)
  699. {
  700.     XSERDPort *s = (XSERDPort *)arg;
  701.     while (!s->output_thread_cancel) {
  702.  
  703.         // Wait for commands
  704.         sem_wait(&s->output_signal);
  705.         if (s->quitting)
  706.             break;
  707.  
  708.         // Execute command
  709.         void *buf = Mac2HostAddr(ReadMacInt32(s->output_pb + ioBuffer));
  710.         uint32 length = ReadMacInt32(s->output_pb + ioReqCount);
  711.         D(bug("output_func transmitting %ld bytes of data...\n", length));
  712.  
  713. #if MONITOR
  714.         bug("Sending serial data:\n");
  715.         uint8 *adr = (uint8 *)buf;
  716.         for (int i=0; i<length; i++) {
  717.             bug("%02x ", adr[i]);
  718.         }
  719.         bug("\n");
  720. #endif
  721.  
  722.         int32 actual = write(s->fd, buf, length);
  723.         D(bug(" %ld bytes transmitted\n", actual));
  724.  
  725.         // KillIO called? Then simply return
  726.         if (s->io_killed) {
  727.  
  728.             WriteMacInt16(s->output_pb + ioResult, uint16(abortErr));
  729.             WriteMacInt32(s->output_pb + ioActCount, 0);
  730.             s->write_pending = s->write_done = false;
  731.  
  732.         } else {
  733.  
  734.             // Set error code
  735.             if (actual >= 0) {
  736.                 WriteMacInt32(s->output_pb + ioActCount, actual);
  737.                 WriteMacInt32(s->output_dt + serdtResult, noErr);
  738.             } else {
  739.                 WriteMacInt32(s->output_pb + ioActCount, 0);
  740.                 WriteMacInt32(s->output_dt + serdtResult, uint16(writErr));
  741.             }
  742.     
  743.             // Trigger serial interrupt
  744.             D(bug(" triggering serial interrupt\n"));
  745.             s->write_done = true;
  746.             SetInterruptFlag(INTFLAG_SERIAL);
  747.             TriggerInterrupt();
  748.         }
  749.     }
  750.     return NULL;
  751. }
  752.