ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/serial_amiga.cpp
Revision: 1.3
Committed: 2000-04-10T18:52:41Z (24 years, 7 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-13072000
Changes since 1.2: +1 -1 lines
Log Message:
- updated copyright info: 1999->2000

File Contents

# Content
1 /*
2 * serial_amiga.cpp - Serial device driver, AmigaOS specific stuff
3 *
4 * Basilisk II (C) 1997-2000 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 }