Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / dev / char / pckbd.c
1 /*
2  * <pckbd.c>
3  *
4  * Open Hack'Ware BIOS PC keyboard driver.
5  * 
6  *  Copyright (c) 2005 Jocelyn Mayer
7  *
8  *  This code is a rework (mostly simplification) from code
9  *  proposed by Matthew Wood <mwood@realmsys.com>
10  *
11  *   This program is free software; you can redistribute it and/or
12  *   modify it under the terms of the GNU General Public License V2
13  *   as published by the Free Software Foundation
14  *
15  *   This program is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with this program; if not, write to the Free Software
22  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include "bios.h"
28
29 /* IO definitions */
30 #define PCKBD_IO_BASE                   0x60
31 #define PCKBD_COMMAND_OFFSET            0x4
32 #define PCKBD_STATUS_OFFSET             0x4
33
34 /* Indexes for keyboard state */
35 #define SHIFT 0x1
36 #define CTRL  0x2
37 #define ALT   0x4
38
39 /* Scan codes */
40 #define L_SHIFT  0x2a
41 #define R_SHIFT  0x36
42 #define L_CTRL   0x1d
43 /* XXX: R_CTRL ? */
44 #define L_ALT    0x38
45 /* XXX: missing capslock */
46 /* XXX: TODO: add keypad/numlock ... (pc105 kbd) */
47
48 typedef struct kbdmap_t kbdmap_t;
49 struct kbdmap_t {
50     char translate[8];
51 };
52
53 typedef struct pckbd_t pckbd_t;
54 struct pckbd_t {
55     int modifiers;
56     kbdmap_t *map;
57     int maplen;
58     int io_base;
59 };
60
61 /* XXX: should not be here cause it's locale dependent */
62 static kbdmap_t pc_map_us[] = {
63     /* 0x00 */
64     { {   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
65     { { 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, }, },
66     { {  '1',  '!',   -1,   -1,  '1',  '!',   -1,   -1, }, },
67     { {  '2', '\'', '\'',   -1,   -1,  '2', '\'', '\'', }, },
68     { {  '3',  '#',   -1,   -1,  '3',  '#',   -1,   -1, }, },
69     { {  '4',  '$',   -1,   -1,  '4',  '$',   -1,   -1, }, },
70     { {  '5',  '%',   -1,   -1,  '5',  '%',   -1,   -1, }, },
71     { {  '6',  '^',   -1,   -1,  '6',  '^',   -1,   -1, }, },
72     /* 0x08 */
73     { {  '7',  '&',   -1,   -1,  '7',  '&',   -1,   -1, }, },
74     { {  '8',  '*',   -1,   -1,  '8',  '*',   -1,   -1, }, },
75     { {  '9',  '(',   -1,   -1,  '9',  '(',   -1,   -1, }, },
76     { {  '0',  ')',   -1,   -1,  '0',  ')',   -1,   -1, }, },
77     { {  '-',  '_',   -1,   -1,  '-',  '_',   -1,   -1, }, },
78     { {  '=',  '+',   -1,   -1,  '=',  '+',   -1,   -1, }, },
79     { { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, },
80     { { 0x2a,   -1,   -1,   -1, 0x2a,   -1,   -1,   -1, }, },
81     /* 0x10 */
82     { {  'q',  'Q',   -1,   -1,  'q',  'Q',   -1,   -1, }, },
83     { {  'w',  'W',   -1,   -1,  'w',  'W',   -1,   -1, }, },
84     { {  'e',  'E',   -1,   -1,  'e',  'E',   -1,   -1, }, },
85     { {  'r',  'R',   -1,   -1,  'r',  'R',   -1,   -1, }, },
86     { {  't',  'T',   -1,   -1,  't',  'T',   -1,   -1, }, },
87     { {  'y',  'Y',   -1,   -1,  'y',  'Y',   -1,   -1, }, },
88     { {  'u',  'U',   -1,   -1,  'u',  'U',   -1,   -1, }, },
89     { {  'i',  'I',   -1,   -1,  'i',  'I',   -1,   -1, }, },
90     /* 0x18 */
91     { {  'o',  'O',   -1,   -1,  'o',  'O',   -1,   -1, }, },
92     { {  'p',  'P',   -1,   -1,  'p',  'P',   -1,   -1, }, },
93     { {  '[',  '{', 0x1b, 0x1b,  '[',  '{', 0x1b, 0x1b, }, },
94     { {  ']',  '}',   -1,   -1,  ']',  '}',   -1,   -1, }, },
95     { { 0x0d, 0x0d, '\r', '\r', 0x0d, 0x0d, '\r', '\r', }, },
96     { {   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
97     { {  'a',  'A',   -1,   -1,  'a',  'A',   -1,   -1, }, },
98     { {  's',  'S',   -1,   -1,  's',  'S',   -1,   -1, }, },
99     /* 0x20 */
100     { {  'd',  'D',   -1,   -1,  'd',  'D',   -1,   -1, }, },
101     { {  'f',  'F',   -1,   -1,  'f',  'F',   -1,   -1, }, },
102     { {  'g',  'G', 0x07, 0x07,  'g',  'G', 0x07, 0x07, }, },
103     { {  'h',  'H', 0x08, 0x08,  'h',  'H', 0x08, 0x08, }, },
104     { {  'j',  'J', '\r', '\r',  'j',  'J', '\r', '\r', }, },
105     { {  'k',  'K',   -1,   -1,  'k',  'K',   -1,   -1, }, },
106     { {  'l',  'L',   -1,   -1,  'l',  'L',   -1,   -1, }, },
107     { {  ';',  ':',   -1,   -1,  ';',  ':',   -1,   -1, }, },
108     /* 0x28 */
109     { { '\'',  '"',   -1,   -1, '\'',  '"',   -1,   -1, }, },
110     { {  '`',  '~',   -1,   -1,  '`',  '~',   -1,   -1, }, },
111     { { 0x02,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
112     { { '\\',  '|',   -1,   -1, '\\',  '|',   -1,   -1, }, },
113     { {  'z',  'Z',   -1,   -1,  'z',  'Z',   -1,   -1, }, },
114     { {  'x',  'X',   -1,   -1,  'x',  'X',   -1,   -1, }, },
115     { {  'c',  'C',   -1,   -1,  'c',  'C',   -1,   -1, }, },
116     { {  'v',  'V', 0x16, 0x16,  'v',  'V',   -1,   -1, }, },
117     /* 0x30 */
118     { {  'b',  'B',   -1,   -1,  'b',  'B',   -1,   -1, }, },
119     { {  'n',  'N',   -1,   -1,  'n',  'N',   -1,   -1, }, },
120     { {  'm',  'M', 0x0d, 0x0d,  'm',  'M', 0x0d, 0x0d, }, },
121     { {  ',',  '<',   -1,   -1,  ',',  '<',   -1,   -1, }, },
122     { {  '.',  '>',   -1,   -1,  '.',  '>',   -1,   -1, }, },
123     { {  '/',  '?',   -1,   -1,  '/',  '?',   -1,   -1, }, },
124     { {   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
125     { {  '*',  '*',   -1,   -1,  '*',  '*',   -1,   -1, }, },
126     /* 0x38 */
127     { {   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, }, },
128     { {  ' ',  ' ',  ' ',  ' ',  ' ',  ' ',  ' ',  ' ', }, },
129 };
130
131 static int pckbd_open (unused void *private)
132 {
133     return 0;
134 }
135
136 static int pckbd_close (unused void *private)
137 {
138     return 0;
139 }
140
141 static int pckbd_readb (void *private)
142 {
143     pckbd_t *kbd = private;
144     int status, key, up, mod;
145     int ret;
146
147     for (ret = -1; ret < 0; ) {
148         status = inb(kbd->io_base + PCKBD_STATUS_OFFSET);
149         if (!(status & 1)) {
150             /* No more data available */
151             break;
152         }
153         key = inb(kbd->io_base);
154         up = (key & 0x80) != 0;
155         key &= ~0x80;
156         switch (key) {
157         case 0:
158             break;
159         case L_ALT:
160             mod = ALT;
161             goto set_modifiers;
162         case L_SHIFT:
163         case R_SHIFT:
164             mod = SHIFT;
165             goto set_modifiers;
166         case L_CTRL:
167 #if 0 /* XXX: missing definition */
168         case R_CTRL:
169 #endif
170             mod = CTRL;
171         set_modifiers:
172             if (up)
173                 kbd->modifiers &= ~mod;
174             else
175                 kbd->modifiers |= mod;
176             break;
177         default:
178             /* We don't care about up events or unknown keys */
179             if (!up && key < kbd->maplen)
180                 ret = kbd->map[key].translate[kbd->modifiers];
181             break;
182         }
183     }
184
185     return ret;
186 }
187
188 static cops_t pckbd_ops = {
189     &pckbd_open,
190     &pckbd_close,
191     &pckbd_readb,
192     NULL,
193 };
194
195 int pckbd_register (void)
196 {
197     pckbd_t *kbd;
198
199     kbd = malloc(sizeof(pckbd_t));
200     if (kbd == NULL)
201         return -1;
202     memset(kbd, 0, sizeof(pckbd_t));
203     /* Set IO base */
204     /* XXX: should be a parameter... */
205     kbd->io_base = PCKBD_IO_BASE;
206     /* Set default keymap */
207     kbd->map = pc_map_us;
208     kbd->maplen = sizeof(pc_map_us) / sizeof(kbdmap_t);
209     /* Reset modifiers state */
210     kbd->modifiers = 0x00;
211     chardev_register(CHARDEV_KBD, &pckbd_ops, kbd);
212
213     return 0;
214 }