+libm
[meinos.git] / apps / console / keyboard.c
blob08b8c0a963e9241f67bac3f7a69e4f0361ee89be
1 /*
2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
20 #include <devfs.h>
21 #include <ioport.h>
22 #include <string.h>
23 #include <irq.h>
24 #include <fcntl.h>
25 #include <wchar.h>
26 #include <errno.h>
27 #include <ringbuf.h>
29 #include "console.h"
31 #define KEYBOARD_IRQ 0x01
32 #define KEYBOARD_PORT_DATA 0x60
33 #define KEYBOARD_PORT_STATUS 0x64
34 #define KEYBUF_SIZE 128
36 /// @todo later "/etc/..." should work (symlink)
37 #define KEYBOARD_DEFAULT_LAYOUT "/boot/etc/keyboard_layouts/de"
39 #define IS_SHIFT(scancode) (scancode==0x2A || scancode==0x36)
40 #define IS_ALTCAP(scancode) (scancode==0xB8)
42 struct {
43 int released;
44 int escape;
45 int shift;
46 int altcap;
47 ringbuf_t *buffer;
48 struct {
49 int has_shift;
50 int has_altcap;
51 unsigned int width; // Num of attributes
52 unsigned int height; // Num of keys
53 wchar_t *table;
54 } layout;
55 } keyboard;
57 static int keyboard_layout_load(const char *filename) {
58 int fh = open(filename,O_RDONLY);
59 if (fh!=-1) {
60 read(fh,&(keyboard.layout.has_shift),1);
61 read(fh,&(keyboard.layout.has_altcap),1);
62 keyboard.layout.width = 1+(keyboard.layout.has_shift?1:0)+(keyboard.layout.has_altcap?1:0);
63 read(fh,&(keyboard.layout.height),4);
64 keyboard.layout.table = calloc(keyboard.layout.width*keyboard.layout.height,sizeof(wchar_t));
65 read(fh,keyboard.layout.table,keyboard.layout.width*keyboard.layout.height*sizeof(wchar_t));
66 DEBUG("keyboard: Layout loaded: %s (width=%d; height=%d; shift=%s; altcap=%s)\n",filename,keyboard.layout.width,keyboard.layout.height,keyboard.layout.has_shift?"yes":"no",keyboard.layout.has_altcap?"yes":"no");
67 close(fh);
68 return 0;
70 else {
71 DEBUG("keyboard: %s: %s\n",strerror(errno),filename);
72 return -1;
76 /*static void keyboard_layout_unload() {
77 free(keyboard.layout.table);
78 memset(&keyboard.layout,0,sizeof(keyboard.layout));
79 }*/
81 static wchar_t scancode2wchr(int scancode) {
82 if (keyboard.layout.table==NULL) return 0;
83 // find right column in table
84 int col = 0;
85 if (keyboard.shift && keyboard.layout.has_shift) col = 1;
86 else if (keyboard.altcap && keyboard.layout.has_altcap) col = 2;
87 //if (col>=keyboard.layout.width) col = keyboard.layout.width-1;
88 // find right row in table
89 int row = scancode;
90 if (row>=keyboard.layout.height) row = keyboard.layout.height-1;
91 // return character
92 return keyboard.layout.table[row*keyboard.layout.width+col];
95 /**
96 * Gets keys from keyboard and parses it to characters
97 * @param buffer Buffer for read chars
98 * @param count How many chars to read
99 * @param dev Device to read from
100 * @return How many bytes read
102 ssize_t onread(devfs_dev_t *dev,void *buffer,size_t count,off_t offset) {
103 return ringbuf_read(keyboard.buffer,buffer,count);
107 * Handles Keyboard IRQ
108 * @param null Unused
109 * @todo Caps lock?
111 static void keyboard_irq(void *null) {
112 int released,scancode;
114 while (inb(KEYBOARD_PORT_STATUS)&1) {
115 // get scancode
116 scancode = inb(KEYBOARD_PORT_DATA);
117 if (scancode!=0xE0) {
118 released = scancode&0x80;
119 scancode &= 0x7F;
122 // check for escaped key
123 if (keyboard.escape) {
124 scancode |= 0x80;
125 keyboard.escape = 0;
127 if (scancode==0xE0) {
128 keyboard.escape = 1;
129 continue;
132 // if shift is pressed/released
133 if (IS_SHIFT(scancode)) keyboard.shift = !released;
134 // if alternative capital is pressed/released
135 else if (IS_ALTCAP(scancode)) keyboard.altcap = !released;
137 // write key into buffer
138 else if (!released) {
139 wchar_t chr = scancode2wchr(scancode);
140 if (chr>0x7F) DEBUG("TODO: Wide characters (%s %d)\n",__FILE__,__LINE__);
141 else if (chr!=0) {
142 //DEBUG("keyboard: Read character: '%c' (0x%02x)\n",chr,chr);
143 ringbuf_write(keyboard.buffer,&chr,1);
150 * Initializes keyboard driver
151 * @return 0=success; -1=failure
153 int init_keyboard() {
154 if (ioport_reg(KEYBOARD_PORT_DATA)==-1) return -1;
155 if (ioport_reg(KEYBOARD_PORT_STATUS)==-1) return -1;
156 irq_reghandler(KEYBOARD_IRQ,keyboard_irq,NULL,0);
158 memset(&keyboard,0,sizeof(keyboard));
159 keyboard.buffer = ringbuf_create(KEYBUF_SIZE);
160 keyboard_layout_load(KEYBOARD_DEFAULT_LAYOUT);
162 keyboard_irq(NULL);
163 return 0;