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

  1. /*
  2.  *  serial_beos.cpp - Serial device driver, BeOS 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 <string.h>
  22. #include <stdio.h>
  23. #include <unistd.h>
  24. #include <DeviceKit.h>
  25.  
  26. #include "sysdeps.h"
  27. #include "cpu_emulation.h"
  28. #include "main.h"
  29. #include "macos_util.h"
  30. #include "prefs.h"
  31. #include "serial.h"
  32. #include "serial_defs.h"
  33.  
  34. #define DEBUG 0
  35. #include "debug.h"
  36.  
  37. #define MONITOR 0
  38.  
  39.  
  40. // Buffer size for kernel-space transfers
  41. const int TMP_BUF_SIZE = 2048;
  42.  
  43. // These packets are sent to the input/output threads
  44. const uint32 CMD_READ = 'read';
  45. const uint32 CMD_WRITE = 'writ';
  46. const uint32 CMD_QUIT = 'quit';
  47.  
  48. struct ThreadPacket {
  49.     uint32 pb;
  50. };
  51.  
  52.  
  53. // Driver private variables
  54. class BeSERDPort : public SERDPort {
  55. public:
  56.     BeSERDPort(const char *dev)
  57.     {
  58.         device_name = dev;
  59.         if (strstr(dev, "parallel")) {
  60.             is_parallel = true;
  61.             fd = -1;
  62.             device = NULL;
  63.         } else {
  64.             is_parallel = false;
  65.             device = new BSerialPort;    
  66.         }
  67.         device_sem = create_sem(1, "serial port");
  68.         input_thread = output_thread = 0;
  69.     }
  70.  
  71.     virtual ~BeSERDPort()
  72.     {
  73.         status_t l;
  74.         if (input_thread > 0) {
  75.             send_data(input_thread, CMD_QUIT, NULL, 0);
  76.             suspend_thread(input_thread);    // Unblock thread
  77.             snooze(1000);
  78.             resume_thread(input_thread);
  79.             wait_for_thread(input_thread, &l);
  80.         }
  81.         if (output_thread > 0) {
  82.             send_data(output_thread, CMD_QUIT, NULL, 0);
  83.             suspend_thread(output_thread);    // Unblock thread
  84.             snooze(1000);
  85.             resume_thread(output_thread);
  86.             wait_for_thread(output_thread, &l);
  87.         }
  88.         acquire_sem(device_sem);
  89.         delete_sem(device_sem);
  90.         delete device;
  91.     }
  92.  
  93.     virtual int16 open(uint16 config);
  94.     virtual int16 prime_in(uint32 pb, uint32 dce);
  95.     virtual int16 prime_out(uint32 pb, uint32 dce);
  96.     virtual int16 control(uint32 pb, uint32 dce, uint16 code);
  97.     virtual int16 status(uint32 pb, uint32 dce, uint16 code);
  98.     virtual int16 close(void);
  99.  
  100. private:
  101.     bool configure(uint16 config);
  102.     void set_handshake(uint32 s, bool with_dtr);
  103.     static status_t input_func(void *arg);
  104.     static status_t output_func(void *arg);
  105.  
  106.     const char *device_name;    // Name of BeOS port
  107.     BSerialPort *device;        // BeOS port object
  108.     bool is_parallel;            // Flag: Port is parallel, use fd
  109.     int fd;                        // FD for parallel ports
  110.     sem_id device_sem;            // BSerialPort arbitration
  111.  
  112.     thread_id input_thread;        // Data input thread
  113.     thread_id output_thread;    // Data output thread
  114.  
  115.     bool io_killed;                // Flag: KillIO called, I/O threads must not call deferred tasks
  116.     bool drop_dtr_on_close;        // Flag: Negate DTR when driver is closed
  117.  
  118.     uint8 tmp_in_buf[TMP_BUF_SIZE];        // Buffers for copying from/to kernel space
  119.     uint8 tmp_out_buf[TMP_BUF_SIZE];
  120. };
  121.  
  122.  
  123. #if DEBUG
  124. static const int baud_rates[] = {
  125.     0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 31250
  126. };
  127. #endif
  128.  
  129.  
  130. /*
  131.  *  Initialization
  132.  */
  133.  
  134. void SerialInit(void)
  135. {
  136.     // Read serial preferences and create structs for both ports
  137.     the_serd_port[0] = new BeSERDPort(PrefsFindString("seriala"));
  138.     the_serd_port[1] = new BeSERDPort(PrefsFindString("serialb"));
  139. }
  140.  
  141.  
  142. /*
  143.  *  Deinitialization
  144.  */
  145.  
  146. void SerialExit(void)
  147. {
  148.     delete (BeSERDPort *)the_serd_port[0];
  149.     delete (BeSERDPort *)the_serd_port[1];
  150. }
  151.  
  152.  
  153. /*
  154.  *  Open serial port
  155.  */
  156.  
  157. int16 BeSERDPort::open(uint16 config)
  158. {
  159.     // Don't open NULL name devices
  160.     if (device_name == NULL)
  161.         return openErr;
  162.  
  163.     // Init variables
  164.     io_killed = false;
  165.     drop_dtr_on_close = true;
  166.  
  167.     // Open port
  168.     while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  169.     if (is_parallel) {
  170.         char name[256];
  171.         sprintf(name, "/dev/parallel/%s", device_name);
  172.         fd = ::open(name, O_WRONLY);
  173.         if (fd < 0) {
  174.             release_sem(device_sem);
  175.             return openErr;
  176.         }
  177.     } else {
  178.         device->SetFlowControl(B_HARDWARE_CONTROL);    // Must be set before port is opened
  179.         if (device->Open(device_name) > 0) {
  180.             device->SetBlocking(true);
  181.             device->SetTimeout(10000000);
  182.             device->SetDTR(true);
  183.             device->SetRTS(true);
  184.         } else {
  185.             release_sem(device_sem);
  186.             return openErr;
  187.         }
  188.     }
  189.  
  190.     // Start input/output threads
  191.     release_sem(device_sem);
  192.     configure(config);
  193.     while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  194.     while ((input_thread = spawn_thread(input_func, "Serial Input", B_NORMAL_PRIORITY, this)) == B_INTERRUPTED) ;
  195.     resume_thread(input_thread);
  196.     while ((output_thread = spawn_thread(output_func, "Serial Output", B_NORMAL_PRIORITY, this)) == B_INTERRUPTED) ;
  197.     resume_thread(output_thread);
  198.     release_sem(device_sem);
  199.     return noErr;
  200. }
  201.  
  202.  
  203. /*
  204.  *  Read data from port
  205.  */
  206.  
  207. int16 BeSERDPort::prime_in(uint32 pb, uint32 dce)
  208. {
  209.     // Send input command to input_thread
  210.     read_done = false;
  211.     read_pending = true;
  212.     ThreadPacket p;
  213.     p.pb = pb;
  214.     WriteMacInt32(input_dt + serdtDCE, dce);
  215.     while (send_data(input_thread, CMD_READ, &p, sizeof(ThreadPacket)) == B_INTERRUPTED) ;
  216.     return 1;    // Command in progress
  217. }
  218.  
  219.  
  220. /*
  221.  *  Write data to port
  222.  */
  223.  
  224. int16 BeSERDPort::prime_out(uint32 pb, uint32 dce)
  225. {
  226.     // Send output command to output_thread
  227.     write_done = false;
  228.     write_pending = true;
  229.     ThreadPacket p;
  230.     p.pb = pb;
  231.     WriteMacInt32(output_dt + serdtDCE, dce);
  232.     while (send_data(output_thread, CMD_WRITE, &p, sizeof(ThreadPacket)) == B_INTERRUPTED) ;
  233.     return 1;    // Command in progress
  234. }
  235.  
  236.  
  237. /*
  238.  *    Control calls
  239.  */
  240.  
  241. int16 BeSERDPort::control(uint32 pb, uint32 dce, uint16 code)
  242. {
  243.     switch (code) {
  244.         case 1:            // KillIO
  245.             io_killed = true;
  246.             suspend_thread(input_thread);    // Unblock threads
  247.             suspend_thread(output_thread);
  248.             snooze(1000);
  249.             resume_thread(input_thread);
  250.             resume_thread(output_thread);
  251.             while (read_pending || write_pending)
  252.                 snooze(10000);
  253.             if (!is_parallel) {
  254.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  255.                 device->ClearInput();
  256.                 device->ClearOutput();
  257.                 release_sem(device_sem);
  258.             }
  259.             io_killed = false;
  260.             return noErr;
  261.  
  262.         case kSERDConfiguration:
  263.             if (configure(ReadMacInt16(pb + csParam)))
  264.                 return noErr;
  265.             else
  266.                 return paramErr;
  267.  
  268.         case kSERDInputBuffer:
  269.             return noErr;    // Not supported under BeOS
  270.  
  271.         case kSERDSerHShake:
  272.             set_handshake(pb + csParam, false);
  273.             return noErr;
  274.  
  275.         case kSERDClearBreak:
  276.         case kSERDSetBreak:
  277.             return noErr;    // Not supported under BeOS
  278.  
  279.         case kSERDBaudRate:
  280.             if (!is_parallel) {
  281.                 uint16 rate = ReadMacInt16(pb + csParam);
  282.                 data_rate baud_rate;
  283.                 if (rate <= 50) {
  284.                     rate = 50; baud_rate = B_50_BPS;
  285.                 } else if (rate <= 75) {
  286.                     rate = 75; baud_rate = B_75_BPS;
  287.                 } else if (rate <= 110) {
  288.                     rate = 110; baud_rate = B_110_BPS;
  289.                 } else if (rate <= 134) {
  290.                     rate = 134; baud_rate = B_134_BPS;
  291.                 } else if (rate <= 150) {
  292.                     rate = 150; baud_rate = B_150_BPS;
  293.                 } else if (rate <= 200) {
  294.                     rate = 200; baud_rate = B_200_BPS;
  295.                 } else if (rate <= 300) {
  296.                     rate = 300; baud_rate = B_300_BPS;
  297.                 } else if (rate <= 600) {
  298.                     rate = 600; baud_rate = B_600_BPS;
  299.                 } else if (rate <= 1200) {
  300.                     rate = 1200; baud_rate = B_1200_BPS;
  301.                 } else if (rate <= 1800) {
  302.                     rate = 1800; baud_rate = B_1800_BPS;
  303.                 } else if (rate <= 2400) {
  304.                     rate = 2400; baud_rate = B_2400_BPS;
  305.                 } else if (rate <= 4800) {
  306.                     rate = 4800; baud_rate = B_4800_BPS;
  307.                 } else if (rate <= 9600) {
  308.                     rate = 9600; baud_rate = B_9600_BPS;
  309.                 } else if (rate <= 19200) {
  310.                     rate = 19200; baud_rate = B_19200_BPS;
  311.                 } else if (rate <= 31250) {
  312.                     rate = 31250; baud_rate = B_31250_BPS;
  313.                 } else if (rate <= 38400) {
  314.                     rate = 38400; baud_rate = B_38400_BPS;
  315.                 } else if (rate <= 57600) {
  316.                     rate = 57600; baud_rate = B_57600_BPS;
  317.                 }
  318.                 WriteMacInt16(pb + csParam, rate);
  319.                 acquire_sem(device_sem);
  320.                 if (device->SetDataRate(baud_rate) == B_OK) {
  321.                     release_sem(device_sem);
  322.                     return noErr;
  323.                 } else {
  324.                     release_sem(device_sem);
  325.                     return paramErr;
  326.                 }
  327.             } else
  328.                 return noErr;
  329.  
  330.         case kSERDHandshake:
  331.         case kSERDHandshakeRS232:
  332.             set_handshake(pb + csParam, true);
  333.             return noErr;
  334.  
  335.         case kSERDClockMIDI:
  336.             if (!is_parallel) {
  337.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  338.                 device->SetParityMode(B_NO_PARITY);
  339.                 device->SetDataBits(B_DATA_BITS_8);
  340.                 device->SetStopBits(B_STOP_BITS_1);
  341.                 if (device->SetDataRate(B_31250_BPS) == B_OK) {
  342.                     release_sem(device_sem);
  343.                     return noErr;
  344.                 } else {
  345.                     release_sem(device_sem);
  346.                     return paramErr;
  347.                 }
  348.             } else
  349.                 return noErr;
  350.  
  351.         case kSERDMiscOptions:
  352.             drop_dtr_on_close = !(ReadMacInt8(pb + csParam) & kOptionPreserveDTR);
  353.             return noErr;
  354.  
  355.         case kSERDAssertDTR:
  356.             if (!is_parallel) {
  357.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  358.                 device->SetDTR(true);
  359.                 release_sem(device_sem);
  360.             }
  361.             return noErr;
  362.  
  363.         case kSERDNegateDTR:
  364.             if (!is_parallel) {
  365.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  366.                 device->SetDTR(false);
  367.                 release_sem(device_sem);
  368.             }
  369.             return noErr;
  370.  
  371.         case kSERDSetPEChar:
  372.         case kSERDSetPEAltChar:
  373.             return noErr;    // Not supported under BeOS
  374.  
  375.         case kSERDResetChannel:
  376.             if (!is_parallel) {
  377.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  378.                 device->ClearInput();
  379.                 device->ClearOutput();
  380.                 release_sem(device_sem);
  381.             }
  382.             return noErr;
  383.  
  384.         case kSERDAssertRTS:
  385.             if (!is_parallel) {
  386.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  387.                 device->SetRTS(true);
  388.                 release_sem(device_sem);
  389.             }
  390.             return noErr;
  391.  
  392.         case kSERDNegateRTS:
  393.             if (!is_parallel) {
  394.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  395.                 device->SetRTS(false);
  396.                 release_sem(device_sem);
  397.             }
  398.             return noErr;
  399.  
  400.         case kSERD115KBaud:
  401.             if (!is_parallel) {
  402.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  403.                 if (device->DataRate() != B_115200_BPS)
  404.                     if (device->SetDataRate(B_115200_BPS) != B_OK) {
  405.                         release_sem(device_sem);
  406.                         return paramErr;
  407.                     }
  408.                 release_sem(device_sem);
  409.             }
  410.             return noErr;
  411.  
  412.         case kSERD230KBaud:
  413.         case kSERDSetHighSpeed:
  414.             if (!is_parallel) {
  415.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  416.                 if (device->DataRate() != B_230400_BPS)
  417.                     if (device->SetDataRate(B_230400_BPS) != B_OK) {
  418.                         release_sem(device_sem);
  419.                         return paramErr;
  420.                     }
  421.                 release_sem(device_sem);
  422.             }
  423.             return noErr;
  424.  
  425.         default:
  426.             printf("WARNING: SerialControl(): unimplemented control code %d\n", code);
  427.             return controlErr;
  428.     }
  429. }
  430.  
  431.  
  432. /*
  433.  *    Status calls
  434.  */
  435.  
  436. int16 BeSERDPort::status(uint32 pb, uint32 dce, uint16 code)
  437. {
  438.     switch (code) {
  439.         case kSERDInputCount:
  440.             WriteMacInt32(pb + csParam, 0);
  441.             if (!is_parallel) {
  442.                 int32 num = 0;
  443.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  444.                 device->NumCharsAvailable(&num);
  445.                 release_sem(device_sem);
  446.                 D(bug(" %d bytes in buffer\n", num));
  447.                 WriteMacInt32(pb + csParam, num);
  448.             }
  449.             return noErr;
  450.  
  451.         case kSERDStatus: {
  452.             uint32 p = pb + csParam;
  453.             WriteMacInt8(p + staCumErrs, cum_errors);
  454.             cum_errors = 0;
  455.             WriteMacInt8(p + staXOffSent, 0);
  456.             WriteMacInt8(p + staXOffHold, 0);
  457.             WriteMacInt8(p + staRdPend, read_pending);
  458.             WriteMacInt8(p + staWrPend, write_pending);
  459.             if (is_parallel) {
  460.                 WriteMacInt8(p + staCtsHold, 0);
  461.                 WriteMacInt8(p + staDsrHold, 0);
  462.                 WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent);
  463.             } else {
  464.                 while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  465.                 WriteMacInt8(p + staCtsHold, !device->IsCTS());
  466.                 WriteMacInt8(p + staDsrHold, !device->IsDSR());
  467.                 WriteMacInt8(p + staModemStatus,
  468.                     (device->IsDSR() ? dsrEvent : 0)
  469.                     | (device->IsRI() ? riEvent : 0)
  470.                     | (device->IsDCD() ? dcdEvent : 0)
  471.                     | (device->IsCTS() ? ctsEvent : 0));
  472.                 release_sem(device_sem);
  473.             }
  474.             return noErr;
  475.         }
  476.  
  477.         default:
  478.             printf("WARNING: SerialStatus(): unimplemented status code %d\n", code);
  479.             return statusErr;
  480.     }
  481. }
  482.  
  483.  
  484. /*
  485.  *    Close serial port
  486.  */
  487.  
  488. int16 BeSERDPort::close()
  489. {
  490.     // Kill threads
  491.     status_t l;
  492.     io_killed = true;
  493.     if (input_thread > 0) {
  494.         while (send_data(input_thread, CMD_QUIT, NULL, 0) == B_INTERRUPTED) ;
  495.         if (read_pending) {
  496.             suspend_thread(input_thread);    // Unblock thread
  497.             snooze(1000);
  498.             resume_thread(input_thread);
  499.         }
  500.         while (wait_for_thread(input_thread, &l) == B_INTERRUPTED) ;
  501.     }
  502.     if (output_thread > 0) {
  503.         while (send_data(output_thread, CMD_QUIT, NULL, 0) == B_INTERRUPTED) ;
  504.         if (write_pending) {
  505.             suspend_thread(output_thread);    // Unblock thread
  506.             snooze(1000);
  507.             resume_thread(output_thread);
  508.         }
  509.         while (wait_for_thread(output_thread, &l) == B_INTERRUPTED) ;
  510.     }
  511.     input_thread = output_thread = 0;
  512.  
  513.     // Close port
  514.     while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  515.     if (is_parallel) {
  516.         ::close(fd);
  517.         fd = -1;
  518.     } else {
  519.         if (drop_dtr_on_close)
  520.             device->SetDTR(false);
  521.         device->Close();
  522.     }
  523.     release_sem(device_sem);
  524.     return noErr;
  525. }
  526.  
  527.  
  528. /*
  529.  *  Configure serial port with MacOS config word
  530.  */
  531.  
  532. bool BeSERDPort::configure(uint16 config)
  533. {
  534.     D(bug(" configure %04x\n", config));
  535.     if (is_parallel)
  536.         return true;
  537.  
  538.     while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  539.  
  540.     // Set number of stop bits
  541.     switch (config & 0xc000) {
  542.         case stop10:
  543.             if (device->StopBits() != B_STOP_BITS_1)
  544.                 device->SetStopBits(B_STOP_BITS_1);
  545.             break;
  546.         case stop20:
  547.             if (device->StopBits() != B_STOP_BITS_2)
  548.                 device->SetStopBits(B_STOP_BITS_2);
  549.             break;
  550.         default:
  551.             release_sem(device_sem);
  552.             return false;
  553.     }
  554.  
  555.     // Set parity mode
  556.     switch (config & 0x3000) {
  557.         case noParity:
  558.             if (device->ParityMode() != B_NO_PARITY)
  559.                 device->SetParityMode(B_NO_PARITY);
  560.             break;
  561.         case oddParity:
  562.             if (device->ParityMode() != B_ODD_PARITY)
  563.                 device->SetParityMode(B_ODD_PARITY);
  564.             break;
  565.         case evenParity:
  566.             if (device->ParityMode() != B_EVEN_PARITY)
  567.                 device->SetParityMode(B_EVEN_PARITY);
  568.             break;
  569.         default:
  570.             release_sem(device_sem);
  571.             return false;
  572.     }
  573.  
  574.     // Set number of data bits
  575.     switch (config & 0x0c00) {
  576.         case data7:
  577.             if (device->DataBits() != B_DATA_BITS_7)
  578.                 device->SetDataBits(B_DATA_BITS_7);
  579.             break;
  580.         case data8:
  581.             if (device->DataBits() != B_DATA_BITS_8)
  582.                 device->SetDataBits(B_DATA_BITS_8);
  583.             break;
  584.         default:
  585.             release_sem(device_sem);
  586.             return false;
  587.     }
  588.  
  589.     // Set baud rate
  590.     data_rate baud_rate;
  591.     switch (config & 0x03ff) {
  592.         case baud150: baud_rate = B_150_BPS; break;
  593.         case baud300: baud_rate = B_300_BPS; break;
  594.         case baud600: baud_rate = B_600_BPS; break;
  595.         case baud1200: baud_rate = B_1200_BPS; break;
  596.         case baud1800: baud_rate = B_1800_BPS; break;
  597.         case baud2400: baud_rate = B_2400_BPS; break;
  598.         case baud4800: baud_rate = B_4800_BPS; break;
  599.         case baud9600: baud_rate = B_9600_BPS; break;
  600.         case baud19200: baud_rate = B_19200_BPS; break;
  601.         case baud38400: baud_rate = B_38400_BPS; break;
  602.         case baud57600: baud_rate = B_57600_BPS; break;
  603.         default:
  604.             release_sem(device_sem);
  605.             return false;
  606.     }
  607.  
  608.     D(bug(" baud rate %d, %d stop bits, %s parity, %d data bits\n", baud_rates[baud_rate], device->StopBits() == B_STOP_BITS_1 ? 1 : 2, device->ParityMode() == B_NO_PARITY ? "no" : device->ParityMode() == B_ODD_PARITY ? "odd" : "even", device->DataBits() == B_DATA_BITS_7 ? 7 : 8));
  609.     if (device->DataRate() != baud_rate) {
  610.         bool res = device->SetDataRate(baud_rate) == B_OK;
  611.         release_sem(device_sem);
  612.         return res;
  613.     } else {
  614.         release_sem(device_sem);
  615.         return true;
  616.     }
  617. }
  618.  
  619.  
  620. /*
  621.  *  Set serial handshaking
  622.  */
  623.  
  624. void BeSERDPort::set_handshake(uint32 s, bool with_dtr)
  625. {
  626.     D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n",
  627.         ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3),
  628.         ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7)));
  629.     if (is_parallel)
  630.         return;
  631.  
  632.     uint32 flow;
  633.     if (with_dtr) {
  634.         if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR))
  635.             flow = B_HARDWARE_CONTROL;
  636.         else
  637.             flow = B_SOFTWARE_CONTROL;
  638.     } else {
  639.         if (ReadMacInt8(s + shkFCTS))
  640.             flow = B_HARDWARE_CONTROL;
  641.         else
  642.             flow = B_SOFTWARE_CONTROL;
  643.     }
  644.  
  645.     D(bug(" %sware flow control\n", flow == B_HARDWARE_CONTROL ? "hard" : "soft"));
  646.     while (acquire_sem(device_sem) == B_INTERRUPTED) ;
  647.     if (device->FlowControl() != flow) {
  648.         device->Close();
  649.         device->SetFlowControl(flow);
  650.         device->Open(device_name);
  651.     }
  652.     release_sem(device_sem);
  653. }
  654.  
  655.  
  656. /*
  657.  *  Data input thread
  658.  */
  659.  
  660. status_t BeSERDPort::input_func(void *arg)
  661. {
  662.     BeSERDPort *s = (BeSERDPort *)arg;
  663.     for (;;) {
  664.  
  665.         // Wait for commands
  666.         thread_id sender;
  667.         ThreadPacket p;
  668.         uint32 code = receive_data(&sender, &p, sizeof(ThreadPacket));
  669.         if (code == CMD_QUIT)
  670.             break;
  671.         if (code != CMD_READ)
  672.             continue;
  673.  
  674.         // Execute command
  675.         void *buf = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer));
  676.         uint32 length = ReadMacInt32(p.pb + ioReqCount);
  677.         D(bug("input_func waiting for %ld bytes of data...\n", length));
  678.         int32 actual;
  679.  
  680.         // Buffer in kernel space?
  681.         if ((uint32)buf < 0x80000000) {
  682.     
  683.             // Yes, transfer via buffer
  684.             actual = 0;
  685.             while (length) {
  686.                 uint32 transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length;
  687.                 int32 transferred;
  688.                 acquire_sem(s->device_sem);
  689.                 if (s->is_parallel) {
  690.                     if ((transferred = read(s->fd, s->tmp_in_buf, transfer_size)) < 0 || s->io_killed) {
  691.                         // Error
  692.                         actual = transferred;
  693.                         release_sem(s->device_sem);
  694.                         break;
  695.                     }
  696.                 } else {
  697.                     if ((transferred = s->device->Read(s->tmp_in_buf, transfer_size)) < 0 || s->io_killed) {
  698.                         // Error
  699.                         actual = transferred;
  700.                         release_sem(s->device_sem);
  701.                         break;
  702.                     }
  703.                 }
  704.                 release_sem(s->device_sem);
  705.                 memcpy(buf, s->tmp_in_buf, transferred);
  706.                 buf = (void *)((uint8 *)buf + transferred);
  707.                 length -= transferred;
  708.                 actual += transferred;
  709.             }
  710.  
  711.         } else {
  712.  
  713.             // No, transfer directly
  714.             acquire_sem(s->device_sem);
  715.             if (s->is_parallel)
  716.                 actual = read(s->fd, buf, length);
  717.             else
  718.                 actual = s->device->Read(buf, length);
  719.             release_sem(s->device_sem);
  720.         }
  721.  
  722.         D(bug(" %ld bytes received\n", actual));
  723.  
  724. #if MONITOR
  725.         bug("Receiving serial data:\n");
  726.         uint8 *adr = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer));
  727.         for (int i=0; i<actual; i++) {
  728.             bug("%02x ", adr[i]);
  729.         }
  730.         bug("\n");
  731. #endif
  732.  
  733.         // KillIO called? Then simply return
  734.         if (s->io_killed) {
  735.  
  736.             WriteMacInt16(p.pb + ioResult, abortErr);
  737.             WriteMacInt32(p.pb + ioActCount, 0);
  738.             s->read_pending = s->read_done = false;
  739.  
  740.         } else {
  741.  
  742.             // Set error code
  743.             if (actual >= 0) {
  744.                 WriteMacInt32(p.pb + ioActCount, actual);
  745.                 WriteMacInt32(s->input_dt + serdtResult, noErr);
  746.             } else {
  747.                 WriteMacInt32(p.pb + ioActCount, 0);
  748.                 WriteMacInt32(s->input_dt + serdtResult, readErr);
  749.             }
  750.     
  751.             // Trigger serial interrupt
  752.             D(bug(" triggering serial interrupt\n"));
  753.             s->read_done = true;
  754.             SetInterruptFlag(INTFLAG_SERIAL);
  755.             TriggerInterrupt();
  756.         }
  757.     }
  758.     return 0;
  759. }
  760.  
  761.  
  762. /*
  763.  *  Data output thread
  764.  */
  765.  
  766. status_t BeSERDPort::output_func(void *arg)
  767. {
  768.     BeSERDPort *s = (BeSERDPort *)arg;
  769.     for (;;) {
  770.  
  771.         // Wait for commands
  772.         thread_id sender;
  773.         ThreadPacket p;
  774.         uint32 code = receive_data(&sender, &p, sizeof(ThreadPacket));
  775.         if (code == CMD_QUIT)
  776.             break;
  777.         if (code != CMD_WRITE)
  778.             continue;
  779.  
  780.         // Execute command
  781.         void *buf = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer));
  782.         uint32 length = ReadMacInt32(p.pb + ioReqCount);
  783.         D(bug("output_func transmitting %ld bytes of data...\n", length));
  784.         int32 actual;
  785.  
  786. #if MONITOR
  787.         bug("Sending serial data:\n");
  788.         uint8 *adr = (uint8 *)buf;
  789.         for (int i=0; i<length; i++) {
  790.             bug("%02x ", adr[i]);
  791.         }
  792.         bug("\n");
  793. #endif
  794.  
  795.         // Buffer in kernel space?
  796.         if ((uint32)buf < 0x80000000) {
  797.     
  798.             // Yes, transfer via buffer
  799.             actual = 0;
  800.             while (length) {
  801.                 uint32 transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length;
  802.                 memcpy(s->tmp_out_buf, buf, transfer_size);
  803.                 int32 transferred;
  804.                 acquire_sem(s->device_sem);
  805.                 if (s->is_parallel) {
  806.                     if ((transferred = write(s->fd, s->tmp_out_buf, transfer_size)) < transfer_size || s->io_killed) {
  807.                         if (transferred < 0)    // Error
  808.                             actual = transferred;
  809.                         else
  810.                             actual += transferred;
  811.                         release_sem(s->device_sem);
  812.                         break;
  813.                     }
  814.                 } else {
  815.                     if ((transferred = s->device->Write(s->tmp_out_buf, transfer_size)) < transfer_size || s->io_killed) {
  816.                         if (transferred < 0)    // Error
  817.                             actual = transferred;
  818.                         else
  819.                             actual += transferred;
  820.                         release_sem(s->device_sem);
  821.                         break;
  822.                     }
  823.                 }
  824.                 release_sem(s->device_sem);
  825.                 if (transferred > transfer_size)    // R3 parallel port driver bug
  826.                     transferred = transfer_size;
  827.                 buf = (void *)((uint8 *)buf + transferred);
  828.                 length -= transferred;
  829.                 actual += transferred;
  830.             }
  831.  
  832.         } else {
  833.     
  834.             // No, transfer directly
  835.             acquire_sem(s->device_sem);
  836.             if (s->is_parallel)
  837.                 actual = write(s->fd, buf, length);
  838.             else
  839.                 actual = s->device->Write(buf, length);
  840.             release_sem(s->device_sem);
  841.             if (actual > length)    // R3 parallel port driver bug
  842.                 actual = length;
  843.         }
  844.  
  845.         D(bug(" %ld bytes transmitted\n", actual));
  846.  
  847.         // KillIO called? Then simply return
  848.         if (s->io_killed) {
  849.  
  850.             WriteMacInt16(p.pb + ioResult, abortErr);
  851.             WriteMacInt32(p.pb + ioActCount, 0);
  852.             s->write_pending = s->write_done = false;
  853.  
  854.         } else {
  855.  
  856.             // Set error code
  857.             if (actual >= 0) {
  858.                 WriteMacInt32(p.pb + ioActCount, actual);
  859.                 WriteMacInt32(s->output_dt + serdtResult, noErr);
  860.             } else {
  861.                 WriteMacInt32(p.pb + ioActCount, 0);
  862.                 WriteMacInt32(s->output_dt + serdtResult, writErr);
  863.             }
  864.     
  865.             // Trigger serial interrupt
  866.             D(bug(" triggering serial interrupt\n"));
  867.             s->write_done = true;
  868.             SetInterruptFlag(INTFLAG_SERIAL);
  869.             TriggerInterrupt();
  870.         }
  871.     }
  872.     return 0;
  873. }
  874.