blob: f67383db4d84243b93d40be4726b67392935c549 [file] [log] [blame]
/*
* Copyright (C) 2003, 2004 Stefan Reinauer
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "config.h"
#include "libopenbios/bindings.h"
#include "kernel/kernel.h"
#include "drivers/drivers.h"
#include "libc/vsprintf.h"
/* ******************************************************************
* serial console functions
* ****************************************************************** */
#define SER_SIZE 8
#define RBR(x) x==2?0x2f8:0x3f8
#define THR(x) x==2?0x2f8:0x3f8
#define IER(x) x==2?0x2f9:0x3f9
#define IIR(x) x==2?0x2fa:0x3fa
#define LCR(x) x==2?0x2fb:0x3fb
#define MCR(x) x==2?0x2fc:0x3fc
#define LSR(x) x==2?0x2fd:0x3fd
#define MSR(x) x==2?0x2fe:0x3fe
#define SCR(x) x==2?0x2ff:0x3ff
#define DLL(x) x==2?0x2f8:0x3f8
#define DLM(x) x==2?0x2f9:0x3f9
int uart_charav(int port)
{
return ((inb(LSR(port)) & 1) != 0);
}
char uart_getchar(int port)
{
while (!uart_charav(port));
return ((char) inb(RBR(port)) & 0177);
}
static void uart_port_putchar(int port, unsigned char c)
{
if (c == '\n')
uart_port_putchar(port, '\r');
while (!(inb(LSR(port)) & 0x20));
outb(c, THR(port));
}
static void uart_init_line(int port, unsigned long baud)
{
int i, baudconst;
switch (baud) {
case 115200:
baudconst = 1;
break;
case 57600:
baudconst = 2;
break;
case 38400:
baudconst = 3;
break;
case 19200:
baudconst = 6;
break;
case 9600:
default:
baudconst = 12;
break;
}
outb(0x87, LCR(port));
outb(0x00, DLM(port));
outb(baudconst, DLL(port));
outb(0x07, LCR(port));
outb(0x0f, MCR(port));
for (i = 10; i > 0; i--) {
if (inb(LSR(port)) == (unsigned int) 0)
break;
inb(RBR(port));
}
}
#ifdef CONFIG_DEBUG_CONSOLE_SERIAL
int uart_init(int port, unsigned long speed)
{
uart_init_line(port, speed);
return -1;
}
void uart_putchar(int c)
{
uart_port_putchar(CONFIG_SERIAL_PORT, (unsigned char) (c & 0xff));
}
#endif
/* ( addr len -- actual ) */
static void
pc_serial_read(unsigned long *address)
{
char *addr;
int len;
len = POP();
addr = (char *)POP();
if (len != 1)
printk("pc_serial_read: bad len, addr %lx len %x\n", (unsigned long)addr, len);
if (uart_charav(*address)) {
*addr = (char)uart_getchar(*address);
PUSH(1);
} else {
PUSH(0);
}
}
/* ( addr len -- actual ) */
static void
pc_serial_write(unsigned long *address)
{
unsigned char *addr;
int i, len;
len = POP();
addr = (unsigned char *)POP();
for (i = 0; i < len; i++) {
uart_port_putchar(*address, addr[i]);
}
PUSH(len);
}
static void
pc_serial_close(void)
{
}
static void
pc_serial_open(unsigned long *address)
{
PUSH(find_ih_method("address", my_self()));
fword("execute");
*address = POP();
RET ( -1 );
}
DECLARE_UNNAMED_NODE(pc_serial, 0, sizeof(unsigned long));
NODE_METHODS(pc_serial) = {
{ "open", pc_serial_open },
{ "close", pc_serial_close },
{ "read", pc_serial_read },
{ "write", pc_serial_write },
};
void
ob_pc_serial_init(const char *path, const char *dev_name, uint64_t base,
uint64_t offset, int intr)
{
phandle_t aliases;
char nodebuff[128];
fword("new-device");
push_str(dev_name);
fword("device-name");
push_str("serial");
fword("device-type");
PUSH((base + offset) >> 32);
fword("encode-int");
PUSH((base + offset) & 0xffffffff);
fword("encode-int");
fword("encode+");
PUSH(SER_SIZE);
fword("encode-int");
fword("encode+");
push_str("reg");
fword("property");
#if !defined(CONFIG_SPARC64)
PUSH(offset);
fword("encode-int");
push_str("address");
fword("property");
#endif
#if defined(CONFIG_SPARC64)
set_int_property(get_cur_dev(), "interrupts", 1);
#endif
BIND_NODE_METHODS(get_cur_dev(), pc_serial);
PUSH(offset);
feval("value address");
fword("finish-device");
aliases = find_dev("/aliases");
snprintf(nodebuff, sizeof(nodebuff), "%s/%s", path, dev_name);
set_property(aliases, "ttya", nodebuff, strlen(nodebuff) + 1);
}