* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: console.h
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* ========== Copyright Header End ============================================
void * callTermThread(void * );
typedef void (*inputCallbk
)(void * data
, unsigned char *c
, int portNum
);
// registerd call back function, called whenever there is an i/p avaliable on terminal
// 'data' is the callback data registered by a client.
// 'c' points to a null terminated string of i/p characters
// 'portNum' is the unique handle associated with the terminal (return value of getTerminal()).
virtual int getTerminal(char * title
, int numScrolLines
, inputCallbk cbFun
, void * cbData
, char ** tty_name
, bool pop_win
= true) = 0;
// get a new terminal window if pop_win is true with
// scroll lines = 'numScrolLines'
// if pop_win is false its assume the user will call 'tip' itself.
// Registers a callback function 'cbFun' which is called whenever there is an input
// available on the terminal. 'data' is any user supplied callback data.
// The call returns a unique handle(portNumber) with which, a client can identify a terminal.
// The string representation is returned in tty_name (space for string is allocated).
virtual void writeTerminal(int portNumber
, unsigned char *c
, int length
= 0) = 0;
// write null terminated string 'c' on terminal with handle 'portNumber'.
// if the string is not null terminated then the length arguement can be provided.
// no error checking is done for the validity of portNumber. Client
// must make sure, portNumber is valid and obtained through an earlier
virtual void log(int portNumber
, bool enable
, char * fileName
= 0, bool raw
= false, bool append
= true) = 0;
// log console i/p, o/p for console associated with portNumber in
// fileName. If file exist, open in append mode,
// else create it. The file is expected to be written in current
// if 'enable' is false, disable logging
// 'raw' determines if the log file o/p is generated w/o any '\b'
// processing and is unbuffered. The default is buffered.
// 'append' if true causes file to open in append mode, else the file is
// truncated if it exists
// dump/restore the contents of console in/from a file
virtual void dump(int portNumber
, FILE *fp
) = 0;
virtual void restore(int portNumber
, FILE * fp
) = 0;
virtual void setId(const char * id
) = 0;
// set a string 'id' to display in debug/error messages
// default 'id' is "console"
// set font, background/foreground color of xterm window
virtual void setFont(const char *) = 0;
virtual void setBg(const char *) = 0;
virtual void setFg(const char *) = 0;
// set command to execute in xterm (/bin/tip is for example)
virtual void setExec(const char *) = 0;
// open an xterm window for handle 'portNum' if not already opened
virtual bool pop_term(int portNum
) = 0;
// kill the xterm window for handle 'portNum' if opened
virtual void kill_term(int portNum
) = 0;
// terminal class. typical usage
// The system would declare a global console object.
// Clients can call getTerminal() method of this object to
// obtain 1 or more terminals. Each terminal will have a
// unique handle. On receiving input on any terminal, a user
// defined client function is called with the i/p characters.
// The client can then decide what to do with the data. The
// client uses function writeTerminal() to write characters
// to a terminal with handle portNumber.
void * callTermThread(void *);
class console
:public consoleInterface
{
// 64 kb circular buffer to dump the contents of console
static const int dumpBufSize
= 64 * 1024;
uint8_t dumpBuf
[dumpBufSize
];
*************************************************************\n\
********************START NEW CONSOLE LOG********************\n\
*************************************************************\n");
static const int maxLineSize
= 1024;
uint8_t lineBuffer
[maxLineSize
];
bool pop_term(char * display
, char * fn
, char * bg
, char * fg
, \
char * title
, int numScrolLines
, char * exec
){
if( (xterm_pid
!= -1) && \
(waitpid(xterm_pid
, &wait_stat
, WNOHANG
) == xterm_pid
) ){
// the xterm window no longer exists
fprintf(stderr
," warning: xterm already opened \n");
sprintf(numBuf
,"%d",numScrolLines
);
if ((xterm_pid
= vfork()) == 0) {
const char* xterm
= "/usr/openwin/bin/xterm";
const char* sam
= getexecname();
// Do we expect getexecname() to fail ... geeesh that would be
// a disaster if $0 is blank. In case it is just assume sam.
// Expect that sam was executed from our release. So expect
// $sam_dir/bin/sam and grab $sam_dir. If not then things have
// been moved around ... well though.
char* origin
= dirname(strdup(sam
));
char* sam_dir
= dirname(strdup(origin
));
// Check the exec argument and sub $SAM with the sam_dir variable.
if (strncmp(exec
,"$SAM/",5) == 0)
char* new_exec
= (char*)malloc(strlen(&exec
[4]) + 1 + strlen(sam_dir
));
sprintf(new_exec
,"%s%s",sam_dir
,&exec
[4]);
execl(xterm
, xterm
, "-display", display
,\
"-fn", fn
, "-bg", bg
, "-fg", fg
, "-rw","-vb", \
"-T", title
, "-sb", "-sl", numBuf
, "-e", exec
, tty_name
, (char*)0);
perror("execl /usr/openwin/bin/xterm:");
}else if(xterm_pid
== -1)
if( (xterm_pid
!= -1) && \
(waitpid(xterm_pid
, &wait_stat
, WNOHANG
) == xterm_pid
) ){
// the xterm window no longer exists
kill(xterm_pid
, SIGKILL
);
fprintf(stderr
," warning: xterm window already closed\n");
void log2File(uint8_t *c
, int length
){
if(*c
== 0xd || *c
== '\0')
// unbuffered, at times gross file logging
if(write(logFd
,c
,length
) != length
)
for(int i
= 0; i
< length
; i
++){
lineBuffer
[bufferIndex
++] = c
[i
];
if(write(logFd
,lineBuffer
,bufferIndex
) != bufferIndex
)
lineBuffer
[bufferIndex
++] = c
[i
];
if(bufferIndex
== maxLineSize
){
if(write(logFd
,lineBuffer
,bufferIndex
) != bufferIndex
)
fprintf(stderr
,"write failed for log file %s\n",logFile
);
void log(bool enable
, char * fileName
, bool raw
,bool append
){
logFd
= open(fileName
,O_CREAT
| O_WRONLY
| O_APPEND
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
logFd
= open(fileName
,O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
fprintf(stderr
,"logfile %s open failed\n",fileName
);
logFile
= strdup(fileName
);
write(logFd
,marker
,strlen(marker
));
map
<int , term
*> termMap
;
map
<int , term
*>::iterator termMapIter
;
pthread_mutex_t termMutex
;
void term_read_ports(fd_set readfds
);
bool get_pty(char **name
, int *sfd
, int *mfd
);
char * bg
; // back ground color
char * fg
; // foreground color
char * exec
; // xterm -e <exec> <pty>
console() : title(NULL
) {
char * dis
= getenv("DISPLAY");
display
= strdup("unknown");
pthread_mutex_init(&termMutex
,0);
assert(pthread_create(&selectThread
,0, callTermThread
,(void*)this) == 0);
fn
= strdup("-dec-terminal-medium-r-normal-*-14-140-*-75-c-80-iso8859-1");
exec
= strdup("/bin/tip");
//public functions for console class
void writeTerminal(int portNumber
, unsigned char *c
, int length
){
//no error checking done here.
term
* t
= termMap
[portNumber
];
write(t
->mport_fd
,c
, strlen((char*)c
));
write(t
->mport_fd
,c
, length
);
t
->log2File(c
,length
== 0 ? strlen((char*)c
):length
);
t
->dumpBuf
[t
->dumpIndex
++] = *c
;
t
->dumpIndex
%= term::dumpBufSize
;
int getTerminal(char * title
, int numScrolLines
, inputCallbk cbFun
, void * cbData
, char ** tty_name
, bool pop_win
);
void log(int portNum
, bool enable
, char * fileName
, bool raw
= false, bool append
= true){
assert(portNum
< currentPortNum
);
sprintf(buf
,"console_log_%d",portNum
);
termMap
[portNum
]->log(enable
,fileName
,raw
,append
);
void setId(const char * n
){
void setTitle(const char * s
){
void setFont(const char * s
){
void setBg(const char * s
){
void setFg(const char * s
){
void setExec(const char * s
){
void dump(int portNumber
, FILE * fp
){
struct term
* t
= termMap
[portNumber
];
if(t
->dumpSize
>= t
->dumpBufSize
)
fwrite(&(t
->dumpBuf
[t
->dumpIndex
]), t
->dumpBufSize
- t
->dumpIndex
, 1, fp
);
fwrite(t
->dumpBuf
, t
->dumpIndex
, 1, fp
);
void restore(int portNumber
, FILE * fp
){
if(termMap
[portNumber
]->xterm_pid
== -1){
fprintf(stderr
,"no xterm window popped, console not restored\n");
bool is_logging
= termMap
[portNumber
]->logEnable
;
termMap
[portNumber
]->logEnable
= false;
while( (k
= fgetc(fp
)) != EOF
){
writeTerminal(portNumber
,&c
,1);
termMap
[portNumber
]->logEnable
= is_logging
;
bool pop_term(int portNum
){
if(!termMap
[portNum
]->pop_term(display
, fn
, bg
, fg
, title
,
fprintf(stderr
," error: failed to open xterm\n");
struct term
* t
= termMap
[portNum
];
ts
.tv_sec
= 0; ts
.tv_nsec
=0;
if(t
->dumpSize
>= t
->dumpBufSize
)
for(int i
= 0; i
< (t
->dumpBufSize
- t
->dumpIndex
); i
++ ){
write(t
->mport_fd
,t
->dumpBuf
+ t
->dumpIndex
+ i
, 1);
for(int i
= 0; i
< t
->dumpIndex
; i
++){
write(t
->mport_fd
,t
->dumpBuf
+ i
, 1);
void kill_term(int portNum
){
termMap
[portNum
]->kill_term();