1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2020/12/31     Bernard      Add license info
9  */
10 #include <rthw.h>
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 
14 #include "board.h"
15 #include "interrupt.h"
16 #include "drv_keyboard.h"
17 
18 #define DBG_LVL DBG_INFO
19 #include "rtdbg.h"
20 
21 #define KEYBOARD_ADDRESS    (0x10006000)
22 #define KEYBOARD_IRQ_NUM    (IRQ_VEXPRESS_A9_KBD)
23 
24 #ifdef PKG_USING_GUIENGINE
25 
26 #include <rtgui/event.h>
27 #include <rtgui/rtgui_server.h>
28 
29 typedef rt_uint32_t virtual_addr_t;
30 
31 enum{
32     KEYBOARD_CR     = 0x00,
33     KEYBOARD_STAT   = 0x04,
34     KEYBOARD_DATA   = 0x08,
35     KEYBOARD_CLKDIV = 0x0c,
36     KEYBOARD_IIR    = 0x10,
37 };
38 
39 struct keyboard_pl050_pdata_t
40 {
41     virtual_addr_t virt;
42     int irq;
43 };
44 
45 enum decode_state {
46     DECODE_STATE_MAKE_CODE,
47     DECODE_STATE_BREAK_CODE,
48     DECODE_STATE_LONG_MAKE_CODE,
49     DECODE_STATE_LONG_BREAK_CODE
50 };
51 
52 struct keymap {
53     rt_uint8_t data;
54     rt_uint32_t key;
55     rt_uint32_t unicode;
56     char *normal_key;
57 };
58 
59 enum key_value_t {
60     KEY_BUTTON_UP,
61     KEY_BUTTON_DOWN,
62 };
63 
64 enum {
65     KBD_LEFT_SHIFT  = (0x1 << 0),
66     KBD_RIGHT_SHIFT = (0x1 << 1),
67     KBD_LEFT_CTRL   = (0x1 << 2),
68     KBD_RIGHT_CTRL  = (0x1 << 3),
69     KBD_CAPS_LOCK   = (0x1 << 6),
70     KBD_NUM_LOCK    = (0x1 << 7),
71     KBD_SCROLL_LOCK = (0x1 << 8),
72 };
73 
74 static const struct keymap map[] = {
75     {0x1c,  RTGUIK_a, 0, "a",          },
76     {0x32,  RTGUIK_b, 0, "b",          },
77     {0x21,  RTGUIK_c, 0, "c",          },
78     {0x23,  RTGUIK_d, 0, "d",          },
79     {0x24,  RTGUIK_e, 0, "e",          },
80     {0x2b,  RTGUIK_f, 0, "f",          },
81     {0x34,  RTGUIK_g, 0, "g",          },
82     {0x33,  RTGUIK_h, 0, "h",          },
83     {0x43,  RTGUIK_i, 0, "i",          },
84     {0x3b,  RTGUIK_j, 0, "j",          },
85     {0x42,  RTGUIK_k, 0, "k",          },
86     {0x4b,  RTGUIK_l, 0, "l",          },
87     {0x3a,  RTGUIK_m, 0, "m",          },
88     {0x31,  RTGUIK_n, 0, "n",          },
89     {0x44,  RTGUIK_o, 0, "o",          },
90     {0x4d,  RTGUIK_p, 0, "p",          },
91     {0x15,  RTGUIK_q, 0, "q",          },
92     {0x2d,  RTGUIK_r, 0, "r",          },
93     {0x1b,  RTGUIK_s, 0, "s",          },
94     {0x2c,  RTGUIK_k, 0, "k",          },
95     {0x3c,  RTGUIK_u, 0, "u",          },
96     {0x2a,  RTGUIK_v, 0, "v",          },
97     {0x1d,  RTGUIK_w, 0, "w",          },
98     {0x22,  RTGUIK_x, 0, "x",          },
99     {0x35,  RTGUIK_y, 0, "y",          },
100     {0x1a,  RTGUIK_z, 0, "z",          },
101 
102     {0x45,  RTGUIK_0, 0, "0",          },
103     {0x16,  RTGUIK_1, 0, "1",          },
104     {0x1e,  RTGUIK_2, 0, "2",          },
105     {0x26,  RTGUIK_3, 0, "3",          },
106     {0x25,  RTGUIK_4, 0, "4",          },
107     {0x2e,  RTGUIK_5, 0, "5",          },
108     {0x36,  RTGUIK_6, 0, "6",          },
109     {0x3d,  RTGUIK_7, 0, "7",          },
110     {0x3e,  RTGUIK_8, 0, "8",          },
111     {0x46,  RTGUIK_9, 0, "9",          },
112 
113     {0x05,  RTGUIK_F1,  0, "F1",       },
114     {0x06,  RTGUIK_F2,  0, "F2",       },
115     {0x04,  RTGUIK_F3,  0, "F3",       },
116     {0x0c,  RTGUIK_F4,  0, "F4",       },
117     {0x03,  RTGUIK_F5,  0, "F5",       },
118     {0x0b,  RTGUIK_F6,  0, "F6",       },
119     {0x83,  RTGUIK_F7,  0, "F7",       },
120     {0x0a,  RTGUIK_F8,  0, "F8",       },
121     {0x01,  RTGUIK_F9,  0, "F9",       },
122     {0x09,  RTGUIK_F10, 0, "F10",      },
123     {0x78,  RTGUIK_F11, 0, "F11",      },
124     {0x07,  RTGUIK_F12, 0, "F12",      },
125 
126     {0x29,  RTGUIK_SPACE,  0, "SPACE"  },
127     {0x71,  RTGUIK_DELETE, 0, "DELETE" },
128     {0x52,  RTGUIK_QUOTE,  0, "'"      },
129     {0x55,  RTGUIK_EQUALS, 0, "="      },
130     {0x41,  RTGUIK_COMMA,  0, ","      },
131     {0x4e,  RTGUIK_MINUS,  0, "-"      },
132     // {0x49,  RTGUIK_,    0, "."         },
133     {0x4a,  RTGUIK_SLASH,  0, "/"      },
134     {0x4c,  RTGUIK_SEMICOLON, 0, ";"   },
135     {0x54,  RTGUIK_LEFTBRACKET, 0, "[" },
136     {0x5d,  RTGUIK_BACKSLASH, 0, "\\"  },
137     {0x5b,  RTGUIK_RIGHTBRACKET, 0, "]"},
138     {0x75,  RTGUIK_UP,    0, "UP"      },
139     {0x72,  RTGUIK_DOWN,  0, "DOWN"    },
140     {0x6b,  RTGUIK_LEFT,  0, "LEFT"    },
141     {0x74,  RTGUIK_RIGHT, 0, "RIGHT"   },
142     {0x0d,  RTGUIK_TAB,   0, "TAB"     },
143     {0x76,  RTGUIK_ESCAPE, 0, "ESC"    },
144     {0x37,  RTGUIK_POWER,  0, "POWER"  },
145     {0x5a,  RTGUIK_KP_ENTER, 0, "ENTER"},
146     {0x66,  RTGUIK_BACKSPACE, 0, "BACKSPACE"},
147 };
148 
read8(uint32_t addr)149 rt_inline rt_uint8_t read8(uint32_t addr)
150 {
151     return (*((volatile rt_uint8_t *)(addr)));
152 }
153 
write8(uint32_t addr,rt_uint8_t value)154 rt_inline void write8(uint32_t addr, rt_uint8_t value)
155 {
156     *((volatile rt_uint8_t *)(addr)) = value;
157 }
158 
read32(uint32_t addr)159 rt_inline rt_uint32_t read32(uint32_t addr)
160 {
161     return (*((volatile rt_uint32_t *)(addr)));
162 }
163 
write32(uint32_t addr,rt_uint32_t value)164 rt_inline void write32(uint32_t addr, rt_uint32_t value)
165 {
166     *((volatile rt_uint32_t *)(addr)) = value;
167 }
168 
kmi_write(struct keyboard_pl050_pdata_t * pdat,rt_uint8_t value)169 rt_inline int kmi_write(struct keyboard_pl050_pdata_t * pdat, rt_uint8_t value)
170 {
171     int timeout = 1000;
172 
173     while((read8(pdat->virt + KEYBOARD_STAT) & (1 << 6)) == 0 && timeout--);
174 
175     if(timeout)
176     {
177         write8(pdat->virt + KEYBOARD_DATA, value);
178         while((read8(pdat->virt + KEYBOARD_STAT) & (1 << 4)) == 0);
179 
180         if(read8(pdat->virt + KEYBOARD_DATA) == 0xfa)
181             return RT_TRUE;
182     }
183     return RT_FALSE;
184 }
185 
kmi_read(struct keyboard_pl050_pdata_t * pdat,rt_uint8_t * value)186 rt_inline int kmi_read(struct keyboard_pl050_pdata_t * pdat, rt_uint8_t * value)
187 {
188     if((read8(pdat->virt + KEYBOARD_STAT) & (1 << 4)))
189     {
190         *value = read8(pdat->virt + KEYBOARD_DATA);
191         return RT_TRUE;
192     }
193     return RT_FALSE;
194 }
195 
keyboard_report_event(void * device,rt_uint32_t flag,rt_uint8_t data,enum key_value_t press)196 static void keyboard_report_event(void * device, rt_uint32_t flag, rt_uint8_t data, enum key_value_t press)
197 {
198     struct rtgui_event_kbd key_event;
199     rt_uint16_t i = 0, mod = 0, find_key = 0;
200 
201     for(i = 0; i < sizeof(map)/sizeof(map[0]); i++)
202     {
203         if (map[i].data == data)
204         {
205             LOG_D("KEY info:");
206             if (flag & KBD_CAPS_LOCK)
207             {
208                 LOG_D("CAPS:LOCK");
209             }
210             else
211             {
212                 LOG_D("CAPS:UNLOCK");
213             }
214 
215             if (flag & KBD_LEFT_SHIFT)
216             {
217                 mod |= RTGUI_KMOD_LSHIFT;
218                 LOG_D("SHIFT:LEFT");
219             }
220             else if (flag & KBD_RIGHT_SHIFT)
221             {
222                 mod |= RTGUI_KMOD_RSHIFT;
223                 LOG_D("SHIFT:RIGHT");
224             }
225             else
226             {
227                 LOG_D("SHIFT:NULL");
228             }
229 
230             if (flag & KBD_LEFT_CTRL)
231             {
232                 mod |= RTGUI_KMOD_LCTRL;
233                 LOG_D("CTRL:LEFT");
234             }
235             else if (flag & KBD_RIGHT_CTRL)
236             {
237                 mod |= RTGUI_KMOD_RCTRL;
238                 LOG_D("CTRL:RIGHT");
239             }
240             else
241             {
242                 LOG_D("CTRL:NULL");
243             }
244 
245             LOG_D("flag:0x%08x value:0x%x key:%s status:%s", \
246                 flag, data, map[i].normal_key, press ==0 ? "UP" : "DOWN");
247             find_key = 1;
248             break;
249         }
250     }
251     if (find_key == 0)
252     {
253         LOG_D("flag:0x%08x value:0x%x key:%s status:%s", \
254             flag, data, "UNKNOWN", press ==0 ? "UP" : "DOWN");
255         return;
256     }
257 
258     key_event.parent.sender = RT_NULL;
259     key_event.parent.type = RTGUI_EVENT_KBD;
260     key_event.type = (press == 0 ? RTGUI_KEYUP : RTGUI_KEYDOWN);
261     key_event.key = map[i].key;
262     key_event.mod = mod;
263     key_event.unicode = map[i].unicode;
264     rtgui_server_post_event(&key_event.parent, sizeof(key_event));
265 }
266 
keyboard_pl050_interrupt(int irq,void * data)267 static void keyboard_pl050_interrupt(int irq, void *data)
268 {
269     struct keyboard_pl050_pdata_t * pdat = (struct keyboard_pl050_pdata_t *)data;
270     static enum decode_state ds = DECODE_STATE_MAKE_CODE;
271     static rt_uint32_t kbd_flag = KBD_NUM_LOCK;
272     rt_uint8_t status, value;
273 
274     status = read8(pdat->virt + KEYBOARD_IIR);
275 
276     while(status & (1 << 0))
277     {
278         value = read8(pdat->virt + KEYBOARD_DATA);
279 
280         switch(ds)
281         {
282         case DECODE_STATE_MAKE_CODE:
283             /* break code */
284             if(value == 0xf0)
285             {
286                 ds = DECODE_STATE_BREAK_CODE;
287             }
288             /* long make code */
289             else if(value == 0xe0)
290             {
291                 ds = DECODE_STATE_LONG_MAKE_CODE;
292             }
293             else
294             {
295                 ds = DECODE_STATE_MAKE_CODE;
296 
297                 /* left shift */
298                 if(value == 0x12)
299                 {
300                     kbd_flag |= KBD_LEFT_SHIFT;
301                 }
302                 /* right shift */
303                 else if(value == 0x59)
304                 {
305                     kbd_flag |= KBD_RIGHT_SHIFT;
306                 }
307                 /* left ctrl */
308                 else if(value == 0x14)
309                 {
310                     kbd_flag |= KBD_LEFT_CTRL;
311                 }
312                 /* caps lock */
313                 else if(value == 0x58)
314                 {
315                     if(kbd_flag & KBD_CAPS_LOCK)
316                         kbd_flag &= ~KBD_CAPS_LOCK;
317                     else
318                         kbd_flag |= KBD_CAPS_LOCK;
319                 }
320                 /* scroll lock */
321                 else if(value == 0x7e)
322                 {
323                     if(kbd_flag & KBD_SCROLL_LOCK)
324                         kbd_flag &= ~KBD_SCROLL_LOCK;
325                     else
326                         kbd_flag |= KBD_SCROLL_LOCK;
327                 }
328                 /* num lock */
329                 else if(value == 0x77)
330                 {
331                     if(kbd_flag & KBD_NUM_LOCK)
332                         kbd_flag &= ~KBD_NUM_LOCK;
333                     else
334                         kbd_flag |= KBD_NUM_LOCK;
335                 }
336                 /* others */
337                 else
338                 {
339                     keyboard_report_event(data, kbd_flag, value, KEY_BUTTON_DOWN);
340                 }
341             }
342             break;
343 
344         case DECODE_STATE_BREAK_CODE:
345             if( (value != 0xf0) && (value != 0xe0))
346             {
347                 ds = DECODE_STATE_MAKE_CODE;
348 
349                 /* left shift */
350                 if(value == 0x12)
351                 {
352                     kbd_flag &= ~KBD_LEFT_SHIFT;
353                 }
354                 /* right shift */
355                 else if(value == 0x59)
356                 {
357                     kbd_flag &= ~KBD_RIGHT_SHIFT;
358                 }
359                 /* left ctrl */
360                 else if(value == 0x14)
361                 {
362                     kbd_flag &= ~KBD_LEFT_CTRL;
363                 }
364                 /* others */
365                 else
366                 {
367                     keyboard_report_event(data, kbd_flag, value, KEY_BUTTON_UP);
368                 }
369             }
370             else
371             {
372                 ds = DECODE_STATE_BREAK_CODE;
373             }
374             break;
375 
376         case DECODE_STATE_LONG_MAKE_CODE:
377             if( value != 0xf0 && value!= 0xe0)
378             {
379                 ds = DECODE_STATE_MAKE_CODE;
380 
381                 /* left ctrl */
382                 if(value == 0x14)
383                 {
384                     kbd_flag |= KBD_RIGHT_CTRL;
385                 }
386                 /* others */
387                 else
388                 {
389                     keyboard_report_event(data, kbd_flag, value, KEY_BUTTON_DOWN);
390                 }
391             }
392             else
393             {
394                 ds = DECODE_STATE_LONG_BREAK_CODE;
395             }
396             break;
397 
398         case DECODE_STATE_LONG_BREAK_CODE:
399             if( (value != 0xf0) && (value != 0xe0))
400             {
401                 ds = DECODE_STATE_MAKE_CODE;
402 
403                 /* left ctrl */
404                 if(value == 0x14)
405                 {
406                     kbd_flag &= ~KBD_RIGHT_CTRL;
407                 }
408                 /* others */
409                 else
410                 {
411                     keyboard_report_event(data, kbd_flag, value, KEY_BUTTON_UP);
412                 }
413             }
414             else
415             {
416                 ds = DECODE_STATE_LONG_BREAK_CODE;
417             }
418             break;
419 
420         default:
421             ds = DECODE_STATE_MAKE_CODE;
422             break;
423         }
424 
425         status = read8(pdat->virt + KEYBOARD_IIR);
426     }
427 }
428 
rt_hw_keyboard_init(void)429 int rt_hw_keyboard_init(void)
430 {
431     rt_uint8_t value;
432     rt_uint32_t id;
433     struct keyboard_pl050_pdata_t *pdat;
434     virtual_addr_t virt;
435     int irq = KEYBOARD_IRQ_NUM;
436 
437     virt = (virtual_addr_t)rt_ioremap((void*)KEYBOARD_ADDRESS, 0x1000);
438 
439     id = (((read32(virt + 0xfec) & 0xff) << 24) |
440                 ((read32(virt + 0xfe8) & 0xff) << 16) |
441                 ((read32(virt + 0xfe4) & 0xff) <<  8) |
442                 ((read32(virt + 0xfe0) & 0xff) <<  0));
443 
444     if(((id >> 12) & 0xff) != 0x41 || (id & 0xfff) != 0x050)
445     {
446         LOG_E("read id fail id:0x%08x", id);
447         return -RT_ERROR;
448     }
449 
450     pdat = rt_malloc(sizeof(struct keyboard_pl050_pdata_t));
451     if(!pdat)
452     {
453         LOG_E("malloc memory failed");
454         return -RT_ERROR;
455     }
456     rt_memset(pdat, 0, sizeof(struct keyboard_pl050_pdata_t));
457 
458     pdat->virt = virt;
459     pdat->irq = irq;
460 
461     write8(pdat->virt + KEYBOARD_CLKDIV, 0);
462     write8(pdat->virt + KEYBOARD_CR, (1 << 2));
463     kmi_read(pdat, &value);
464     kmi_write(pdat, 0xff);
465     kmi_read(pdat, &value);
466     kmi_write(pdat, 0xf3);
467     kmi_write(pdat, 0x2b);
468     kmi_write(pdat, 0xf0);
469     kmi_write(pdat, 0x02);
470     kmi_write(pdat, 0xfa);
471     kmi_write(pdat, 0xed);
472     kmi_write(pdat, 0x02);
473     write8(pdat->virt + KEYBOARD_CR, (1 << 2) | (1 << 4));
474 
475     rt_hw_interrupt_install(irq, keyboard_pl050_interrupt, (void *)pdat, "keyboard");
476     rt_hw_interrupt_umask(irq);
477 
478     return RT_EOK;
479 }
480 INIT_DEVICE_EXPORT(rt_hw_keyboard_init);
481 
482 #endif
483