1 /*
2  * Copyright (C) 2003, 2004 Stefan Reinauer
3  *
4  * See the file "COPYING" for further information about
5  * the copyright and warranty status of this work.
6  */
7 
8 #include "config.h"
9 #include "libopenbios/bindings.h"
10 #include "kernel/kernel.h"
11 #include "drivers/drivers.h"
12 #include "libc/vsprintf.h"
13 
14 /* ******************************************************************
15  *                       serial console functions
16  * ****************************************************************** */
17 
18 #define SER_SIZE 8
19 
20 #define RBR(x)  x==2?0x2f8:0x3f8
21 #define THR(x)  x==2?0x2f8:0x3f8
22 #define IER(x)  x==2?0x2f9:0x3f9
23 #define IIR(x)  x==2?0x2fa:0x3fa
24 #define LCR(x)  x==2?0x2fb:0x3fb
25 #define MCR(x)  x==2?0x2fc:0x3fc
26 #define LSR(x)  x==2?0x2fd:0x3fd
27 #define MSR(x)  x==2?0x2fe:0x3fe
28 #define SCR(x)  x==2?0x2ff:0x3ff
29 #define DLL(x)  x==2?0x2f8:0x3f8
30 #define DLM(x)  x==2?0x2f9:0x3f9
31 
uart_charav(int port)32 int uart_charav(int port)
33 {
34 	return ((inb(LSR(port)) & 1) != 0);
35 }
36 
uart_getchar(int port)37 char uart_getchar(int port)
38 {
39 	while (!uart_charav(port));
40 	return ((char) inb(RBR(port)) & 0177);
41 }
42 
uart_port_putchar(int port,unsigned char c)43 static void uart_port_putchar(int port, unsigned char c)
44 {
45 	if (c == '\n')
46 		uart_port_putchar(port, '\r');
47 	while (!(inb(LSR(port)) & 0x20));
48 	outb(c, THR(port));
49 }
50 
uart_init_line(int port,unsigned long baud)51 static void uart_init_line(int port, unsigned long baud)
52 {
53 	int i, baudconst;
54 
55 	switch (baud) {
56 	case 115200:
57 		baudconst = 1;
58 		break;
59 	case 57600:
60 		baudconst = 2;
61 		break;
62 	case 38400:
63 		baudconst = 3;
64 		break;
65 	case 19200:
66 		baudconst = 6;
67 		break;
68 	case 9600:
69 	default:
70 		baudconst = 12;
71 		break;
72 	}
73 
74 	outb(0x87, LCR(port));
75 	outb(0x00, DLM(port));
76 	outb(baudconst, DLL(port));
77 	outb(0x07, LCR(port));
78 	outb(0x0f, MCR(port));
79 
80 	for (i = 10; i > 0; i--) {
81 		if (inb(LSR(port)) == (unsigned int) 0)
82 			break;
83 		inb(RBR(port));
84 	}
85 }
86 
87 #ifdef CONFIG_DEBUG_CONSOLE_SERIAL
uart_init(int port,unsigned long speed)88 int uart_init(int port, unsigned long speed)
89 {
90         uart_init_line(port, speed);
91 	return -1;
92 }
93 
uart_putchar(int c)94 void uart_putchar(int c)
95 {
96 	uart_port_putchar(CONFIG_SERIAL_PORT, (unsigned char) (c & 0xff));
97 }
98 #endif
99 
100 /* ( addr len -- actual ) */
101 static void
pc_serial_read(unsigned long * address)102 pc_serial_read(unsigned long *address)
103 {
104     char *addr;
105     int len;
106 
107     len = POP();
108     addr = (char *)POP();
109 
110     if (len != 1)
111         printk("pc_serial_read: bad len, addr %lx len %x\n", (unsigned long)addr, len);
112 
113     if (uart_charav(*address)) {
114         *addr = (char)uart_getchar(*address);
115         PUSH(1);
116     } else {
117         PUSH(0);
118     }
119 }
120 
121 /* ( addr len -- actual ) */
122 static void
pc_serial_write(unsigned long * address)123 pc_serial_write(unsigned long *address)
124 {
125     unsigned char *addr;
126     int i, len;
127 
128     len = POP();
129     addr = (unsigned char *)POP();
130 
131      for (i = 0; i < len; i++) {
132         uart_port_putchar(*address, addr[i]);
133     }
134     PUSH(len);
135 }
136 
137 static void
pc_serial_close(void)138 pc_serial_close(void)
139 {
140 }
141 
142 static void
pc_serial_open(unsigned long * address)143 pc_serial_open(unsigned long *address)
144 {
145     PUSH(find_ih_method("address", my_self()));
146     fword("execute");
147     *address = POP();
148 
149     RET ( -1 );
150 }
151 
152 DECLARE_UNNAMED_NODE(pc_serial, 0, sizeof(unsigned long));
153 
154 NODE_METHODS(pc_serial) = {
155     { "open",               pc_serial_open              },
156     { "close",              pc_serial_close             },
157     { "read",               pc_serial_read              },
158     { "write",              pc_serial_write             },
159 };
160 
161 void
ob_pc_serial_init(const char * path,const char * dev_name,uint64_t base,uint64_t offset,int intr)162 ob_pc_serial_init(const char *path, const char *dev_name, uint64_t base,
163                   uint64_t offset, int intr)
164 {
165     phandle_t aliases;
166     char nodebuff[128];
167 
168     fword("new-device");
169 
170     push_str(dev_name);
171     fword("device-name");
172 
173     push_str("serial");
174     fword("device-type");
175 
176     PUSH((base + offset) >> 32);
177     fword("encode-int");
178     PUSH((base + offset) & 0xffffffff);
179     fword("encode-int");
180     fword("encode+");
181     PUSH(SER_SIZE);
182     fword("encode-int");
183     fword("encode+");
184     push_str("reg");
185     fword("property");
186 
187 #if !defined(CONFIG_SPARC64)
188     PUSH(offset);
189     fword("encode-int");
190     push_str("address");
191     fword("property");
192 #endif
193 
194 #if defined(CONFIG_SPARC64)
195     set_int_property(get_cur_dev(), "interrupts", 1);
196 #endif
197 
198     BIND_NODE_METHODS(get_cur_dev(), pc_serial);
199 
200     PUSH(offset);
201     feval("value address");
202 
203     fword("finish-device");
204 
205     aliases = find_dev("/aliases");
206     snprintf(nodebuff, sizeof(nodebuff), "%s/%s", path, dev_name);
207     set_property(aliases, "ttya", nodebuff, strlen(nodebuff) + 1);
208 }
209