/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1991, 1990 MIPS Computer Systems, Inc.      |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
#ident	"$Header: sysconinit.c,v 1.10.1.1 92/06/24 13:52:53 marker Exp $"

#include <stdio.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/errno.h>
#include <sys/mipskopt.h>
#include <bsd43/machine/hwconf.h>
#include <bsd43/sys/syscall.h>
#include <bsd43/sys/sysmips.h>
#include <sys/cpu_board.h>
#include <sys/grafreg.h>

#define CONSOLE_DEFAULT	'l'
#define	FBDEV		"/dev/fb0"
#define TTYKEYBD	"/dev/ttykeybd"
#define TTY0		"/dev/tty0"
#define TTY1		"/dev/tty1"
#define LOGFILE	"/tmp/sysconinit.log"

#define bsd43_sysmips(x,y,z,q) syscall(BSD43_SYS_sysmips,(x),(y),(z),(q))
#define bsd43_mips_hwconf(x,y) bsd43_sysmips(BSD43_MIPS_HWCONF,(x),(y),0)
#define get_hwconf(x) bsd43_mips_hwconf(BSD43_HWCONF_GET,(x))

struct	bsd43_hw_config conf;	/* configuration - what machine we are etc.. */
int	debug = 0;
char 	*consolename = TTYKEYBD;/* name to link console to */
char	*console_default;
FILE	*logfile;
extern int errno;

main (argc, argv)
int argc;
char **argv;
{
	unsigned char consoletype;		/* t,0,1,l,r, etc. */
	int display_only = 0;
	int c;
	extern int optind;

	while ((c = getopt(argc, argv, "dn")) != EOF)
		switch (c) {
		case 'd':
			debug = 1;
			break;
		case 'n':
			display_only = 1;
			break;
		default:
			fprintf(stderr,
				"usage: sysconinit [-dn] consoletype\n");
			exit(1);
		}

	/*
	 *  Read console variable from kernel and set
	 *  consolename to appropriate name.
	 */
	consoletype = get_consoletype();

	if (debug)
		printf("Got console as '%c'\n", consoletype);
	
	/* if the consoletype is the default and there is an argument
	 *	to sysconinit let it override.
	 */
	if (consoletype == CONSOLE_DEFAULT && optind < argc)
		consoletype = argv[optind][0];

	set_consolename(consoletype);

	/*
	 * Check for keyboard and video.  If not present, ignore kernel
	 * setting for console, force linking to default tty port.
	 */
	if (strcmp(consolename, TTYKEYBD) == 0) {
		int fd;

		if ((fd = open(TTYKEYBD, O_RDWR)) < 0) {
			if (debug) {
				perror("Failed to open keyboard device");
			}
			consolename = console_default;
		}
		else {
			(void) close(fd);
			if (vidprobe())
				consolename = console_default;
		}
	}
	if (display_only) {
		openlog();
		fprintf(logfile, "type = %c; link /dev/console to %s\n",
			consoletype, consolename);
	}
	else {
		relink(consolename, "/dev/console");
		relink(consolename, "/dev/syscon");
		relink(consolename, "/dev/systty");
	}
	exit(0);
}

static
relink(n1, n2)
	char *n1, *n2;
{
	(void) unlink(n2);
	if (link(n1, n2) < 0) {
		fprintf(stderr, "cannot link %s to %s", n1, n2);
		perror("");
		exit(1);
	}
}

get_consoletype()
{
	int	i;
	int	memfd, addr;
	char	con_val;

	if (get_hwconf(&conf) == -1) {
		perror("hwconf");
		exit(1);
	}
	switch (conf.cpubd_type) {
	case BRDTYPE_R3030:
		console_default = TTY1;
		con_val = '1';
		break;

	default:
		console_default = TTY0;
		con_val = '0';
		break;
	}
	errno = 0;
	addr = bsd43_sysmips(BSD43_MIPS_KOPT, "console", 0, KOPT_GET);
	if (errno != 0) {
	    openlog();
	    fprintf(logfile,"sysconinit: kopting console var (errno=%d)",errno);
	    exit(2);
	}
	if ((memfd = open("/dev/kmem", O_RDONLY)) < 0) {
	    	openlog();
		fprintf(logfile,"sysconinit: opening /dev/kmem (errno=%d)",
									errno);
		exit(2);
	}
	if ( lseek(memfd,(long)(addr&0x7fffffff),0)  == -1 ) {
		fprintf(logfile,
			"sysconinit: seeking for 'console' value (errno=%d)",
									errno);
		exit(2);
	}
	if ( read(memfd, &con_val, (int)sizeof(con_val)) !=
				(int)sizeof(con_val) ) {
	    	openlog();
		fprintf(logfile,
			"sysconinit: reading 'console' value (errno=%d)",
									errno);
		exit(2);
	}
	return con_val;
}

set_consolename(consoletype)
unsigned char consoletype;
{
	switch (consoletype) {
	case 'T':
	case 't':
	case '1':
		consolename = TTY1;
		break;
	case 'r':
	case '0':
		consolename = TTY0;
		break;

	default:
	    	openlog();
		fprintf(logfile,
		"sysconinit: warning: '%c' unknown console setting, using 'l'",
		    consoletype);
		/* fall through */
	case 'a':
	case 'l':
	case 'g':
	case 'v':
	case 'm':
	case 'c':
		consolename = TTYKEYBD;
		break;
	}
}

/*
 *  Open log file if not already open.
 */
openlog()
{
	static int logfileopen = 0;

	if ( !logfileopen ) {
		/*
	 	 *  Open log file to log errors and -n information.
	 	 */
		logfile = fopen(LOGFILE,"w");
		logfileopen++;
	}
}

static int
vidprobe()
{
	int fd;

	/* look for new style frame buffer device */
	if ((fd = open(FBDEV, 0, 0)) >= 0) {
		(void) close(fd);
		return 0;
	}

	/* look for old SHM frame buffer devices */
	switch (conf.cpubd_type) {
	case BRDTYPE_R3030:
		if (shmget(GREGKEY, R3030_GRAPHICS_REG_SIZE, 0666) < 0) {
			if (debug)
				perror(
				"failed to open color frame buffer");
			if (shmget(GBMONCH, MONO_FRAME_SIZE, 0666) < 0) {
				if (debug)
					perror(
				"failed to open monochrome frame buffer");
				return 1;
			}
		}
		break;

	default:
		if (shmget(GREGKEY, GRAPHICS_REG_SIZE, 0666) < 0) {
			if (debug)
				perror("failed to open frame Buffer");
			return 1;
		}
		break;
	}

	return 0;
}
