]>
git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/serial_console.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
29 * @APPLE_FREE_COPYRIGHT@
33 #include <platforms.h>
34 #include <serial_console_default.h>
37 #include <machine/machparam.h> /* spl definitions */
39 #include <ppc/POWERMAC/video_console_entries.h>
40 #include <ppc/misc_protos.h>
41 #include <ppc/POWERMAC/serial_io.h>
42 #include <kern/cpu_number.h>
43 #include <ppc/Firmware.h>
44 #include <ppc/proc_reg.h>
45 #include <pexpert/pexpert.h>
48 * A machine MUST have a console. In our case
49 * things are a little complicated by the graphic
50 * display: people expect it to be their "console",
51 * but we'd like to be able to live without it.
52 * This is not to be confused with the "rconsole" thing:
53 * that just duplicates the console I/O to
54 * another place (for debugging/logging purposes).
57 const int console_unit
= 0;
58 const int console_chan_default
= CONSOLE_PORT
;
59 #define console_chan (console_chan_default) /* ^ cpu_number()) */
61 #define OPS(putc, getc, nosplputc, nosplgetc) putc, getc
63 const struct console_ops
{
64 int (*putc
)(int, int, int);
65 int (*getc
)(int, int, boolean_t
, boolean_t
);
67 #define SCC_CONS_OPS 0
68 {OPS(scc_putc
, scc_getc
, no_spl_scputc
, no_spl_scgetc
)},
70 {OPS(vcputc
, vcgetc
, no_spl_vcputc
, no_spl_vcgetc
)},
72 #define NCONSOPS (sizeof cons_ops / sizeof cons_ops[0])
74 #if SERIAL_CONSOLE_DEFAULT
75 #define CONS_OPS SCC_CONS_OPS
76 #define CONS_NAME "com"
78 #define CONS_OPS VC_CONS_OPS
79 #define CONS_NAME "vc"
82 #define MP_SAFE_CONSOLE 1 /* Set this to 1 to allow more than 1 processor to print at once */
85 struct ppcbfr
{ /* Controls multiple processor output */
86 unsigned int pos
; /* Current position in buffer */
87 unsigned int noprompt
; /* Set if we skip the prompt */
88 unsigned int echo
; /* Control character echoing */
89 char buffer
[256]; /* Fairly big buffer */
91 typedef struct ppcbfr ppcbfr
;
92 ppcbfr cbfr
[NCPUS
]; /* Get one of these for each processor */
93 volatile unsigned int cbfpend
; /* A buffer is pending output */
94 volatile unsigned int sconowner
=-1; /* Mark who's actually writing */
99 unsigned int cons_ops_index
= CONS_OPS
;
100 unsigned int killprint
= 0;
101 unsigned int debcnputc
= 0;
102 extern unsigned int mappingdeb0
;
103 extern int debugger_holdoff
[NCPUS
];
104 extern int debugger_cpu
;
106 static void _cnputc(char c
)
108 cons_ops
[cons_ops_index
].putc(console_unit
, console_chan
, c
);
111 void cnputcusr(char c
) { /* Echo input character directly */
117 hw_atomic_add(&debugger_holdoff
[cpu
], 1); /* Don't allow debugger entry just now (this is a HACK) */
119 _cnputc( c
); /* Echo the character */
120 if(c
=='\n') _cnputc( '\r'); /* Add a return if we had a new line */
122 hw_atomic_sub(&debugger_holdoff
[cpu
], 1); /* Don't allow debugger entry just now (this is a HACK) */
130 unsigned int oldpend
, i
, cpu
, ourbit
, sccpu
;
136 * Handle multiple CPU console output.
137 * Note: this thing has gotten god-awful complicated. We need a better way.
142 return; /* If printing is disabled, bail... */
147 hw_atomic_add(&debugger_holdoff
[cpu
], 1); /* Don't allow debugger entry just now (this is a HACK) */
149 ourbit
= 1 << cpu
; /* Make a mask for just us */
150 if(debugger_cpu
!= -1) { /* Are we in the debugger with empty buffers? */
152 while(sconowner
!= cpu
) { /* Anyone but us? */
153 hw_compare_and_store(-1, cpu
, (unsigned int *)&sconowner
); /* Try to mark it for us if idle */
156 _cnputc( c
); /* Yeah, just write it */
157 if(c
=='\n') /* Did we just write a new line? */
158 _cnputc( '\r'); /* Yeah, just add a return */
160 sconowner
=-1; /* Mark it idle */
161 hw_atomic_sub(&debugger_holdoff
[cpu
], 1); /* Don't allow debugger entry just now (this is a HACK) */
163 return; /* Leave... */
166 s
=splhigh(); /* Don't bother me */
168 while(ourbit
&cbfpend
); /* We aren't "double buffered," so we'll just wait until the buffers are written */
169 isync(); /* Just in case we had to wait */
171 if(c
) { /* If the character is not null */
172 cbfr
[cpu
].buffer
[cbfr
[cpu
].pos
]=c
; /* Fill in the buffer for our CPU */
173 cbfr
[cpu
].pos
++; /* Up the count */
174 if(cbfr
[cpu
].pos
> 253) { /* Is the buffer full? */
175 cbfr
[cpu
].buffer
[254]='\n'; /* Yeah, set the second to last as a LF */
176 cbfr
[cpu
].buffer
[255]='\r'; /* And the last to a CR */
177 cbfr
[cpu
].pos
=256; /* Push the buffer to the end */
178 c
='\r'; /* Set character to a CR */
182 if(c
== '\n') { /* Are we finishing a line? */
183 cbfr
[cpu
].buffer
[cbfr
[cpu
].pos
]='\r'; /* And the last to a CR */
184 cbfr
[cpu
].pos
++; /* Up the count */
185 c
='\r'; /* Set character to a CR */
189 if(cbfr
[cpu
].echo
== 1) { /* Did we hit an escape last time? */
190 if(c
== 'K') { /* Is it a partial clear? */
191 cbfr
[cpu
].echo
= 2; /* Yes, enter echo mode */
193 else cbfr
[cpu
].echo
= 0; /* Otherwise reset escape */
195 else if(cbfr
[cpu
].echo
== 0) { /* Not in escape sequence, see if we should enter */
196 cbfr
[cpu
].echo
= 1; /* Set that we are in escape sequence */
200 if((c
== 0x00) || (c
== '\r') || (cbfr
[cpu
].echo
== 2)) { /* Try to push out all buffers if we see CR or null */
202 while(1) { /* Loop until we see who's doing this */
203 oldpend
=cbfpend
; /* Get the currentest pending buffer flags */
204 if(hw_compare_and_store(oldpend
, oldpend
|ourbit
, (unsigned int *)&cbfpend
)) /* Swap ours on if no change */
205 break; /* Bail the loop if it worked */
208 if(!hw_compare_and_store(-1, cpu
, (unsigned int *)&sconowner
)) { /* See if someone else has this, and take it if not */
209 debugger_holdoff
[cpu
] = 0; /* Allow debugger entry (this is a HACK) */
210 splx(s
); /* Let's take some 'rupts now */
211 return; /* We leave here, 'cause another processor is already writing the buffers */
214 while(1) { /* Loop to dump out all of the finished buffers */
215 oldpend
=cbfpend
; /* Get the most current finished buffers */
216 for(sccpu
=0; sccpu
<NCPUS
; sccpu
++) { /* Cycle through all CPUs buffers */
218 if(oldpend
&(1<<sccpu
)) { /* Does this guy have a buffer to do? */
221 if(!cbfr
[sccpu
].noprompt
) { /* Don't prompt if there was not CR before */
222 _cnputc( '{'); /* Mark CPU number */
223 _cnputc( '0'+sccpu
); /* Mark CPU number */
224 _cnputc( '.'); /* (TEST/DEBUG) */
225 _cnputc( '0'+cpu
); /* (TEST/DEBUG) */
226 _cnputc( '}'); /* Mark CPU number */
227 _cnputc( ' '); /* Mark CPU number */
231 for(i
=0; i
<cbfr
[sccpu
].pos
; i
++) { /* Do the whole buffer */
232 _cnputc( cbfr
[sccpu
].buffer
[i
]); /* Write it */
235 if(cbfr
[sccpu
].buffer
[cbfr
[sccpu
].pos
-1]!='\r') { /* Was the last character a return? */
236 cbfr
[sccpu
].noprompt
= 1; /* Remember not to prompt */
238 else { /* Last was a return */
239 cbfr
[sccpu
].noprompt
= 0; /* Otherwise remember to prompt */
240 cbfr
[sccpu
].echo
= 0; /* And clear echo */
243 cbfr
[sccpu
].pos
=0; /* Reset the buffer pointer */
245 while(!hw_compare_and_store(cbfpend
, cbfpend
&~(1<<sccpu
), (unsigned int *)&cbfpend
)); /* Swap it off */
248 sconowner
=-1; /* Set the writer to idle */
249 sync(); /* Insure that everything's done */
250 if(hw_compare_and_store(0, 0, (unsigned int *)&cbfpend
)) break; /* If there are no new buffers, we are done... */
251 if(!hw_compare_and_store(-1, cpu
, (unsigned int *)&sconowner
)) break; /* If this isn't idle anymore, we're done */
255 hw_atomic_sub(&debugger_holdoff
[cpu
], 1); /* Don't allow debugger entry just now (this is a HACK) */
256 splx(s
); /* Let's take some 'rupts now */
258 #else /* MP_SAFE_CONSOLE */
262 #endif /* MP_SAFE_CONSOLE */
269 return cons_ops
[cons_ops_index
].getc(console_unit
, console_chan
,
276 return cons_ops
[cons_ops_index
].getc(console_unit
, console_chan
,
280 boolean_t
console_is_serial()
282 return cons_ops_index
== SCC_CONS_OPS
;
286 switch_to_video_console()
288 int old_cons_ops
= cons_ops_index
;
289 cons_ops_index
= VC_CONS_OPS
;
294 switch_to_serial_console()
296 int old_cons_ops
= cons_ops_index
;
297 cons_ops_index
= SCC_CONS_OPS
;
301 /* The switch_to_{video,serial,kgdb}_console functions return a cookie that
302 can be used to restore the console to whatever it was before, in the
303 same way that splwhatever() and splx() work. */
305 switch_to_old_console(int old_console
)
307 static boolean_t squawked
;
308 unsigned int ops
= old_console
;
310 if (ops
>= NCONSOPS
&& !squawked
) {
312 printf("switch_to_old_console: unknown ops %d\n", ops
);
314 cons_ops_index
= ops
;
319 vcgetc(int l
, int u
, boolean_t wait
, boolean_t raw
)
323 if( 0 == (*PE_poll_input
)( 0, &c
))