Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / drivers / pc_serial.c
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
32 int uart_charav(int port)
33 {
34         return ((inb(LSR(port)) & 1) != 0);
35 }
36
37 char uart_getchar(int port)
38 {
39         while (!uart_charav(port));
40         return ((char) inb(RBR(port)) & 0177);
41 }
42
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
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
88 int uart_init(int port, unsigned long speed)
89 {
90         uart_init_line(port, speed);
91         return -1;
92 }
93
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
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
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
138 pc_serial_close(void)
139 {
140 }
141
142 static void
143 pc_serial_open(unsigned long *address)
144 {
145     RET ( -1 );
146 }
147
148 static void
149 pc_serial_init(unsigned long *address)
150 {
151     *address = POP();
152 }
153
154 DECLARE_UNNAMED_NODE(pc_serial, INSTALL_OPEN, sizeof(unsigned long));
155
156 NODE_METHODS(pc_serial) = {
157     { "init",               pc_serial_init              },
158     { "open",               pc_serial_open              },
159     { "close",              pc_serial_close             },
160     { "read",               pc_serial_read              },
161     { "write",              pc_serial_write             },
162 };
163
164 void
165 ob_pc_serial_init(const char *path, const char *dev_name, uint64_t base,
166                   uint64_t offset, int intr)
167 {
168     phandle_t aliases;
169     char nodebuff[128];
170
171     snprintf(nodebuff, sizeof(nodebuff), "%s/%s", path, dev_name);
172     REGISTER_NAMED_NODE(pc_serial, nodebuff);
173
174     push_str(nodebuff);
175     fword("find-device");
176
177     PUSH(offset);
178     PUSH(find_package_method("init", get_cur_dev()));
179     fword("execute");
180
181     push_str("serial");
182     fword("device-type");
183
184     PUSH((base + offset) >> 32);
185     fword("encode-int");
186     PUSH((base + offset) & 0xffffffff);
187     fword("encode-int");
188     fword("encode+");
189     PUSH(SER_SIZE);
190     fword("encode-int");
191     fword("encode+");
192     push_str("reg");
193     fword("property");
194     
195 #if !defined(CONFIG_SPARC64)
196     PUSH(offset);
197     fword("encode-int");
198     push_str("address");
199     fword("property");
200 #endif
201     
202 #if defined(CONFIG_SPARC64)
203     set_int_property(get_cur_dev(), "interrupts", 1);
204 #endif
205
206     aliases = find_dev("/aliases");
207     set_property(aliases, "ttya", nodebuff, strlen(nodebuff) + 1);
208 }