/* * 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); }