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

File Contents

# Content
1 /*
2 * serial.cpp - Serial device driver
3 *
4 * SheepShaver (C) 1997-2008 Marc Hellwig and 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 "sysdeps.h"
22 #include "main.h"
23 #include "macos_util.h"
24 #include "serial.h"
25 #include "serial_defs.h"
26
27 #define DEBUG 0
28 #include "debug.h"
29
30
31 // Global variables
32 SERDPort *the_serd_port[2];
33
34 // Function pointers from imported functions
35 typedef int16 (*iocic_ptr)(uint32, int16);
36 static uint32 iocic_tvect = 0;
37 static inline int16 IOCommandIsComplete(uint32 arg1, int16 arg2)
38 {
39 return (int16)CallMacOS2(iocic_ptr, iocic_tvect, arg1, arg2);
40 }
41
42
43 /*
44 * Empty function (AIn/BIn Open/Close)
45 */
46
47 int16 SerialNothing(uint32 pb, uint32 dce)
48 {
49 return noErr;
50 }
51
52
53 /*
54 * Driver Open() routine (output side only)
55 */
56
57 int16 SerialOpen(uint32 pb, uint32 dce)
58 {
59 D(bug("SerialOpen pb %08lx, dce %08lx\n", pb, dce));
60
61 // Get IOCommandIsComplete function
62 iocic_tvect = FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete");
63 D(bug("IOCommandIsComplete TVECT at %08lx\n", iocic_tvect));
64 if (iocic_tvect == 0) {
65 printf("FATAL: SerialOpen(): Can't find IOCommandIsComplete()\n");
66 return openErr;
67 }
68
69 // Do nothing if port is already open
70 SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1];
71 if (the_port->is_open)
72 return noErr;
73
74 // Init variables
75 the_port->read_pending = the_port->write_pending = false;
76 the_port->read_done = the_port->write_done = false;
77 the_port->cum_errors = 0;
78
79 // Open port
80 int16 res = the_port->open(ReadMacInt16(0x1fc + ((-(int16)ReadMacInt16(dce + dCtlRefNum)-6) & 2)));
81 if (res)
82 return res;
83
84 // Allocate Deferred Task structures
85 if ((the_port->dt_store = Mac_sysalloc(SIZEOF_serdt * 2)) == 0)
86 return openErr;
87 uint32 input_dt = the_port->input_dt = the_port->dt_store;
88 uint32 output_dt = the_port->output_dt = the_port->dt_store + SIZEOF_serdt;
89 D(bug(" input_dt %08lx, output_dt %08lx\n", input_dt, output_dt));
90
91 WriteMacInt16(input_dt + qType, dtQType);
92 WriteMacInt32(input_dt + dtAddr, input_dt + serdtCode);
93 WriteMacInt32(input_dt + dtParam, input_dt + serdtResult);
94 // Deferred function for signalling that Prime is complete (pointer to mydtResult in a1)
95 WriteMacInt16(input_dt + serdtCode, 0x2019); // move.l (a1)+,d0 (result)
96 WriteMacInt16(input_dt + serdtCode + 2, 0x2251); // move.l (a1),a1 (dce)
97 WriteMacInt32(input_dt + serdtCode + 4, 0x207808fc); // move.l JIODone,a0
98 WriteMacInt16(input_dt + serdtCode + 8, 0x4ed0); // jmp (a0)
99
100 WriteMacInt16(output_dt + qType, dtQType);
101 WriteMacInt32(output_dt + dtAddr, output_dt + serdtCode);
102 WriteMacInt32(output_dt + dtParam, output_dt + serdtResult);
103 // Deferred function for signalling that Prime is complete (pointer to mydtResult in a1)
104 WriteMacInt16(output_dt + serdtCode, 0x2019); // move.l (a1)+,d0 (result)
105 WriteMacInt16(output_dt + serdtCode + 2, 0x2251); // move.l (a1),a1 (dce)
106 WriteMacInt32(output_dt + serdtCode + 4, 0x207808fc); // move.l JIODone,a0
107 WriteMacInt16(output_dt + serdtCode + 8, 0x4ed0); // jmp (a0)
108
109 the_port->is_open = true;
110 return noErr;
111 }
112
113
114 /*
115 * Driver Prime() routines
116 */
117
118 int16 SerialPrimeIn(uint32 pb, uint32 dce)
119 {
120 D(bug("SerialPrimeIn pb %08lx, dce %08lx\n", pb, dce));
121 int16 res;
122
123 SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1];
124 if (!the_port->is_open)
125 res = notOpenErr;
126 else {
127 if (the_port->read_pending) {
128 printf("FATAL: SerialPrimeIn() called while request is pending\n");
129 res = readErr;
130 } else
131 res = the_port->prime_in(pb, dce);
132 }
133
134 if (ReadMacInt16(pb + ioTrap) & 0x0200)
135 if (res > 0) {
136 WriteMacInt16(pb + ioResult, 0);
137 return 0; // Command in progress
138 } else {
139 WriteMacInt16(pb + ioResult, res);
140 return res;
141 }
142 else
143 if (res > 0)
144 return 0; // Command in progress
145 else {
146 IOCommandIsComplete(pb, res);
147 return res;
148 }
149 }
150
151 int16 SerialPrimeOut(uint32 pb, uint32 dce)
152 {
153 D(bug("SerialPrimeOut pb %08lx, dce %08lx\n", pb, dce));
154 int16 res;
155
156 SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1];
157 if (!the_port->is_open)
158 res = notOpenErr;
159 else {
160 if (the_port->write_pending) {
161 printf("FATAL: SerialPrimeOut() called while request is pending\n");
162 res = writErr;
163 } else
164 res = the_port->prime_out(pb, dce);
165 }
166
167 if (ReadMacInt16(pb + ioTrap) & 0x0200)
168 if (res > 0) {
169 WriteMacInt16(pb + ioResult, 0);
170 return 0; // Command in progress
171 } else {
172 WriteMacInt16(pb + ioResult, res);
173 return res;
174 }
175 else
176 if (res > 0)
177 return 0; // Command in progress
178 else {
179 IOCommandIsComplete(pb, res);
180 return res;
181 }
182 }
183
184
185 /*
186 * Driver Control() routine
187 */
188
189 int16 SerialControl(uint32 pb, uint32 dce)
190 {
191 uint16 code = ReadMacInt16(pb + csCode);
192 D(bug("SerialControl %d, pb %08lx, dce %08lx\n", code, pb, dce));
193 int16 res;
194
195 SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1];
196 if (!the_port->is_open)
197 res = notOpenErr;
198 else {
199 switch (code) {
200 case kSERDSetPollWrite:
201 res = noErr;
202 break;
203 default:
204 res = the_port->control(pb, dce, code);
205 break;
206 }
207 }
208
209 if (code == 1)
210 return res;
211 else if (ReadMacInt16(pb + ioTrap) & 0x0200) {
212 WriteMacInt16(pb + ioResult, res);
213 return res;
214 } else {
215 IOCommandIsComplete(pb, res);
216 return res;
217 }
218 }
219
220
221 /*
222 * Driver Status() routine
223 */
224
225 int16 SerialStatus(uint32 pb, uint32 dce)
226 {
227 uint16 code = ReadMacInt16(pb + csCode);
228 D(bug("SerialStatus %d, pb %08lx, dce %08lx\n", code, pb, dce));
229 int16 res;
230
231 SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1];
232 if (!the_port->is_open)
233 res = notOpenErr;
234 else {
235 switch (code) {
236 case kSERDVersion:
237 WriteMacInt8(pb + csParam, 9); // Second-generation SerialDMA driver
238 res = noErr;
239 break;
240
241 case 0x8000:
242 WriteMacInt8(pb + csParam, 9); // Second-generation SerialDMA driver
243 WriteMacInt16(pb + csParam + 4, 0x1997); // Date of serial driver
244 WriteMacInt16(pb + csParam + 6, 0x0616);
245 res = noErr;
246 break;
247
248 default:
249 res = the_port->status(pb, dce, code);
250 break;
251 }
252 }
253
254 if (ReadMacInt16(pb + ioTrap) & 0x0200) {
255 WriteMacInt16(pb + ioResult, res);
256 return res;
257 } else {
258 IOCommandIsComplete(pb, res);
259 return res;
260 }
261 }
262
263
264 /*
265 * Driver Close() routine
266 */
267
268 int16 SerialClose(uint32 pb, uint32 dce)
269 {
270 D(bug("SerialClose pb %08lx, dce %08lx\n", pb, dce));
271
272 // Close port if open
273 SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1];
274 if (the_port->is_open) {
275 Mac_sysfree(the_port->dt_store);
276 int16 res = the_port->close();
277 the_port->is_open = false;
278 return res;
279 } else
280 return noErr;
281 }
282
283
284 /*
285 * Serial interrupt - Prime command completed, activate deferred tasks to call IODone
286 */
287
288 void SerialInterrupt(void)
289 {
290 D(bug("SerialIRQ\n"));
291
292 // Port 0
293 if (the_serd_port[0]->is_open) {
294 if (the_serd_port[0]->read_pending && the_serd_port[0]->read_done) {
295 Enqueue(the_serd_port[0]->input_dt, 0xd92);
296 the_serd_port[0]->read_pending = the_serd_port[0]->read_done = false;
297 }
298 if (the_serd_port[0]->write_pending && the_serd_port[0]->write_done) {
299 Enqueue(the_serd_port[0]->output_dt, 0xd92);
300 the_serd_port[0]->write_pending = the_serd_port[0]->write_done = false;
301 }
302 }
303
304 // Port 1
305 if (the_serd_port[1]->is_open) {
306 if (the_serd_port[1]->read_pending && the_serd_port[1]->read_done) {
307 Enqueue(the_serd_port[1]->input_dt, 0xd92);
308 the_serd_port[1]->read_pending = the_serd_port[1]->read_done = false;
309 }
310 if (the_serd_port[1]->write_pending && the_serd_port[1]->write_done) {
311 Enqueue(the_serd_port[1]->output_dt, 0xd92);
312 the_serd_port[1]->write_pending = the_serd_port[1]->write_done = false;
313 }
314 }
315 }