ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/serial.cpp
Revision: 1.8
Committed: 2008-01-01T09:40:31Z (16 years, 4 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * serial.cpp - Serial device driver
3 *
4 * Basilisk II (C) 1997-2008 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 /*
22 * SEE ALSO
23 * Inside Macintosh: Devices, chapter 7 "Serial Driver"
24 * Technote HW 04: "Break/CTS Device Driver Event Structure"
25 * Technote 1018: "Understanding the SerialDMA Driver"
26 */
27
28 #include <stdio.h>
29
30 #include "sysdeps.h"
31 #include "cpu_emulation.h"
32 #include "main.h"
33 #include "macos_util.h"
34 #include "serial.h"
35 #include "serial_defs.h"
36
37 #include "emul_op.h"
38
39 #define DEBUG 0
40 #include "debug.h"
41
42
43 // Global variables
44 SERDPort *the_serd_port[2];
45
46
47 /*
48 * Driver Open() routine
49 */
50
51 int16 SerialOpen(uint32 pb, uint32 dce, int port)
52 {
53 D(bug("SerialOpen port %d, pb %08lx, dce %08lx\n", port, pb, dce));
54
55 if (port == 0 || port == 2) {
56
57 // Do nothing for input side
58 return noErr;
59
60 } else {
61
62 // Do nothing if port is already open
63 SERDPort *the_port = the_serd_port[port >> 1];
64 if (the_port->is_open)
65 return noErr;
66
67 // Init variables
68 the_port->read_pending = the_port->write_pending = false;
69 the_port->read_done = the_port->write_done = false;
70 the_port->cum_errors = 0;
71
72 // Open port
73 int16 res = the_port->open(ReadMacInt16(0x1fc + (port & 2)));
74 if (res)
75 return res;
76
77 // Allocate Deferred Task structures
78 M68kRegisters r;
79 r.d[0] = SIZEOF_serdt * 2;
80 Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
81 if (r.a[0] == 0) {
82 the_port->close();
83 return openErr;
84 }
85 uint32 input_dt = the_port->input_dt = r.a[0];
86 uint32 output_dt = the_port->output_dt = r.a[0] + SIZEOF_serdt;
87 D(bug(" input_dt %08lx, output_dt %08lx\n", input_dt, output_dt));
88
89 WriteMacInt16(input_dt + qType, dtQType);
90 WriteMacInt32(input_dt + dtAddr, input_dt + serdtCode);
91 WriteMacInt32(input_dt + dtParam, input_dt + serdtResult);
92 // Deferred function for signalling that Prime is complete (pointer to mydtResult in a1)
93 WriteMacInt16(input_dt + serdtCode, 0x2019); // move.l (a1)+,d0 (result)
94 WriteMacInt16(input_dt + serdtCode + 2, 0x2251); // move.l (a1),a1 (dce)
95 WriteMacInt32(input_dt + serdtCode + 4, 0x207808fc); // move.l JIODone,a0
96 WriteMacInt16(input_dt + serdtCode + 8, 0x4ed0); // jmp (a0)
97
98 WriteMacInt16(output_dt + qType, dtQType);
99 WriteMacInt32(output_dt + dtAddr, output_dt + serdtCode);
100 WriteMacInt32(output_dt + dtParam, output_dt + serdtResult);
101 // Deferred function for signalling that Prime is complete (pointer to mydtResult in a1)
102 WriteMacInt16(output_dt + serdtCode, 0x2019); // move.l (a1)+,d0 (result)
103 WriteMacInt16(output_dt + serdtCode + 2, 0x2251); // move.l (a1),a1 (dce)
104 WriteMacInt32(output_dt + serdtCode + 4, 0x207808fc); // move.l JIODone,a0
105 WriteMacInt16(output_dt + serdtCode + 8, 0x4ed0); // jmp (a0)
106
107 the_port->is_open = true;
108 return noErr;
109 }
110 }
111
112
113 /*
114 * Driver Prime() routine
115 */
116
117 int16 SerialPrime(uint32 pb, uint32 dce, int port)
118 {
119 D(bug("SerialPrime port %d, pb %08lx, dce %08lx\n", port, pb, dce));
120
121 // Error if port is not open
122 SERDPort *the_port = the_serd_port[port >> 1];
123 if (!the_port->is_open)
124 return notOpenErr;
125
126 if (port == 0 || port == 2) {
127 if (the_port->read_pending) {
128 printf("FATAL: SerialPrimeIn() called while request is pending\n");
129 return readErr;
130 } else
131 return the_port->prime_in(pb, dce);
132 } else {
133 if (the_port->write_pending) {
134 printf("FATAL: SerialPrimeOut() called while request is pending\n");
135 return readErr;
136 } else
137 return the_port->prime_out(pb, dce);
138 }
139 }
140
141
142 /*
143 * Driver Control() routine
144 */
145
146 int16 SerialControl(uint32 pb, uint32 dce, int port)
147 {
148 uint16 code = ReadMacInt16(pb + csCode);
149 D(bug("SerialControl %d, port %d, pb %08lx, dce %08lx\n", code, port, pb, dce));
150
151 // Error if port is not open
152 SERDPort *the_port = the_serd_port[port >> 1];
153 if (!the_port->is_open)
154 return notOpenErr;
155
156 switch (code) {
157 case kSERDSetPollWrite:
158 return noErr;
159
160 default:
161 return the_port->control(pb, dce, code);
162 }
163 }
164
165
166 /*
167 * Driver Status() routine
168 */
169
170 int16 SerialStatus(uint32 pb, uint32 dce, int port)
171 {
172 uint16 code = ReadMacInt16(pb + csCode);
173 D(bug("SerialStatus %d, port %d, pb %08lx, dce %08lx\n", code, port, pb, dce));
174
175 // Error if port is not open
176 SERDPort *the_port = the_serd_port[port >> 1];
177 if (!the_port->is_open)
178 return notOpenErr;
179
180 switch (code) {
181 case kSERDVersion:
182 WriteMacInt8(pb + csParam, 9); // Second-generation SerialDMA driver
183 return noErr;
184
185 case 0x8000:
186 WriteMacInt8(pb + csParam, 9); // Second-generation SerialDMA driver
187 WriteMacInt16(pb + csParam + 4, 0x1997); // Date of serial driver
188 WriteMacInt16(pb + csParam + 6, 0x0616);
189 return noErr;
190
191 default:
192 return the_port->status(pb, dce, code);
193 }
194 }
195
196
197 /*
198 * Driver Close() routine
199 */
200
201 int16 SerialClose(uint32 pb, uint32 dce, int port)
202 {
203 D(bug("SerialClose port %d, pb %08lx, dce %08lx\n", port, pb, dce));
204
205 if (port == 0 || port == 2) {
206
207 // Do nothing for input side
208 return noErr;
209
210 } else {
211
212 // Close port if open
213 SERDPort *the_port = the_serd_port[port >> 1];
214 if (the_port->is_open) {
215 int16 res = the_port->close();
216 M68kRegisters r; // Free Deferred Task structures
217 r.a[0] = the_port->input_dt;
218 Execute68kTrap(0xa01f, &r); // DisposePtr()
219 the_port->is_open = false;
220 return res;
221 } else
222 return noErr;
223 }
224 }
225
226
227 /*
228 * Serial interrupt - Prime command completed, activate deferred tasks to call IODone
229 */
230
231 static void serial_irq(SERDPort *p)
232 {
233 if (p->is_open) {
234 if (p->read_pending && p->read_done) {
235 EnqueueMac(p->input_dt, 0xd92);
236 p->read_pending = p->read_done = false;
237 }
238 if (p->write_pending && p->write_done) {
239 EnqueueMac(p->output_dt, 0xd92);
240 p->write_pending = p->write_done = false;
241 }
242 }
243 }
244
245 void SerialInterrupt(void)
246 {
247 D(bug("SerialIRQ\n"));
248
249 serial_irq(the_serd_port[0]);
250 serial_irq(the_serd_port[1]);
251 }