Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / term.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: term.cc
// 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 ============================================
/*
* Copyright (C) 2001 Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "@(#)1.16 07/11/19 term.cc"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <stropts.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include "types.h"
#include "blaze_globals.h"
#include "term.h"
// Needed for FlexConfig
#include "mmi.h"
#include "ui.h"
#include "serial_mod.h"
//extern FILE *serial_file;
extern serialInterface * systemConsole;
typedef void (*serial_send)(void *, char *, int );
static int portnum = -1;
struct term {
bool_t initialized;
int port_fd;
int mport_fd;
char *port_name;
serial_send input;
void * cbData;
FILE *serial_output_file;
};
static struct term terms[NUM_PORTS];
/////////////////////////////////////////////////
static bool_t get_pty(char *name, int *sfd, int *mfd)
{
if ((*mfd = open("/dev/ptmx", O_RDWR|O_NDELAY)) == -1) {
ui->error("serial: Cannot find a pseudo tty.\n");
return FALSE;
}
if (grantpt(*mfd) < 0) {
ui->error("serial: Could not grant access to slave pseudo tty\n");
ui->perror("grantpt");
close(*mfd);
return FALSE;
}
if (unlockpt(*mfd) < 0) {
ui->error("serial: Unable to unlock pseudo tty.\n");
ui->perror("unlockpt");
close(*mfd);
return FALSE;
}
strcpy(name, ptsname(*mfd));
*sfd = open(name, O_RDWR);
if (*sfd < 0) {
ui->error("serial: Unable to open slave side for %d\n", *mfd);
close(*mfd);
return FALSE;
}
if (ioctl(*sfd, I_PUSH, "ptem") < 0) {
ui->error("serial: Ioctl I_PUSH ptem failed\n");
ui->perror("ioctl i_push ptem");
close(*mfd);
return FALSE;
}
if (ioctl(*sfd, I_PUSH, "ldterm") < 0) {
ui->error("serial: Ioctl I_PUSH ldterm failed\n");
ui->perror("ioctl i_push ldterm");
close(*mfd);
return FALSE;
}
return TRUE;
}
static int xterm_pid = -1;
int term_console (char *pty_dev, char *display)
{
int pid = 0;
if ((pid = vfork()) == 0) {
execl("/usr/openwin/bin/xterm", "/usr/openwin/bin/xterm", "-display", display,
"-T", "blaze-sim-console", "-n", "blz-sim-con", "-sb", "-sl", "10000",
"-e", "/bin/tip", pty_dev, NULL);
// shouldn't get here
ui->perror("/usr/openwin/bin/xterm for blaze console");
exit(1);
}
return xterm_pid = pid;
}
void term_console_destroy ()
{
if (xterm_pid != -1) {
ui->verbose("\nkilling console window (pid %d)\n", xterm_pid);
kill(xterm_pid, 9);
int deadpid = wait(NULL);
ui->verbose(" done\n");
}
}
int term_init(FILE *fp, serial_send fn, void *cbData,char **tty_name)
{
char pty_name[20];
portnum++;
terms[portnum].initialized = FALSE;
if (fp == NULL) {
if (!get_pty(pty_name, &terms[portnum].port_fd,
&terms[portnum].mport_fd)) {
ui->error("TERM : get_pty failed\n");
return NULL;
}
chmod(pty_name,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |
S_IWOTH);
terms[portnum].port_name = strdup(pty_name);
terms[portnum].input = fn;
terms[portnum].cbData = cbData;
terms[portnum].initialized = TRUE;
terms[portnum].serial_output_file = fp;
*tty_name = strdup(pty_name);
}
else {
terms[portnum].serial_output_file = fp;
terms[portnum].port_name = NULL;
terms[portnum].input = fn;
terms[portnum].cbData = cbData;
terms[portnum].initialized = TRUE;
terms[portnum].mport_fd = -1;
terms[portnum].port_fd = -1;
*tty_name = strdup("Op redirected !!");
}
return portnum;
}
void term_write(unsigned char *c, int port)
{
FILE *fp = terms[port].serial_output_file;
if (fp) {
if(*c == 0xd || *c == '\0')
return;
putc(*c, fp);
term_redirect_add (c[0]);
fflush(fp);
} else {
write(terms[port].mport_fd, c, 1);
term_redirect_add (c[0]) ;
}
}
static void term_read_ports(fd_set readfds)
{
int i;
char chstr[2];
for (i = 0; i < NUM_PORTS; i++) {
if (FD_ISSET(terms[i].mport_fd, &readfds)) {
int nbytes;
uint8_t ch;
while ((nbytes = read(terms[i].mport_fd, &ch, 1)) == 1) {
sprintf(chstr,"%c", ch);
terms[i].input(terms[i].cbData,chstr,i);
}
}
}
}
void term_fake_input (uint8_t *cmd, int l, int port)
{
systemConsole->chars_send((char *)cmd, systemConsole->portH);
}
extern volatile bool config_is_done;
// volatile is needed, otherwise the compiler eliminates the
// while loop as dead-code for opt version
void term_thread(void *)
{
int i, n;
fd_set readfds;
// spin loop until the sysconf modules are loaded and initialized
// not doing this results in a race condition where the select call is
// made before the terms[i] struct is initialzed. The effect is, no
// console input possible.
// the variable config_is_done is set to true after the init_done() has
// been called for all the sysconf modules.
// better approaches are possible but would need to much work and cleanup.
// untill later....
while(!config_is_done);
for (;;) {
FD_ZERO(&readfds);
for (i = 0; i <= portnum; i++) {
if (terms[i].initialized && terms[i].mport_fd != -1) {
FD_SET(terms[i].mport_fd, &readfds);
}
}
n = select(FD_SETSIZE, &readfds, (fd_set *)NULL,
(fd_set *)NULL, NULL);
switch (n) {
case -1: /* error */
break;
case 0: /* timeout */
break;
default: /* input available */
term_read_ports(readfds);
break;
}
}
}