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 using Antmicro.Renode.Utilities; 13 14 namespace Antmicro.Renode.Peripherals.Input 15 { 16 public class PS2Mouse : IPS2Peripheral, IRelativePositionPointerInput 17 { PS2Mouse()18 public PS2Mouse() 19 { 20 data = new Queue<byte>(); 21 Reset(); 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 if(lastCommand == Command.None) 39 { 40 switch((Command)value) 41 { 42 case Command.Reset: 43 AckAndReset(); 44 break; 45 case Command.GetDeviceId: 46 lock(data) 47 { 48 SendAck(); 49 data.Enqueue(0x00); 50 } 51 break; 52 case Command.SetSampleRate: 53 case Command.SetResolution: 54 lastCommand = (Command)value; 55 SendAck(); 56 break; 57 default: 58 this.Log(LogLevel.Warning, "Unhandled PS2 command: {0}", (Command)value); 59 break; 60 } 61 } 62 else 63 { 64 switch(lastCommand) 65 { 66 case Command.SetSampleRate: 67 case Command.SetResolution: 68 SendAck(); 69 break; 70 } 71 lastCommand = Command.None; 72 } 73 } 74 MoveBy(int x, int y)75 public void MoveBy(int x, int y) 76 { 77 byte dataByte = buttonState; 78 y = -y; 79 if(x < 0) 80 { 81 dataByte |= 1 << 4; 82 } 83 if(y < 0) 84 { 85 dataByte |= 1 << 5; 86 } 87 88 x = x.Clamp(-255, 255); 89 y = y.Clamp(-255, 255); 90 91 lock(data) 92 { 93 data.Enqueue(dataByte); 94 data.Enqueue((byte)x); 95 data.Enqueue((byte)y); 96 } 97 NotifyParent(); 98 } 99 Press(MouseButton button = MouseButton.Left)100 public void Press(MouseButton button = MouseButton.Left) 101 { 102 buttonState |= (byte)button; 103 SendButtonState(); 104 } 105 Release(MouseButton button = MouseButton.Left)106 public void Release(MouseButton button = MouseButton.Left) 107 { 108 buttonState &= (byte) ~button; 109 SendButtonState(); 110 } 111 Reset()112 public void Reset() 113 { 114 buttonState = 0x08; 115 data.Clear(); 116 } 117 118 public IPS2Controller Controller { get; set; } 119 SendButtonState()120 private void SendButtonState() 121 { 122 lock(data) 123 { 124 data.Enqueue(buttonState); 125 data.Enqueue(0x00); 126 data.Enqueue(0x00); 127 } 128 NotifyParent(); 129 } 130 AckAndReset()131 private void AckAndReset() 132 { 133 Reset(); 134 lock(data) 135 { 136 SendAck(); 137 data.Enqueue((byte) Command.SelfTestPassed); 138 data.Enqueue(0x00); 139 } 140 } 141 SendAck()142 private void SendAck() 143 { 144 data.Enqueue((byte)Command.Acknowledge); 145 NotifyParent(); 146 } 147 NotifyParent()148 private void NotifyParent() 149 { 150 if(Controller != null) 151 { 152 if(data.Count > 0) 153 { 154 Controller.Notify(); 155 } 156 } 157 else 158 { 159 this.Log(LogLevel.Noisy, "PS2 device not connected to any controller issued an update."); 160 } 161 } 162 163 private Command lastCommand; 164 private byte buttonState; 165 private readonly Queue<byte> data; 166 167 enum Command : byte 168 { 169 Reset = 0xFF, 170 SetSampleRate = 0xF3, 171 GetDeviceId = 0xF2, 172 SetResolution = 0xE8, 173 Acknowledge = 0xFA, 174 SelfTestPassed = 0xAA, 175 None = 0x00, 176 } 177 } 178 } 179