Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / drivers / pc_kbd.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  *          simple polling video/keyboard console functions
16  * ****************************************************************** */
17
18 #define SER_SIZE 8
19
20 /*
21  *  keyboard driver
22  */
23
24 static const char normal[] = {
25         0x0, 0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-',
26         '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o',
27         'p', '[', ']', 0xa, 0x0, 'a', 's', 'd', 'f', 'g', 'h', 'j',
28         'k', 'l', ';', 0x27, 0x60, 0x0, 0x5c, 'z', 'x', 'c', 'v', 'b',
29         'n', 'm', ',', '.', '/', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0,
30         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
31         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '0', 0x7f
32 };
33
34 static const char shifted[] = {
35         0x0, 0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_',
36         '+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O',
37         'P', '{', '}', 0xa, 0x0, 'A', 'S', 'D', 'F', 'G', 'H', 'J',
38         'K', 'L', ':', 0x22, '~', 0x0, '|', 'Z', 'X', 'C', 'V', 'B',
39         'N', 'M', '<', '>', '?', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0,
40         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '7', '8',
41         '9', 0x0, '4', '5', '6', 0x0, '1', '2', '3', '0', 0x7f
42 };
43
44 static int key_ext;
45 static int key_lshift = 0, key_rshift = 0, key_caps = 0;
46
47 static char last_key;
48
49 static void pc_kbd_cmd(unsigned char cmd, unsigned char val)
50 {
51         outb(cmd, 0x60);
52         /* wait until keyboard controller accepts cmds: */
53         while (inb(0x64) & 2);
54         outb(val, 0x60);
55         while (inb(0x64) & 2);
56 }
57
58 static void pc_kbd_controller_cmd(unsigned char cmd, unsigned char val)
59 {
60         outb(cmd, 0x64);
61         /* wait until keyboard controller accepts cmds: */
62         while (inb(0x64) & 2);
63         outb(val, 0x60);
64         while (inb(0x64) & 2);
65 }
66
67 static char pc_kbd_poll(void)
68 {
69         unsigned int c;
70         if (inb(0x64) & 1) {
71                 c = inb(0x60);
72                 switch (c) {
73                 case 0xe0:
74                         key_ext = 1;
75                         return 0;
76                 case 0x2a:
77                         key_lshift = 1;
78                         return 0;
79                 case 0x36:
80                         key_rshift = 1;
81                         return 0;
82                 case 0xaa:
83                         key_lshift = 0;
84                         return 0;
85                 case 0xb6:
86                         key_rshift = 0;
87                         return 0;
88                 case 0x3a:
89                         if (key_caps) {
90                                 key_caps = 0;
91                                 pc_kbd_cmd(0xed, 0);
92                         } else {
93                                 key_caps = 1;
94                                 pc_kbd_cmd(0xed, 4);    /* set caps led */
95                         }
96                         return 0;
97                 }
98
99                 if (key_ext) {
100                         // void printk(const char *format, ...);
101                         printk("extended keycode: %x\n", c);
102
103                         key_ext = 0;
104                         return 0;
105                 }
106
107                 if (c & 0x80)   /* unhandled key release */
108                         return 0;
109
110                 if (key_lshift || key_rshift)
111                         return key_caps ? normal[c] : shifted[c];
112                 else
113                         return key_caps ? shifted[c] : normal[c];
114         }
115         return 0;
116 }
117
118 int pc_kbd_dataready(void)
119 {
120         if (last_key)
121                 return 1;
122
123         last_key = pc_kbd_poll();
124
125         return (last_key != 0);
126 }
127
128 unsigned char pc_kbd_readdata(void)
129 {
130         char tmp;
131         while (!pc_kbd_dataready());
132         tmp = last_key;
133         last_key = 0;
134         return tmp;
135 }
136
137 /* ( addr len -- actual ) */
138 static void
139 pc_kbd_read(void)
140 {
141     unsigned char *addr;
142     int len;
143
144     len = POP();
145     addr = (unsigned char *)POP();
146
147     if (len != 1)
148         printk("pc_kbd_read: bad len, addr %lx len %x\n", (unsigned long)addr, len);
149
150     if (pc_kbd_dataready()) {
151         *addr = pc_kbd_readdata();
152         PUSH(1);
153     } else {
154         PUSH(0);
155     }
156 }
157
158 static void
159 pc_kbd_close(void)
160 {
161 }
162
163 static void
164 pc_kbd_open(unsigned long *address)
165 {
166     int len;
167     phandle_t ph;
168     unsigned long *prop;
169
170     fword("my-self");
171     fword("ihandle>phandle");
172     ph = (phandle_t)POP();
173     prop = (unsigned long *)get_property(ph, "address", &len);
174     *address = *prop;
175
176     RET ( -1 );
177 }
178
179 DECLARE_UNNAMED_NODE(pc_kbd, INSTALL_OPEN, sizeof(unsigned long));
180
181 NODE_METHODS(pc_kbd) = {
182     { "open",               pc_kbd_open              },
183     { "close",              pc_kbd_close             },
184     { "read",               pc_kbd_read              },
185 };
186
187 void
188 ob_pc_kbd_init(const char *path, const char *dev_name, uint64_t base,
189                uint64_t offset, int intr)
190 {
191     phandle_t chosen, aliases;
192     char nodebuff[128];
193
194     snprintf(nodebuff, sizeof(nodebuff), "%s/%s", path, dev_name);
195     REGISTER_NAMED_NODE(pc_kbd, nodebuff);
196
197     push_str(nodebuff);
198     fword("find-device");
199
200     push_str(dev_name);
201     fword("device-name");
202
203     push_str("serial");
204     fword("device-type");
205
206     PUSH(-1);
207     fword("encode-int");
208     push_str("keyboard");
209     fword("property");
210
211     PUSH((base + offset) >> 32);
212     fword("encode-int");
213     PUSH((base + offset) & 0xffffffff);
214     fword("encode-int");
215     fword("encode+");
216     PUSH(SER_SIZE);
217     fword("encode-int");
218     fword("encode+");
219     push_str("reg");
220     fword("property");
221     
222     PUSH(offset);
223     fword("encode-int");
224     push_str("address");
225     fword("property");
226
227     chosen = find_dev("/chosen");
228     push_str(nodebuff);
229     fword("open-dev");
230     set_int_property(chosen, "keyboard", POP());
231
232     aliases = find_dev("/aliases");
233     set_property(aliases, "keyboard", nodebuff, strlen(nodebuff) + 1);
234
235     pc_kbd_controller_cmd(0x60, 0x40); // Write mode command, translated mode
236 }