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, 11 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * serial.cpp - Serial device driver
3     *
4 gbeauche 1.6 * SheepShaver (C) 1997-2008 Marc Hellwig and 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 "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 gbeauche 1.2 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 cebix 1.1
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 gbeauche 1.4 iocic_tvect = FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete");
63 gbeauche 1.2 D(bug("IOCommandIsComplete TVECT at %08lx\n", iocic_tvect));
64     if (iocic_tvect == 0) {
65 cebix 1.1 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 gbeauche 1.4 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 cebix 1.1 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 gbeauche 1.4 Mac_sysfree(the_port->dt_store);
276 cebix 1.1 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     }