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