#include <mach_kdb.h>
#include <platforms.h>
#include <serial_console_default.h>
#include <kern/spl.h>
#include <machine/machparam.h>
#include <types.h>
#include <ppc/POWERMAC/video_console_entries.h>
#include <ppc/misc_protos.h>
#include <ppc/POWERMAC/serial_io.h>
#include <ppc/POWERMAC/mp/mp.h>
#include <kern/cpu_number.h>
#include <ppc/Firmware.h>
#include <ppc/proc_reg.h>
#include <pexpert/pexpert.h>
const int console_unit = 0;
const int console_chan_default = CONSOLE_PORT;
#define console_chan (console_chan_default)
#define OPS(putc, getc, nosplputc, nosplgetc) putc, getc
const struct console_ops {
int (*putc)(int, int, int);
int (*getc)(int, int, boolean_t, boolean_t);
} cons_ops[] = {
#define SCC_CONS_OPS 0
{OPS(scc_putc, scc_getc, no_spl_scputc, no_spl_scgetc)},
#define VC_CONS_OPS 1
{OPS(vcputc, vcgetc, no_spl_vcputc, no_spl_vcgetc)},
};
#define NCONSOPS (sizeof cons_ops / sizeof cons_ops[0])
#if SERIAL_CONSOLE_DEFAULT
#define CONS_OPS SCC_CONS_OPS
#define CONS_NAME "com"
#else
#define CONS_OPS VC_CONS_OPS
#define CONS_NAME "vc"
#endif
#define MP_SAFE_CONSOLE 1
#if MP_SAFE_CONSOLE
struct ppcbfr {
unsigned int pos;
unsigned int noprompt;
unsigned int echo;
char buffer[256];
};
typedef struct ppcbfr ppcbfr;
ppcbfr cbfr[NCPUS];
volatile unsigned int cbfpend;
volatile unsigned int sconowner=-1;
#endif
unsigned int cons_ops_index = CONS_OPS;
unsigned int killprint = 0;
unsigned int debcnputc = 0;
extern unsigned int mappingdeb0;
extern int debugger_holdoff[NCPUS];
static void _cnputc(char c)
{
cons_ops[cons_ops_index].putc(console_unit, console_chan, c);
}
void cnputcusr(char c) {
unsigned int cpu;
cpu = cpu_number();
hw_atomic_add(&debugger_holdoff[cpu], 1);
_cnputc( c);
if(c=='\n') _cnputc( '\r');
hw_atomic_sub(&debugger_holdoff[cpu], 1);
return;
}
void
cnputc(char c)
{
unsigned int oldpend, i, cpu, ourbit, sccpu;
spl_t s;
#if MP_SAFE_CONSOLE
if(killprint) {
return;
}
cpu = cpu_number();
hw_atomic_add(&debugger_holdoff[cpu], 1);
ourbit = 1 << cpu;
if(debugger_cpu != -1) {
while(sconowner != cpu) {
hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner);
}
_cnputc( c);
if(c=='\n')
_cnputc( '\r');
sconowner=-1;
hw_atomic_sub(&debugger_holdoff[cpu], 1);
return;
}
s=splhigh();
while(ourbit&cbfpend);
isync();
if(c) {
cbfr[cpu].buffer[cbfr[cpu].pos]=c;
cbfr[cpu].pos++;
if(cbfr[cpu].pos > 253) {
cbfr[cpu].buffer[254]='\n';
cbfr[cpu].buffer[255]='\r';
cbfr[cpu].pos=256;
c='\r';
}
}
if(c == '\n') {
cbfr[cpu].buffer[cbfr[cpu].pos]='\r';
cbfr[cpu].pos++;
c='\r';
}
#if 1
if(cbfr[cpu].echo == 1) {
if(c == 'K') {
cbfr[cpu].echo = 2;
}
else cbfr[cpu].echo = 0;
}
else if(cbfr[cpu].echo == 0) {
cbfr[cpu].echo = 1;
}
#endif
if((c == 0x00) || (c == '\r') || (cbfr[cpu].echo == 2)) {
while(1) {
oldpend=cbfpend;
if(hw_compare_and_store(oldpend, oldpend|ourbit, (unsigned int *)&cbfpend))
break;
}
if(!hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner)) {
debugger_holdoff[cpu] = 0;
splx(s);
return;
}
while(1) {
oldpend=cbfpend;
for(sccpu=0; sccpu<NCPUS; sccpu++) {
if(oldpend&(1<<sccpu)) {
#if 0
if(!cbfr[sccpu].noprompt) {
_cnputc( '{');
_cnputc( '0'+sccpu);
_cnputc( '.');
_cnputc( '0'+cpu);
_cnputc( '}');
_cnputc( ' ');
}
#endif
for(i=0; i<cbfr[sccpu].pos; i++) {
_cnputc( cbfr[sccpu].buffer[i]);
}
if(cbfr[sccpu].buffer[cbfr[sccpu].pos-1]!='\r') {
cbfr[sccpu].noprompt = 1;
}
else {
cbfr[sccpu].noprompt = 0;
cbfr[sccpu].echo = 0;
}
cbfr[sccpu].pos=0;
while(!hw_compare_and_store(cbfpend, cbfpend&~(1<<sccpu), (unsigned int *)&cbfpend));
}
}
sconowner=-1;
sync();
if(hw_compare_and_store(0, 0, (unsigned int *)&cbfpend)) break;
if(!hw_compare_and_store(-1, cpu, (unsigned int *)&sconowner)) break;
}
}
hw_atomic_sub(&debugger_holdoff[cpu], 1);
splx(s);
#else
_cnputc( c);
if (c == '\n')
_cnputc('\r');
#endif
}
int
cngetc()
{
return cons_ops[cons_ops_index].getc(console_unit, console_chan,
TRUE, FALSE);
}
int
cnmaygetc()
{
return cons_ops[cons_ops_index].getc(console_unit, console_chan,
FALSE, FALSE);
}
boolean_t console_is_serial()
{
return cons_ops_index == SCC_CONS_OPS;
}
int
switch_to_video_console()
{
int old_cons_ops = cons_ops_index;
cons_ops_index = VC_CONS_OPS;
return old_cons_ops;
}
int
switch_to_serial_console()
{
int old_cons_ops = cons_ops_index;
cons_ops_index = SCC_CONS_OPS;
return old_cons_ops;
}
void
switch_to_old_console(int old_console)
{
static boolean_t squawked;
unsigned int ops = old_console;
if (ops >= NCONSOPS && !squawked) {
squawked = TRUE;
printf("switch_to_old_console: unknown ops %d\n", ops);
} else
cons_ops_index = ops;
}
int
vcgetc(int l, int u, boolean_t wait, boolean_t raw)
{
char c;
if( 0 == (*PE_poll_input)( 0, &c))
return( c);
else
return( 0);
}