[BACK]Return to console.c CVS log [TXT][DIR] Up to [local] / prex / dev / arm / gba

File: [local] / prex / dev / arm / gba / console.c (download)

Revision 1.1, Tue Aug 19 12:46:47 2008 UTC (15 years, 9 months ago) by nbrk
Branch point for: MAIN

Initial revision

/*-
 * Copyright (c) 2005-2007, Kohsuke Ohtani
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * console.c - GBA console driver
 */

#include <driver.h>
#include <sys/tty.h>
#include "lcd.h"
#include "font.h"

static int console_init(void);
static int console_read(device_t, char *, size_t *, int);
static int console_write(device_t, char *, size_t *, int);
static int console_ioctl(device_t, u_long, void *);
void console_attach(struct tty **);

/*
 * Driver structure
 */
struct driver console_drv = {
	/* name */ "GBA Console",
	/* order */ 4,
	/* init */  console_init,
};

static struct devio console_io = {
	/* open */	NULL,
	/* close */	NULL,
	/* read */	console_read,
	/* write */	console_write,
	/* ioctl */	console_ioctl,
	/* event */	NULL,
};

static device_t console_dev;
static struct tty console_tty;

static uint16_t *vram = CONSOLE_MAP;
static int pos_x;
static int pos_y;
static u_short attrib;

static int esc_index;
static int esc_arg1;
static int esc_arg2;
static int esc_argc;
static int esc_saved_x;
static int esc_saved_y;

static u_short ansi_colors[] = {0, 4, 2, 6, 1, 5, 3, 7};

static void
scroll_up(void)
{
	int i;

	for (i = 0; i < VSCR_COLS * (SCR_ROWS - 1); i++)
		vram[i] = vram[i + VSCR_COLS];
	for (i = 0; i < VSCR_COLS; i++)
		vram[VSCR_COLS * (SCR_ROWS - 1) + i] = ' ';
}

static void
move_cursor(void)
{
}


static void
new_line(void)
{

	pos_x = 0;
	pos_y++;
	if (pos_y >= SCR_ROWS) {
		pos_y = SCR_ROWS - 1;
		scroll_up();
	}
}

static void
clear_screen(void)
{
	int i;

	for (i = 0; i < VSCR_COLS * SCR_ROWS; i++)
		vram[i] = ' ';

	pos_x = 0;
	pos_y = 0;
	move_cursor();
}

/*
 * Check for escape code sequence.
 * Return true if escape
 *
 * <Support list>
 *  ESC[#;#H or	: moves cursor to line #, column #
 *  ESC[#;#f
 *  ESC[#A	: moves cursor up # lines
 *  ESC[#B	: moves cursor down # lines
 *  ESC[#C	: moves cursor right # spaces
 *  ESC[#D	: moves cursor left # spaces
 *  ESC[#;#R	: reports current cursor line & column
 *  ESC[s	: save cursor position for recall later
 *  ESC[u	: return to saved cursor position
 *  ESC[2J	: clear screen and home cursor
 *  ESC[K	: clear to end of line
 *
 * <Not support>
 *  ESC[#m	: attribute (0=attribure off, 4=underline, 5=blink)
 */
static int
check_escape(char c)
{
	int move = 0;
	int val;
	u_short color;

	if (c == 033) {
		esc_index = 1;
		esc_argc = 0;
		return 1;
	}
	if (esc_index == 0)
		return 0;

	if (c >= '0' && c <= '9') {
		val = c - '0';
		switch (esc_argc) {
		case 0:
			esc_arg1 = val;
			esc_index++;
			break;
		case 1:
			esc_arg1 = esc_arg1 * 10 + val;
			break;
		case 2:
			esc_arg2 = val;
			esc_index++;
			break;
		case 3:
			esc_arg2 = esc_arg2 * 10 + val;
			break;
		default:
			goto reset;
		}
		esc_argc++;
		return 1;
	}

	esc_index++;

	switch (esc_index) {
        case 2:
		if (c != '[')
			goto reset;
		return 1;
	case 3:
		switch (c) {
		case 's':	/* Save cursor position */
			esc_saved_x = pos_x;
			esc_saved_y = pos_y;
			break;
		case 'u':	/* Return to saved cursor position */
			pos_x = esc_saved_x;
			pos_y = esc_saved_y;
			move_cursor();
			break;
		case 'K':	/* Clear to end of line */
			break;
		}
		goto reset;
	case 4:
		switch (c) {
		case 'A':	/* Move cursor up # lines */
			pos_y -= esc_arg1;
			if (pos_y < 0)
				pos_y = 0;
			move = 1;
			break;
		case 'B':	/* Move cursor down # lines */
			pos_y += esc_arg1;
			if (pos_y >= SCR_ROWS)
				pos_y = SCR_ROWS - 1;
			move = 1;
			break;
		case 'C':	/* Move cursor forward # spaces */
			pos_x += esc_arg1;
			if (pos_x >= SCR_COLS)
				pos_x = SCR_COLS - 1;
			move = 1;
			break;
		case 'D':	/* Move cursor back # spaces */
			pos_x -= esc_arg1;
			if (pos_x < 0)
				pos_x = 0;
			move = 1;
			break;
		case ';':
			if (esc_argc == 1)
				esc_argc = 2;
			return 1;
		case 'J':
			if (esc_arg1 == 2)	/* Clear screen */
				clear_screen();
			break;
		case 'm':	/* Change attribute */
			switch (esc_arg1) {
			case 0:		/* reset */
				attrib = 0x0F;
				break;
			case 1:		/* bold */
				attrib = 0x0F;
				break;
			case 4:		/* under line */
				break;
			case 5:		/* blink */
				attrib |= 0x80;
				break;
			case 30: case 31: case 32: case 33:
			case 34: case 35: case 36: case 37:
				color = ansi_colors[esc_arg1 - 30];
				attrib = (attrib & 0xf0) | color;
				break;
			case 40: case 41: case 42: case 43:
			case 44: case 45: case 46: case 47:
				color = ansi_colors[esc_arg1 - 40];
				attrib = (attrib & 0x0f) | (color << 4);
				break;
			}
			break;

		}
		if (move)
			move_cursor();
		goto reset;
	case 6:
		switch (c) {
		case 'H':
		case 'f':
			pos_y = esc_arg1;
			pos_x = esc_arg2;
			if (pos_y >= SCR_ROWS)
				pos_y = SCR_ROWS - 1;
			if (pos_x >= SCR_COLS)
				pos_x = SCR_COLS - 1;
			move_cursor();
			break;
		case 'R':
			/* XXX */
			break;
		}
		goto reset;
	default:
		goto reset;
	}
	return 1;
 reset:
	esc_index = 0;
	esc_argc = 0;
	return 1;
}

