1 //
2 // Copyright (c) 2010-2018 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Core;
12 
13 namespace Antmicro.Renode.Peripherals.Input
14 {
15     public class PS2Keyboard : IPS2Peripheral, IKeyboard
16     {
PS2Keyboard()17         public PS2Keyboard()
18         {
19             data = new Queue<byte>();
20             Reset();
21             data.Enqueue((byte)Command.SelfTestPassed);
22         }
23 
Read()24         public byte Read()
25         {
26             if(data.Count > 0)
27             {
28                 var result = data.Dequeue();
29                 NotifyParent();
30                 return result;
31             }
32             this.Log(LogLevel.Warning, "Attempted to read while no data in buffer. Returning 0.");
33             return 0;
34         }
35 
Write(byte value)36         public void Write(byte value)
37         {
38             switch((Command)value)
39             {
40             case Command.Reset:
41                 Reset();
42                 lock(data)
43                 {
44                     SendAck();
45                     data.Enqueue((byte)Command.SelfTestPassed);
46                 }
47                 break;
48             case Command.ReadId:
49                 lock(data)
50                 {
51                     SendAck();
52                     data.Enqueue((byte) (deviceId >> 8));
53                     data.Enqueue((byte) (deviceId & 0xff));
54                 }
55                 break;
56             default:
57                 this.Log(LogLevel.Warning, "Unhandled PS2 keyboard command: {0}", value);
58                 break;
59             }
60         }
61 
Press(KeyScanCode scanCode)62         public void Press(KeyScanCode scanCode)
63         {
64             var key = PS2ScanCodeTranslator.Instance.GetCode(scanCode);
65             data.Enqueue((byte)(key & 0x7f));
66             NotifyParent();
67         }
68 
Release(KeyScanCode scanCode)69         public void Release(KeyScanCode scanCode)
70         {
71             var key = PS2ScanCodeTranslator.Instance.GetCode(scanCode);
72             data.Enqueue((byte)Command.Release);
73             data.Enqueue((byte)(key & 0x7f));
74             NotifyParent();
75         }
76 
Reset()77         public void Reset()
78         {
79             data.Clear();
80         }
81 
82         public IPS2Controller Controller { get; set; }
83 
SendAck()84         private void SendAck()
85         {
86             data.Enqueue((byte)Command.Acknowledge);
87             NotifyParent();
88         }
89 
NotifyParent()90         private void NotifyParent()
91         {
92             if(Controller != null)
93             {
94                 if(data.Count > 0)
95                 {
96                     Controller.Notify();
97                 }
98             }
99             else
100             {
101                 this.Log(LogLevel.Noisy, "PS2 device not connected to any controller issued an update.");
102             }
103         }
104 
105         private readonly Queue<byte> data;
106         private const ushort deviceId = 0xABBA;
107 
108         private enum Command
109         {
110             Reset = 0xFF,
111             Acknowledge = 0xFA,
112             ReadId = 0xF2,
113             SetResetLeds = 0xED,
114             Release = 0xF0,
115             SelfTestPassed = 0xAA,
116         }
117     }
118 }
119