ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/serial_amiga.cpp
Revision: 1.6
Committed: 2002-06-23T08:27:05Z (22 years ago) by jlachmann
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-12, nigel-build-13, nigel-build-16, nigel-build-17, nigel-build-15
Changes since 1.5: +5 -2 lines
Log Message:
Adapted to OO video scheme; Audio volume/muting/sample rate now settable

File Contents

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