static void
put_char(char c)
{

	if (check_escape(c))
		return;

	switch (c) {
	case '\n':
		new_line();
		return;
	case '\r':
		pos_x = 0;
		return;
	case '\b':
		if (pos_x == 0)
			return;
		pos_x--;
		return;
	}

	vram[pos_y * VSCR_COLS + pos_x] = c;
	pos_x++;
	if (pos_x >= SCR_COLS) {
		pos_x = 0;
		pos_y++;
		if (pos_y >= SCR_ROWS) {
			pos_y = SCR_ROWS - 1;
			scroll_up();
		}
	}
}

static void
console_output(struct tty *tp)
{
	int c;

	sched_lock();
	while ((c = ttyq_getc(&tp->t_outq)) >= 0)
		put_char(c);
	move_cursor();
	esc_index = 0;
	sched_unlock();
}

#if defined(DEBUG) && defined(CONFIG_DIAG_SCREEN)
/*
 * Debug print handler
 */
static void
diag_print(char *str)
{
	size_t count;
	char c;

	sched_lock();
	for (count = 0; count < 128; count++) {
		c = *str;
		if (c == '\0')
			break;
		put_char(c);
		str++;
	}
	move_cursor();
	esc_index = 0;
	sched_unlock();
}
#endif

/*
 * Read
 */
static int
console_read(device_t dev, char *buf, size_t *nbyte, int blkno)
{

	return tty_read(&console_tty, buf, nbyte);
}

/*
 * Write
 */
static int
console_write(device_t dev, char *buf, size_t *nbyte, int blkno)
{

	return tty_write(&console_tty, buf, nbyte);
}

/*
 * I/O control
 */
static int
console_ioctl(device_t dev, u_long cmd, void *arg)
{

	return tty_ioctl(&console_tty, cmd, arg);
}

/*
 * Attach input device.
 */
void
console_attach(struct tty **tpp)
{

	*tpp = &console_tty;
}

/*
 * Init font
 */
static void
init_font(void)
{
	int i, row, col, bit, val = 0;
	uint16_t *tile = CONSOLE_TILE;

	for (i = 0; i < 128; i++) {
		for (row = 0; row < 8; row++) {
			for (col = 7; col >= 0; col--) {
				bit = (font_bitmap[i][row] & (1 << col)) ? 2 : 1;
				if (col % 2)
					val = bit;
				else
					tile[(i * 32) + (row * 4) + ((7 - col) / 2)] =
						val + (bit << 8);
			}
		}
	}
}

/*
 * Init screen
 */
static void
init_screen(void)
{
	uint16_t *pal = BG_PALETTE;

	/* Initialize palette */
	pal[0] = 0;		/* Transparent */
	pal[1] = RGB(0,0,0);	/* Black */
	pal[2] = RGB(31,31,31);	/* White */

	/* Setup video */
	REG_BG3CNT = 0x1080;	/* Size0, 256color, priority0 */
	REG_DISPCNT = 0x0800;	/* Mode0, BG3 */
}

/*
 * Init
 */
static int
console_init(void)
{

	esc_index = 0;
	pos_x = 0;
	pos_y = 19;
	console_dev = device_create(&console_io, "console", DF_CHR);
	init_font();
	init_screen();
#if defined(DEBUG) && defined(CONFIG_DIAG_SCREEN)
	debug_attach(diag_print);
#endif
	tty_register(&console_io, &console_tty, console_output);
	console_tty.t_winsize.ws_row = SCR_ROWS;
	console_tty.t_winsize.ws_col = SCR_COLS;
	return 0;
}