ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/serial_amiga.cpp
Revision: 1.1
Committed: 1999-10-03T14:16:25Z (25 years, 1 month ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# User Rev Content
1 cebix 1.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 PrimeIn(uint32 pb, uint32 dce);
90     virtual int16 PrimeOut(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, serial_func,
170     NP_Name, "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::PrimeIn(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::PrimeOut(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     }