208 lines
4.2 KiB
C
208 lines
4.2 KiB
C
/*
|
|
* 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);
|
|
}
|