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

  1. /*
  2.  *  serial_amiga.cpp - Serial device driver, AmigaOS 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 <exec/types.h>
  22. #include <exec/memory.h>
  23. #include <exec/errors.h>
  24. #include <dos/dos.h>
  25. #include <dos/dosextens.h>
  26. #include <dos/dostags.h>
  27. #include <devices/serial.h>
  28. #include <devices/parallel.h>
  29. #include <proto/exec.h>
  30. #include <proto/dos.h>
  31.  
  32. #include "sysdeps.h"
  33. #include "cpu_emulation.h"
  34. #include "main.h"
  35. #include "macos_util.h"
  36. #include "prefs.h"
  37. #include "serial.h"
  38. #include "serial_defs.h"
  39.  
  40. #define DEBUG 0
  41. #include "debug.h"
  42.  
  43. #define MONITOR 0
  44.  
  45.  
  46. // These messages are sent to the serial process
  47. const uint32 MSG_QUERY = 'qery';            // Query port status, return status in control_io
  48. const uint32 MSG_SET_PARAMS = 'setp';        // Set serial parameters (parameters in control_io)
  49. const uint32 MSG_SET_PAR_PARAMS = 'pstp';    // Set parallel parameters (parameters in control_io)
  50. const uint32 MSG_KILL_IO = 'kill';            // Kill pending I/O requests
  51. const uint32 MSG_BREAK = 'brek';            // Send break
  52. const uint32 MSG_RESET = 'rset';            // Reset channel
  53. const uint32 MSG_PRIME_IN = 'prin';            // Data input
  54. const uint32 MSG_PRIME_OUT = 'pout';        // Data output
  55.  
  56. struct SerMessage : public Message {
  57.     SerMessage(uint32 what_, const struct MsgPort *reply_port = NULL)
  58.     {
  59.         what = what_;
  60.         mn_ReplyPort = (struct MsgPort *)reply_port;
  61.         mn_Length = sizeof(*this);
  62.     }
  63.     uint32 what;
  64.     uint32 pb;
  65. };
  66.  
  67.  
  68. // Driver private variables
  69. class ASERDPort : public SERDPort {
  70. public:
  71.     ASERDPort(const char *dev)
  72.     {
  73.         device_name = dev;
  74.         if (dev && dev[0] == '*') {
  75.             is_parallel = true;
  76.             device_name++;
  77.         } else
  78.             is_parallel = false;
  79.         control_io = NULL;
  80.         serial_proc = NULL;
  81.         reply_port = NULL;
  82.     }
  83.  
  84.     virtual ~ASERDPort()
  85.     {
  86.     }
  87.  
  88.     virtual int16 open(uint16 config);
  89.     virtual int16 prime_in(uint32 pb, uint32 dce);
  90.     virtual int16 prime_out(uint32 pb, uint32 dce);
  91.     virtual int16 control(uint32 pb, uint32 dce, uint16 code);
  92.     virtual int16 status(uint32 pb, uint32 dce, uint16 code);
  93.     virtual int16 close(void);
  94.  
  95. private:
  96.     bool configure(uint16 config);
  97.     void set_handshake(uint32 s, bool with_dtr);
  98.     void send_to_proc(uint32 what, uint32 pb = 0);
  99.     bool query(void);
  100.     bool set_params(void);
  101.     bool set_par_params(void);
  102.     void conv_error(struct IOExtSer *io, uint32 dt);
  103.     static void serial_func(void);
  104.  
  105.     const char *device_name;            // Device name
  106.     bool is_parallel;                    // Flag: Port is parallel
  107.     IOExtSer *control_io;                // IORequest for setting serial port characteristics etc.
  108.  
  109.     struct Process *serial_proc;        // Serial device handler process
  110.     bool proc_error;                    // Flag: process didn't initialize
  111.     struct MsgPort *proc_port;            // Message port of process, for communication with main task
  112.     struct MsgPort *reply_port;            // Reply port for communication with process
  113.  
  114.     uint8 err_mask;                        // shkErrs
  115. };
  116.  
  117.  
  118. // Global variables
  119. static void *proc_arg;                        // Argument to process
  120. extern struct Task *MainTask;                // Pointer to main task (from main_amiga.cpp)
  121.  
  122.  
  123. /*
  124.  *  Initialization
  125.  */
  126.  
  127. void SerialInit(void)
  128. {
  129.     // Read serial preferences and create structs for both ports
  130.     the_serd_port[0] = new ASERDPort(PrefsFindString("seriala"));
  131.     the_serd_port[1] = new ASERDPort(PrefsFindString("serialb"));
  132. }
  133.  
  134.  
  135. /*
  136.  *  Deinitialization
  137.  */
  138.  
  139. void SerialExit(void)
  140. {
  141.     delete (ASERDPort *)the_serd_port[0];
  142.     delete (ASERDPort *)the_serd_port[1];
  143. }
  144.  
  145.  
  146. /*
  147.  *  Open serial port
  148.  */
  149.  
  150. int16 ASERDPort::open(uint16 config)
  151. {
  152.     // Don't open NULL name devices
  153.     if (device_name == NULL)
  154.         return openErr;
  155.  
  156.     // Init variables
  157.     err_mask = 0;
  158.  
  159.     // Create message port
  160.     reply_port = CreateMsgPort();
  161.     if (reply_port == NULL)
  162.         goto open_error;
  163.  
  164.     // Start process
  165.     proc_error = false;
  166.     proc_arg = this;
  167.     SetSignal(0, SIGF_SINGLE);
  168.     serial_proc = CreateNewProcTags(
  169.         NP_Entry, (ULONG)serial_func,
  170.         NP_Name, (ULONG)"Basilisk II Serial Task",
  171.         NP_Priority, 1,
  172.         TAG_END    
  173.     );
  174.     if (serial_proc == NULL)
  175.         goto open_error;
  176.  
  177.     // Wait for signal from process
  178.     Wait(SIGF_SINGLE);
  179.  
  180.     // Initialization error? Then bail out
  181.     if (proc_error)
  182.         goto open_error;
  183.  
  184.     // Configure port
  185.     configure(config);
  186.     return noErr;
  187.  
  188. open_error:
  189.     serial_proc = NULL;
  190.     if (reply_port) {
  191.         DeleteMsgPort(reply_port);
  192.         reply_port = NULL;
  193.     }
  194.     return openErr;
  195. }
  196.  
  197.  
  198. /*
  199.  *  Read data from port
  200.  */
  201.  
  202. int16 ASERDPort::prime_in(uint32 pb, uint32 dce)
  203. {
  204.     // Send input command to serial process
  205.     D(bug("primein\n"));
  206.     read_done = false;
  207.     read_pending = true;
  208.     WriteMacInt32(input_dt + serdtDCE, dce);
  209.     send_to_proc(MSG_PRIME_IN, pb);
  210.     return 1;    // Command in progress
  211. }
  212.  
  213.  
  214. /*
  215.  *  Write data to port
  216.  */
  217.  
  218. int16 ASERDPort::prime_out(uint32 pb, uint32 dce)
  219. {
  220.     // Send output command to serial process
  221.     D(bug("primeout\n"));
  222.     write_done = false;
  223.     write_pending = true;
  224.     WriteMacInt32(output_dt + serdtDCE, dce);
  225.     send_to_proc(MSG_PRIME_OUT, pb);
  226.     return 1;    // Command in progress
  227. }
  228.  
  229.  
  230. /*
  231.  *    Control calls
  232.  */
  233.  
  234. int16 ASERDPort::control(uint32 pb, uint32 dce, uint16 code)
  235. {
  236.     D(bug("control(%ld)\n", (uint32)code));
  237.     switch (code) {
  238.         case 1:            // KillIO
  239.             send_to_proc(MSG_KILL_IO);
  240.             return noErr;
  241.  
  242.         case kSERDConfiguration:
  243.             if (configure(ReadMacInt16(pb + csParam)))
  244.                 return noErr;
  245.             else
  246.                 return paramErr;
  247.  
  248.         case kSERDInputBuffer: {
  249.             if (is_parallel)
  250.                 return noErr;
  251.             int buf = ReadMacInt16(pb + csParam + 4) & 0xffffffc0;
  252.             if (buf < 1024)    // 1k minimum
  253.                 buf = 1024;
  254.             D(bug(" buffer size is now %08lx\n", buf));
  255.             control_io->io_RBufLen = buf;
  256.             return set_params() ? noErr : paramErr;
  257.         }
  258.  
  259.         case kSERDSerHShake:
  260.             set_handshake(pb + csParam, false);
  261.             return noErr;
  262.  
  263.         case kSERDSetBreak:
  264.             if (!is_parallel)
  265.                 send_to_proc(MSG_BREAK);
  266.             return noErr;
  267.  
  268.         case kSERDClearBreak:
  269.             return noErr;
  270.  
  271.         case kSERDBaudRate:
  272.             if (is_parallel)
  273.                 return noErr;
  274.             control_io->io_Baud = ReadMacInt16(pb + csParam);
  275.             D(bug(" baud rate %ld\n", control_io->io_Baud));
  276.             return set_params() ? noErr : paramErr;
  277.  
  278.         case kSERDHandshake:
  279.         case kSERDHandshakeRS232:
  280.             set_handshake(pb + csParam, true);
  281.             return noErr;
  282.  
  283.         case kSERDClockMIDI:
  284.             if (is_parallel)
  285.                 return noErr;
  286.             control_io->io_Baud = 31250;
  287.             control_io->io_SerFlags = SERF_XDISABLED | SERF_SHARED;
  288.             control_io->io_StopBits = 1;
  289.             control_io->io_ReadLen = control_io->io_WriteLen = 8;
  290.             return set_params() ? noErr : paramErr;
  291.  
  292.         case kSERDMiscOptions:
  293.         case kSERDAssertDTR:
  294.         case kSERDNegateDTR:
  295.         case kSERDSetPEChar:
  296.         case kSERDSetPEAltChar:
  297.         case kSERDAssertRTS:
  298.         case kSERDNegateRTS:
  299.             return noErr;    // Not supported under AmigaOS
  300.  
  301.         case kSERD115KBaud:
  302.             if (is_parallel)
  303.                 return noErr;
  304.             control_io->io_Baud = 115200;
  305.             return set_params() ? noErr : paramErr;
  306.  
  307.         case kSERD230KBaud:
  308.         case kSERDSetHighSpeed:
  309.             if (is_parallel)
  310.                 return noErr;
  311.             control_io->io_Baud = 230400;
  312.             return set_params() ? noErr : paramErr;
  313.  
  314.         case kSERDResetChannel:
  315.             send_to_proc(MSG_RESET);
  316.             return noErr;
  317.  
  318.         default:
  319.             printf("WARNING: SerialControl(): unimplemented control code %d\n", code);
  320.             return controlErr;
  321.     }
  322. }
  323.  
  324.  
  325. /*
  326.  *    Status calls
  327.  */
  328.  
  329. int16 ASERDPort::status(uint32 pb, uint32 dce, uint16 code)
  330. {
  331.     D(bug("status(%ld)\n", (uint32)code));
  332.     switch (code) {
  333.         case kSERDInputCount:
  334.             WriteMacInt32(pb + csParam, 0);
  335.             if (!is_parallel) {
  336.                 if (!query())
  337.                     return noErr;
  338.                 D(bug("status(2) successful, returning %08lx\n", control_io->IOSer.io_Actual));
  339.                 WriteMacInt32(pb + csParam, control_io->IOSer.io_Actual);
  340.             }
  341.             return noErr;
  342.  
  343.         case kSERDStatus: {
  344.             uint32 p = pb + csParam;
  345.             WriteMacInt8(p + staCumErrs, cum_errors);
  346.             cum_errors = 0;
  347.             WriteMacInt8(p + staRdPend, read_pending);
  348.             WriteMacInt8(p + staWrPend, write_pending);
  349.             if (is_parallel) {
  350.                 WriteMacInt8(p + staXOffSent, 0);
  351.                 WriteMacInt8(p + staXOffHold, 0);
  352.                 WriteMacInt8(p + staCtsHold, 0);
  353.                 WriteMacInt8(p + staDsrHold, 0);
  354.                 WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent);
  355.             } else {
  356.                 query();
  357.                 WriteMacInt8(p + staXOffSent,
  358.                     (control_io->io_Status & IO_STATF_XOFFREAD ? xOffWasSent : 0)
  359.                     | (control_io->io_Status & (1 << 6) ? dtrNegated : 0));        // RTS
  360.                 WriteMacInt8(p + staXOffHold, control_io->io_Status & IO_STATF_XOFFWRITE);
  361.                 WriteMacInt8(p + staCtsHold, control_io->io_Status & (1 << 4));    // CTS
  362.                 WriteMacInt8(p + staDsrHold, control_io->io_Status & (1 << 3));    // DSR
  363.                 WriteMacInt8(p + staModemStatus,
  364.                     (control_io->io_Status & (1 << 3) ? 0 : dsrEvent)
  365.                     | (control_io->io_Status & (1 << 2) ? riEvent : 0)
  366.                     | (control_io->io_Status & (1 << 5) ? 0 : dcdEvent)
  367.                     | (control_io->io_Status & (1 << 4) ? 0 : ctsEvent)
  368.                     | (control_io->io_Status & IO_STATF_READBREAK ? breakEvent : 0));
  369.             }
  370.             return noErr;
  371.         }
  372.  
  373.         default:
  374.             printf("WARNING: SerialStatus(): unimplemented status code %d\n", code);
  375.             return statusErr;
  376.     }
  377. }
  378.  
  379.  
  380. /*
  381.  *    Close serial port
  382.  */
  383.  
  384. int16 ASERDPort::close()
  385. {
  386.     // Stop process
  387.     if (serial_proc) {
  388.         SetSignal(0, SIGF_SINGLE);
  389.         Signal(&serial_proc->pr_Task, SIGBREAKF_CTRL_C);
  390.         Wait(SIGF_SINGLE);
  391.     }
  392.  
  393.     // Delete reply port
  394.     if (reply_port) {
  395.         DeleteMsgPort(reply_port);
  396.         reply_port = NULL;
  397.     }
  398.     return noErr;
  399. }
  400.  
  401.  
  402. /*
  403.  *  Configure serial port with MacOS config word
  404.  */
  405.  
  406. bool ASERDPort::configure(uint16 config)
  407. {
  408.     D(bug(" configure %04lx\n", (uint32)config));
  409.     if (is_parallel)
  410.         return true;
  411.  
  412.     // Set number of stop bits
  413.     switch (config & 0xc000) {
  414.         case stop10:
  415.             control_io->io_StopBits = 1;
  416.             break;
  417.         case stop20:
  418.             control_io->io_StopBits = 2;
  419.             break;
  420.         default:
  421.             return false;
  422.     }
  423.  
  424.     // Set parity mode
  425.     switch (config & 0x3000) {
  426.         case noParity:
  427.             control_io->io_SerFlags &= ~SERF_PARTY_ON;
  428.             break;
  429.         case oddParity:
  430.             control_io->io_SerFlags |= SERF_PARTY_ON | SERF_PARTY_ODD;
  431.             break;
  432.         case evenParity:
  433.             control_io->io_SerFlags |= SERF_PARTY_ON;
  434.             control_io->io_SerFlags &= ~SERF_PARTY_ODD;
  435.             break;
  436.         default:
  437.             return false;
  438.     }
  439.  
  440.     // Set number of data bits
  441.     switch (config & 0x0c00) {
  442.         case data5:
  443.             control_io->io_ReadLen = control_io->io_WriteLen = 5;
  444.             break;
  445.         case data6:
  446.             control_io->io_ReadLen = control_io->io_WriteLen = 6;
  447.             break;
  448.         case data7:
  449.             control_io->io_ReadLen = control_io->io_WriteLen = 7;
  450.             break;
  451.         case data8:
  452.             control_io->io_ReadLen = control_io->io_WriteLen = 8;
  453.             break;
  454.     }
  455.  
  456.     // Set baud rate
  457.     control_io->io_Baud = 115200 / ((config & 0x03ff) + 2);
  458.     return set_params();
  459. }
  460.  
  461.  
  462. /*
  463.  *  Set serial handshaking
  464.  */
  465.  
  466. void ASERDPort::set_handshake(uint32 s, bool with_dtr)
  467. {
  468.     D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n",
  469.         ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3),
  470.         ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7)));
  471.  
  472.     err_mask = ReadMacInt8(s + shkErrs);
  473.  
  474.     if (is_parallel) {
  475.  
  476.         // Parallel handshake
  477.         if (with_dtr) {
  478.             if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR))
  479.                 ((IOExtPar *)control_io)->io_ParFlags |= PARF_ACKMODE;
  480.             else
  481.                 ((IOExtPar *)control_io)->io_ParFlags &= ~PARF_ACKMODE;
  482.         } else {
  483.             if (ReadMacInt8(s + shkFCTS))
  484.                 ((IOExtPar *)control_io)->io_ParFlags |= PARF_ACKMODE;
  485.             else
  486.                 ((IOExtPar *)control_io)->io_ParFlags &= ~PARF_ACKMODE;
  487.         }
  488.         set_par_params();
  489.  
  490.     } else {
  491.  
  492.         // Serial handshake
  493.         if (ReadMacInt8(s + shkFXOn) || ReadMacInt8(s + shkFInX))
  494.             control_io->io_SerFlags &= ~SERF_XDISABLED;
  495.         else
  496.             control_io->io_SerFlags |= SERF_XDISABLED;
  497.  
  498.         if (with_dtr) {
  499.             if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR))
  500.                 control_io->io_SerFlags |= SERF_7WIRE;
  501.             else
  502.                 control_io->io_SerFlags &= ~SERF_7WIRE;
  503.         } else {
  504.             if (ReadMacInt8(s + shkFCTS))
  505.                 control_io->io_SerFlags |= SERF_7WIRE;
  506.             else
  507.                 control_io->io_SerFlags &= ~SERF_7WIRE;
  508.         }
  509.         control_io->io_CtlChar = ReadMacInt16(s + shkXOn) << 16;
  510.         set_params();
  511.     }
  512. }
  513.  
  514.  
  515. /*
  516.  *  Send message to serial process
  517.  */
  518.  
  519. void ASERDPort::send_to_proc(uint32 what, uint32 pb)
  520. {
  521.     D(bug("sending %08lx to serial_proc\n", what));
  522.     SerMessage msg(what, reply_port);
  523.     msg.pb = pb;
  524.     PutMsg(proc_port, &msg);
  525.     WaitPort(reply_port);
  526.     GetMsg(reply_port);
  527.     D(bug(" sent\n"));
  528. }
  529.  
  530.  
  531. /*
  532.  *  Query serial port status
  533.  */
  534.  
  535. bool ASERDPort::query(void)
  536. {
  537.     send_to_proc(MSG_QUERY);
  538.     return control_io->IOSer.io_Error == 0;
  539. }
  540.  
  541.  
  542. /*
  543.  *  Set serial parameters
  544.  */
  545.  
  546. bool ASERDPort::set_params(void)
  547. {
  548.     // Set/clear RadBoogie
  549.     UBYTE flags = control_io->io_SerFlags;
  550.     if (!(flags & SERF_PARTY_ON) && (flags & SERF_XDISABLED) && control_io->io_ReadLen == 8)
  551.         control_io->io_SerFlags |= SERF_RAD_BOOGIE;
  552.     else
  553.         control_io->io_SerFlags &= ~SERF_RAD_BOOGIE;
  554.  
  555.     // Send message to serial process
  556.     send_to_proc(MSG_SET_PARAMS);
  557.     return control_io->IOSer.io_Error == 0;
  558. }
  559.  
  560.  
  561. /*
  562.  *  Set parallel parameters
  563.  */
  564.  
  565. bool ASERDPort::set_par_params(void)
  566. {
  567.     send_to_proc(MSG_SET_PAR_PARAMS);
  568.     return control_io->IOSer.io_Error == 0;
  569. }
  570.  
  571.  
  572. /*
  573.  *  Convert AmigaOS error code to MacOS error code, set serdtResult and cum_errors
  574.  */
  575.  
  576. void ASERDPort::conv_error(struct IOExtSer *io, uint32 dt)
  577. {
  578.     int16 oserr;
  579.     uint8 cum;
  580.  
  581.     BYTE err = io->IOSer.io_Error;
  582.     if (err == 0 || err == IOERR_NOCMD) {
  583.         oserr = 0;
  584.         cum = 0;
  585.     } else {
  586.         if (is_parallel) {
  587.             oserr = (err_mask & framingErr) ? rcvrErr : 0;
  588.             cum = framingErr;
  589.         } else {
  590.             switch (io->IOSer.io_Error) {
  591.                 case SerErr_DetectedBreak:
  592.                     oserr = breakRecd;
  593.                     cum = breakErr;
  594.                     break;
  595.                 case SerErr_ParityErr:
  596.                     oserr = (err_mask & parityErr) ? rcvrErr : 0;
  597.                     cum = parityErr;
  598.                     break;
  599.                 case SerErr_BufOverflow:
  600.                     oserr = (err_mask & swOverrunErr) ? rcvrErr : 0;
  601.                     cum = swOverrunErr;
  602.                     break;
  603.                 case SerErr_LineErr:
  604.                     oserr = (err_mask & hwOverrunErr) ? rcvrErr : 0;
  605.                     cum = hwOverrunErr;
  606.                     break;
  607.                 default:
  608.                     oserr = (err_mask & framingErr) ? rcvrErr : 0;
  609.                     cum = framingErr;
  610.                     break;
  611.             }
  612.         }
  613.     }
  614.  
  615.     WriteMacInt32(dt + serdtResult, oserr);
  616.     cum_errors |= cum;
  617. }
  618.  
  619.  
  620. /*
  621.  *  Process for communication with the serial.device
  622.  */
  623.  
  624. __saveds void ASERDPort::serial_func(void)
  625. {
  626.     struct ASERDPort *obj = (ASERDPort *)proc_arg;
  627.     struct MsgPort *proc_port = NULL, *io_port = NULL, *control_port = NULL;
  628.     struct IOExtSer *read_io = NULL, *write_io = NULL, *control_io = NULL;
  629.     uint8 orig_params[sizeof(struct IOExtSer)];
  630.     bool opened = false;
  631.     ULONG io_mask = 0, proc_port_mask = 0;
  632.  
  633.     // Default: error occured
  634.     obj->proc_error = true;
  635.  
  636.     // Create message port for communication with main task
  637.     proc_port = CreateMsgPort();
  638.     if (proc_port == NULL)
  639.         goto quit;
  640.     proc_port_mask = 1 << proc_port->mp_SigBit;
  641.  
  642.     // Create message ports for serial.device I/O
  643.     io_port = CreateMsgPort();
  644.     if (io_port == NULL)
  645.         goto quit;
  646.     io_mask = 1 << io_port->mp_SigBit;
  647.     control_port = CreateMsgPort();
  648.     if (control_port == NULL)
  649.         goto quit;
  650.  
  651.     // Create IORequests
  652.     read_io = (struct IOExtSer *)CreateIORequest(io_port, sizeof(struct IOExtSer));
  653.     write_io = (struct IOExtSer *)CreateIORequest(io_port, sizeof(struct IOExtSer));
  654.     control_io = (struct IOExtSer *)CreateIORequest(control_port, sizeof(struct IOExtSer));
  655.     if (read_io == NULL || write_io == NULL || control_io == NULL)
  656.         goto quit;
  657.     read_io->IOSer.io_Message.mn_Node.ln_Type = 0;    // Avoid CheckIO() bug
  658.     write_io->IOSer.io_Message.mn_Node.ln_Type = 0;
  659.     control_io->IOSer.io_Message.mn_Node.ln_Type = 0;
  660.  
  661.     // Parse device name
  662.     char dev_name[256];
  663.     ULONG dev_unit;
  664.     if (sscanf(obj->device_name, "%[^/]/%ld", dev_name, &dev_unit) < 2)
  665.         goto quit;
  666.  
  667.     // Open device
  668.     if (obj->is_parallel)
  669.         ((IOExtPar *)read_io)->io_ParFlags = PARF_SHARED;
  670.     else
  671.         read_io->io_SerFlags = SERF_SHARED | SERF_7WIRE;
  672.     if (OpenDevice((UBYTE *)dev_name, dev_unit, (struct IORequest *)read_io, 0) || read_io->IOSer.io_Device == NULL)
  673.         goto quit;
  674.     opened = true;
  675.  
  676.     // Copy IORequests
  677.     memcpy(write_io, read_io, sizeof(struct IOExtSer));
  678.     memcpy(control_io, read_io, sizeof(struct IOExtSer));
  679.  
  680.     // Attach control_io to control_port and set default values
  681.     control_io->IOSer.io_Message.mn_ReplyPort = control_port;
  682.     if (!obj->is_parallel) {
  683.         control_io->io_CtlChar = SER_DEFAULT_CTLCHAR;
  684.         control_io->io_RBufLen = 64;
  685.         control_io->io_ExtFlags = 0;
  686.         control_io->io_Baud = 9600;
  687.         control_io->io_BrkTime = 250000;
  688.         control_io->io_ReadLen = control_io->io_WriteLen = 8;
  689.         control_io->io_StopBits = 1;
  690.         control_io->io_SerFlags = SERF_SHARED;
  691.         control_io->IOSer.io_Command = SDCMD_SETPARAMS;
  692.         DoIO((struct IORequest *)control_io);
  693.         memcpy(orig_params, &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar));
  694.     }
  695.  
  696.     // Initialization went well, inform main task
  697.     obj->proc_port = proc_port;
  698.     obj->control_io = control_io;
  699.     obj->proc_error = false;
  700.     Signal(MainTask, SIGF_SINGLE);
  701.  
  702.     // Main loop
  703.     for (;;) {
  704.  
  705.         // Wait for I/O and messages (CTRL_C is used for quitting the task)
  706.         ULONG sig = Wait(proc_port_mask | io_mask | SIGBREAKF_CTRL_C);
  707.  
  708.         // Main task wants to quit us
  709.         if (sig & SIGBREAKF_CTRL_C)
  710.             break;
  711.  
  712.         // Main task sent a command to us
  713.         if (sig & proc_port_mask) {
  714.             struct SerMessage *msg;
  715.             while (msg = (SerMessage *)GetMsg(proc_port)) {
  716.                 D(bug("serial_proc received %08lx\n", msg->what));
  717.                 switch (msg->what) {
  718.                     case MSG_QUERY:
  719.                         control_io->IOSer.io_Command = SDCMD_QUERY;
  720.                         DoIO((struct IORequest *)control_io);
  721.                         D(bug(" query returned %08lx, actual %08lx\n", control_io->IOSer.io_Error, control_io->IOSer.io_Actual));
  722.                         break;
  723.  
  724.                     case MSG_SET_PARAMS:
  725.                         // Only send SDCMD_SETPARAMS when configuration has changed
  726.                         if (memcmp(orig_params, &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar))) {
  727.                             memcpy(orig_params, &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar));
  728.                             memcpy(&(read_io->io_CtlChar), &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar));
  729.                             memcpy(&(write_io->io_CtlChar), &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar));
  730.                             control_io->IOSer.io_Command = SDCMD_SETPARAMS;
  731.                             D(bug(" params %08lx %08lx %08lx %08lx %08lx %08lx\n", control_io->io_CtlChar, control_io->io_RBufLen, control_io->io_ExtFlags, control_io->io_Baud, control_io->io_BrkTime, *(uint32 *)((uint8 *)control_io + 76)));
  732.                             DoIO((struct IORequest *)control_io);
  733.                             D(bug(" set_parms returned %08lx\n", control_io->IOSer.io_Error));
  734.                         }
  735.                         break;
  736.  
  737.                     case MSG_SET_PAR_PARAMS:
  738.                         control_io->IOSer.io_Command = PDCMD_SETPARAMS;
  739.                         DoIO((struct IORequest *)control_io);
  740.                         D(bug(" set_par_parms returned %08lx\n", control_io->IOSer.io_Error));
  741.                         break;
  742.  
  743.                     case MSG_BREAK:
  744.                         control_io->IOSer.io_Command = SDCMD_BREAK;
  745.                         DoIO((struct IORequest *)control_io);
  746.                         D(bug(" break returned %08lx\n", control_io->IOSer.io_Error));
  747.                         break;
  748.  
  749.                     case MSG_RESET:
  750.                         control_io->IOSer.io_Command = CMD_RESET;
  751.                         DoIO((struct IORequest *)control_io);
  752.                         D(bug(" reset returned %08lx\n", control_io->IOSer.io_Error));
  753.                         break;
  754.  
  755.                     case MSG_KILL_IO:
  756.                         AbortIO((struct IORequest *)read_io);
  757.                         AbortIO((struct IORequest *)write_io);
  758.                         WaitIO((struct IORequest *)read_io);
  759.                         WaitIO((struct IORequest *)write_io);
  760.                         obj->read_pending = obj->write_pending = false;
  761.                         obj->read_done = obj->write_done = false;
  762.                         break;
  763.  
  764.                     case MSG_PRIME_IN:
  765.                         read_io->IOSer.io_Message.mn_Node.ln_Name = (char *)msg->pb;
  766.                         read_io->IOSer.io_Data = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer));
  767.                         read_io->IOSer.io_Length = ReadMacInt32(msg->pb + ioReqCount);
  768.                         read_io->IOSer.io_Actual = 0;
  769.                         read_io->IOSer.io_Command = CMD_READ;
  770.                         D(bug("serial_proc receiving %ld bytes from %08lx\n", read_io->IOSer.io_Length, read_io->IOSer.io_Data));
  771.                         SendIO((struct IORequest *)read_io);
  772.                         break;
  773.  
  774.                     case MSG_PRIME_OUT: {
  775.                         write_io->IOSer.io_Message.mn_Node.ln_Name = (char *)msg->pb;
  776.                         write_io->IOSer.io_Data = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer));
  777.                         write_io->IOSer.io_Length = ReadMacInt32(msg->pb + ioReqCount);
  778.                         write_io->IOSer.io_Actual = 0;
  779.                         write_io->IOSer.io_Command = CMD_WRITE;
  780.                         D(bug("serial_proc transmitting %ld bytes from %08lx\n", write_io->IOSer.io_Length, write_io->IOSer.io_Data));
  781. #if MONITOR
  782.                         bug("Sending serial data:\n");
  783.                         uint8 *adr = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer));
  784.                         for (int i=0; i<len; i++) {
  785.                             bug("%02lx ", adr[i]);
  786.                         }
  787.                         bug("\n");
  788. #endif
  789.                         SendIO((struct IORequest *)write_io);
  790.                         break;
  791.                     }
  792.                 }
  793.                 D(bug(" serial_proc replying\n"));
  794.                 ReplyMsg(msg);
  795.             }
  796.         }
  797.  
  798.         // I/O operation completed
  799.         if (sig & io_mask) {
  800.             struct IOExtSer *io;
  801.             while (io = (struct IOExtSer *)GetMsg(io_port)) {
  802.                 if (io == read_io) {
  803.                     D(bug("read_io complete, %ld bytes received, error %ld\n", read_io->IOSer.io_Actual, read_io->IOSer.io_Error));
  804.                     uint32 pb = (uint32)read_io->IOSer.io_Message.mn_Node.ln_Name;
  805. #if MONITOR
  806.                     bug("Receiving serial data:\n");
  807.                     uint8 *adr = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer));
  808.                     for (int i=0; i<read_io->IOSer.io_Actual; i++) {
  809.                         bug("%02lx ", adr[i]);
  810.                     }
  811.                     bug("\n");
  812. #endif
  813.                     WriteMacInt32(pb + ioActCount, read_io->IOSer.io_Actual);
  814.                     obj->conv_error(read_io, obj->input_dt);
  815.                     obj->read_done = true;
  816.                     SetInterruptFlag(INTFLAG_SERIAL);
  817.                     TriggerInterrupt();
  818.                 } else if (io == write_io) {
  819.                     D(bug("write_io complete, %ld bytes sent, error %ld\n", write_io->IOSer.io_Actual, write_io->IOSer.io_Error));
  820.                     uint32 pb = (uint32)write_io->IOSer.io_Message.mn_Node.ln_Name;
  821.                     WriteMacInt32(pb + ioActCount, write_io->IOSer.io_Actual);
  822.                     obj->conv_error(write_io, obj->output_dt);
  823.                     obj->write_done = true;
  824.                     SetInterruptFlag(INTFLAG_SERIAL);
  825.                     TriggerInterrupt();
  826.                 }
  827.             }
  828.         }
  829.     }
  830. quit:
  831.  
  832.     // Close everything
  833.     if (opened) {
  834.         if (CheckIO((struct IORequest *)write_io) == 0) {
  835.             AbortIO((struct IORequest *)write_io);
  836.             WaitIO((struct IORequest *)write_io);
  837.         }
  838.         if (CheckIO((struct IORequest *)read_io) == 0) {
  839.             AbortIO((struct IORequest *)read_io);
  840.             WaitIO((struct IORequest *)read_io);
  841.         }
  842.         CloseDevice((struct IORequest *)read_io);
  843.     }
  844.     if (control_io)
  845.         DeleteIORequest(control_io);
  846.     if (write_io)
  847.         DeleteIORequest(write_io);
  848.     if (read_io)
  849.         DeleteIORequest(read_io);
  850.     if (control_port)
  851.         DeleteMsgPort(control_port);
  852.     if (io_port)
  853.         DeleteMsgPort(io_port);
  854.  
  855.     // Send signal to main task to confirm termination
  856.     Forbid();
  857.     Signal(MainTask, SIGF_SINGLE);
  858. }
  859.