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