]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/edb7xxx/v2_0/misc/kbd_support.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / edb7xxx / v2_0 / misc / kbd_support.c
1 //==========================================================================
2 //
3 //        kbd_support.c
4 //
5 //        Cirrus Logic EDB7xxx eval board ASCII keyboard support functions
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):     gthomas
44 // Contributors:  gthomas
45 // Date:          1999-05-15
46 // Description:   Functions used to support ASCII keyboard
47 //####DESCRIPTIONEND####
48
49 static char kbd_server_stack[STACK_SIZE];
50 static cyg_thread kbd_server_thread_data;
51 static cyg_handle_t kbd_server_thread_handle;
52
53 static cyg_interrupt kbd_interrupt;
54 static cyg_handle_t  kbd_interrupt_handle;
55
56 static cyg_mbox      kbd_events_mbox;
57 static cyg_handle_t  kbd_events_mbox_handle;
58 static cyg_sem_t     kbd_sem;
59
60 static cyg_uint8 col_state[8];
61 static cyg_uint8 ext_state[8];
62
63 static void
64 kbd_delay(void)
65 {
66     volatile int i;
67     for (i = 0;  i < 250;  i++) ;
68 }
69
70 static void
71 kbd_scan(void)
72 {
73     int i;
74     cyg_uint8 port_data, ext_data;
75     // Turn off drive (de-select) all columns
76     *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
77         SYSCON1_KBD_LOW;
78     for (i = 0;  i < 8;  i++) {
79         // Select column 'i'
80         *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
81             SYSCON1_KBD_COL(i);
82         // Small pause to let the wires charge up :-)
83         kbd_delay();
84         // Grab the data
85         col_state[i] = port_data = *(volatile cyg_uint8 *)PADR;
86         ext_state[i] = ext_data = *(volatile cyg_uint8 *)KBD_PORT;
87         // De-Select column 'i'
88         *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
89             SYSCON1_KBD_TRISTATE;
90         // Allow line to go slack
91         kbd_delay();
92     }
93     // Turn on drive (select) all columns - necessary to see interrupts
94     *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
95         SYSCON1_KBD_HIGH;
96 }
97
98 static cyg_uint8     kbd_state[128];      // Known state of each key
99 static cyg_uint8     kbd_new_state[128];  // Current state of each key
100
101 // Row #1
102 #define KBD_Escape     0x00
103 #define KBD_F1         0x01
104 #define KBD_F2         0x02
105 #define KBD_F3         0x03
106 #define KBD_F4         0x04
107 #define KBD_F5         0x05
108 #define KBD_F6         0x06
109 #define KBD_F7         0x07
110 #define KBD_F8         0x08
111 #define KBD_F9         0x09
112 #define KBD_F10        0x0A
113 #define KBD_NumLock    0x0B
114 #define KBD_SysReq     0x0C
115 #define KBD_ScrlLock   0x0D
116 #define KBD_Break      0x0E
117 // Row #2
118 #define KBD_1          0x10
119 #define KBD_2          0x11
120 #define KBD_3          0x12
121 #define KBD_4          0x13
122 #define KBD_5          0x14
123 #define KBD_6          0x15
124 #define KBD_7          0x16
125 #define KBD_8          0x17
126 #define KBD_9          0x18
127 #define KBD_0          0x19
128 #define KBD_Hyphen     0x1A
129 #define KBD_Equals     0x1B
130 #define KBD_BackSpace  0x1C
131 #define KBD_Home       0x1D
132 // Row #3
133 #define KBD_Tab        0x20
134 #define KBD_Q          0x21
135 #define KBD_W          0x22
136 #define KBD_E          0x23
137 #define KBD_R          0x24
138 #define KBD_T          0x25
139 #define KBD_Y          0x26
140 #define KBD_U          0x27
141 #define KBD_I          0x28
142 #define KBD_O          0x29
143 #define KBD_P          0x2A
144 #define KBD_LeftBrkt   0x2B
145 #define KBD_RightBrkt  0x2C
146 #define KBD_BackSlash  0x2D
147 #define KBD_PageUp     0x2E
148 // Row #4
149 #define KBD_CapsLock   0x30
150 #define KBD_A          0x31
151 #define KBD_S          0x32
152 #define KBD_D          0x33
153 #define KBD_F          0x34
154 #define KBD_G          0x35
155 #define KBD_H          0x36
156 #define KBD_J          0x37
157 #define KBD_K          0x38
158 #define KBD_L          0x39
159 #define KBD_SemiColon  0x3A
160 #define KBD_Quote      0x3B
161 #define KBD_Enter      0x3C
162 #define KBD_PageDown   0x3D
163 // Row #5
164 #define KBD_LeftShift  0x40
165 #define KBD_Z          0x41
166 #define KBD_X          0x42
167 #define KBD_C          0x43
168 #define KBD_V          0x44
169 #define KBD_B          0x45
170 #define KBD_N          0x46
171 #define KBD_M          0x47
172 #define KBD_Comma      0x48
173 #define KBD_Period     0x49
174 #define KBD_Slash      0x4A
175 #define KBD_RightShift 0x4B
176 #define KBD_UpArrow    0x4C
177 #define KBD_End        0x4D
178 // Row #6
179 #define KBD_Ctrl       0x50
180 #define KBD_Function   0x51
181 #define KBD_LeftAlt    0x52
182 #define KBD_Accent     0x53
183 #define KBD_Space      0x54
184 #define KBD_RightAlt   0x55
185 #define KBD_Ins        0x56
186 #define KBD_Del        0x57
187 #define KBD_LeftArrow  0x58
188 #define KBD_DownArrow  0x59
189 #define KBD_RightArrow 0x5A
190
191 #define KBD_Press      0x80  // Event has this bit when the key is pressed
192 #define KBD_Empty      0xFF
193
194 // Map column, bit -> keycode
195 static cyg_uint32    kbd_map[8][16] = {
196     // Column #0
197     {KBD_Escape,    KBD_1,          KBD_Tab,        KBD_CapsLock,
198      KBD_BackSlash, KBD_Space,      KBD_LeftArrow,  KBD_UpArrow,
199      KBD_DownArrow, KBD_RightArrow, KBD_LeftShift,  KBD_Ctrl, 
200      KBD_Function,  KBD_LeftAlt,    KBD_RightAlt,   KBD_RightShift },
201     // Column #1
202     {KBD_F5,        KBD_6,          KBD_T,          KBD_G,  
203      KBD_B,         KBD_Slash,      KBD_SemiColon,  KBD_P,  
204      KBD_Hyphen,    KBD_F10,        KBD_Empty,      KBD_Empty,
205      KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty     },
206     // Column #2
207     {KBD_F4,        KBD_5,          KBD_R,          KBD_F,  
208      KBD_V,         KBD_Del,        KBD_Quote,      KBD_LeftBrkt,  
209      KBD_Equals,    KBD_NumLock,    KBD_Empty,      KBD_Empty,
210      KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
211     // Column #3
212     {KBD_F3,        KBD_4,          KBD_E,          KBD_D,  
213      KBD_C,         KBD_Ins,        KBD_Empty,      KBD_RightBrkt,  
214      KBD_BackSpace, KBD_SysReq,     KBD_Empty,      KBD_Empty,
215      KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
216     // Column #4
217     {KBD_F2,        KBD_3,          KBD_W,          KBD_S,  
218      KBD_X,         KBD_Empty,      KBD_Enter,      KBD_Empty,
219      KBD_Empty,     KBD_ScrlLock,   KBD_Empty,      KBD_Empty,
220      KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
221     // Column #5
222     {KBD_F1,        KBD_2,          KBD_Q,          KBD_A,  
223      KBD_Z,         KBD_End,        KBD_PageDown,   KBD_PageUp,
224      KBD_Home,      KBD_Break,      KBD_Empty,      KBD_Empty,
225      KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
226     // Column #6
227     {KBD_F6,        KBD_7,          KBD_Y,          KBD_H,  
228      KBD_N,         KBD_Period,     KBD_L,          KBD_O,  
229      KBD_0,         KBD_F9,         KBD_Empty,      KBD_Empty,
230      KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
231     // Column #7
232     {KBD_F7,        KBD_8,          KBD_U,          KBD_J,  
233      KBD_M,         KBD_Comma,      KBD_K,          KBD_I,  
234      KBD_9,         KBD_F8,         KBD_Empty,      KBD_Empty,
235      KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
236 };
237
238 static cyg_uint8 kbd_chars[96] = {
239     /* 0x00 - 0x0F */
240     0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241     /* 0x10 - 0x1F */
242      '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  '0',  '-',  '=', 0x08, 0x00, 0x00, 0x00,
243     /* 0x20 - 0x2F */
244     '\t',  'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',  'o',  'p',  '[',  ']', '\\', 0x00, 0x00,
245     /* 0x30 - 0x3F */
246     0x00,  'a',  's',  'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';', '\'', 0x0D, 0x00, 0x00, 0x00,
247     /* 0x40 - 0x4F */
248     0x00,  'z',  'x',  'c',  'v',  'b',  'n',  'm',  ',',  '.',  '/', 0x00, 0x00, 0x00, 0x00, 0x00,
249     /* 0x50 - 0x5F */
250     0x00, 0x00, 0x00, 0x00,  ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 };
252
253 static cyg_uint8 kbd_shifted_chars[96] = {
254     /* 0x00 - 0x0F */
255     '\b', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256     /* 0x10 - 0x1F */
257      '!',  '@',  '#',  '$',  '%',  '^',  '&',  '*',  '(',  ')',  '_',  '+', 0x08, 0x00, 0x00, 0x00,
258     /* 0x20 - 0x2F */
259     '\t',  'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',  'O',  'P',  '{',  '}',  '|', 0x00, 0x00,
260     /* 0x30 - 0x3F */
261     0x00,  'A',  'S',  'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':',  '"', 0x0D, 0x00, 0x00, 0x00,
262     /* 0x40 - 0x4F */
263     0x00,  'Z',  'X',  'C',  'V',  'B',  'N',  'M',  '<',  '>',  '?', 0x00, 0x00, 0x00, 0x00, 0x00,
264     /* 0x50 - 0x5F */
265     0x00, 0x00, 0x00, 0x00,  ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 };
267
268 // This ISR is called when the keyboard interrupt occurs
269 static int
270 keyboard_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
271 {
272     cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_KBDINT);
273     return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
274 }
275
276 // This DSR handles the keyboard [logical] processing
277 static void
278 keyboard_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
279 {
280     // Tell the keyboard processing thread to give it a shot
281     cyg_semaphore_post(&kbd_sem);
282 }
283
284 static void
285 kbd_server(cyg_addrword_t p)
286 {
287     int col, bit, key, event, timeout;
288     diag_printf("KBD server here\n");
289     while (TRUE) {
290         cyg_semaphore_wait(&kbd_sem);
291         // As long as keys are pressed, scan and update
292         timeout = 0;
293         while (TRUE) {
294             // Wait for 20ms - time to debounce keyboard
295             cyg_thread_delay(2);
296             // Scan keyboard
297             kbd_scan();
298             // Reset state
299             for (key = 0;  key < sizeof(kbd_new_state);  key++) {
300                 kbd_new_state[key] = 0;
301             }
302             // Check state of all keys and send events for those that change
303             for (col = 0;  col < 8;  col++) {
304                 for (bit = 0;  bit < 8;  bit++) {
305                     if (col_state[col] & (1<<bit)) {
306                         key = kbd_map[col][bit];
307                         if (key != KBD_Empty) {
308                             kbd_new_state[key] = 1;
309                         }
310                     }
311                     if (ext_state[col] & (1<<bit)) {
312                         key = kbd_map[col][bit+8];
313                         if (key != KBD_Empty) {
314                             kbd_new_state[key] = 1;
315                         }
316                     }
317                 }
318             }
319             // Compare new and old (known) states, generate events for changes
320             // Send events for modifier keys first.
321             for (key = 0;  key < sizeof(kbd_new_state);  key++) {
322                 if (kbd_state[key] != kbd_new_state[key]) {
323                     event = 0xFF;
324                     switch (key) {
325                     case KBD_LeftShift:
326                     case KBD_RightShift:
327                     case KBD_Ctrl:
328                     case KBD_LeftAlt:
329                     case KBD_RightAlt:
330                     case KBD_Function:
331                     case KBD_CapsLock:
332                         if (kbd_state[key]) {
333                             // Key going up
334                             event = key;
335                         } else {
336                             // Key going down
337                             event = key + KBD_Press;
338                         }
339                         kbd_state[key] = kbd_new_state[key];
340                     }
341                     if (event != 0xFF) {
342                         if (!cyg_mbox_tryput(kbd_events_mbox_handle, (void *)event)) {
343                             diag_printf("KBD event lost: %x\n", event);
344                         }
345                     }
346                 }
347             }
348             // First key up events
349             for (key = 0;  key < sizeof(kbd_new_state);  key++) {
350                 if (kbd_state[key] != kbd_new_state[key]) {
351                     if (kbd_state[key]) {
352                         // Key going up
353                         event = key;
354                     } else {
355                         // Key going down
356                         event = key + KBD_Press;
357                     }
358                     if (!cyg_mbox_tryput(kbd_events_mbox_handle, (void *)event)) {
359                         diag_printf("KBD event lost: %x\n", event);
360                     }
361                 }
362                 kbd_state[key] = kbd_new_state[key];
363             }
364             // Clear interrupt (true when keys are pressed)
365             cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT);
366 #if 0
367             if (*(volatile cyg_uint32 *)INTSR2 & INTSR2_KBDINT) {
368                 timeout = 0;
369             } else if (++timeout == 5) {
370                 // No keys for 100ms
371                 break;
372             }
373 #endif
374         }
375         // Allow interrupts to happen again
376         cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT);
377         cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_KBDINT);
378     }
379 }
380
381 void
382 kbd_init(void)
383 {
384     // Initialize environment, setup interrupt handler
385     cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_KBDINT,
386                              99,                     // Priority - what goes here?
387                              0,                      //  Data item passed to interrupt handler
388                              (cyg_ISR_t *)keyboard_isr,
389                              (cyg_DSR_t *)keyboard_dsr,
390                              &kbd_interrupt_handle,
391                              &kbd_interrupt);
392     cyg_drv_interrupt_attach(kbd_interrupt_handle);
393     cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT);
394     cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_KBDINT);
395     // Set up the mbox for keyboard data
396     cyg_mbox_create(&kbd_events_mbox_handle, &kbd_events_mbox);
397     // This semaphore is set when there is a keypress
398     cyg_semaphore_init(&kbd_sem, 0);  
399     // Create a thread whose job it is to de-bounce the keyboard and
400     // actually process the input, turning it into a series of events
401     cyg_thread_create(10,                           // Priority - just a number
402                       kbd_server,                   // entry
403                       0,                            // initial parameter
404                       "KBD_server",                 // Name
405                       &kbd_server_stack[0],         // Stack
406                       STACK_SIZE,                   // Size
407                       &kbd_server_thread_handle,    // Handle
408                       &kbd_server_thread_data       // Thread data structure
409             );
410     cyg_thread_resume(kbd_server_thread_handle);  // Start it
411 }
412
413 #define MOD_Shift    0x40
414 #define MOD_Ctrl     0x20
415 #define MOD_CapsLock 0x10
416 static cyg_uint32    kbd_modifiers;
417
418 cyg_uint8 
419 kbd_getc(void)
420 {
421     cyg_uint8 ch;
422     cyg_uint32 kbd_event;
423     while (TRUE) {
424         kbd_event = (cyg_uint32)cyg_mbox_get(kbd_events_mbox_handle);
425         switch (kbd_event & 0x7F) {
426         case KBD_LeftShift:
427         case KBD_RightShift:
428             if (kbd_event & KBD_Press) {
429                 kbd_modifiers |= MOD_Shift;
430             } else {
431                 kbd_modifiers &= ~MOD_Shift;
432             }
433             break;
434         case KBD_Ctrl:
435             if (kbd_event & KBD_Press) {
436                 kbd_modifiers |= MOD_Ctrl;
437             } else {
438                 kbd_modifiers &= ~MOD_Ctrl;
439             }
440             break;
441         case KBD_CapsLock:
442             if (kbd_event & KBD_Press) {                
443                 kbd_modifiers ^= MOD_CapsLock;
444             }
445             break;
446         case KBD_LeftAlt:
447         case KBD_RightAlt:
448         case KBD_Function:
449         default:
450         }
451         // Return character [if one has arrived]
452         if (kbd_event & KBD_Press) {
453             if (kbd_modifiers & (MOD_Shift|MOD_CapsLock)) {
454                 ch = kbd_shifted_chars[kbd_event & 0x7F];
455             } else {
456                 ch = kbd_chars[kbd_event & 0x7F];
457             }
458             if (kbd_modifiers & MOD_Ctrl) {
459                 ch &= 0x1F;
460             }
461             if (ch) {
462                 return (ch);
463             }
464         }
465     }
466 }