1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections.Generic; 9 using System.Dynamic; 10 using System.Linq; 11 using Antmicro.Renode.Exceptions; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Utilities; 14 using Antmicro.Renode.Utilities.Packets; 15 16 namespace Antmicro.Renode.Core.USB 17 { 18 public class USBDeviceCore : DescriptorProvider 19 { USBDeviceCore(IUSBDevice device, USBClassCode classCode = USBClassCode.NotSpecified, byte subClassCode = 0, byte protocol = 0, USBProtocol usbProtocolVersion = USBProtocol.USB_2_0, short deviceReleaseNumber = 0, PacketSize maximalPacketSize = PacketSize.Size64, string manufacturerName = null, string productName = null, string serialNumber = null, ushort vendorId = 0, ushort productId = 0, Action<SetupPacket, byte[], Action<byte[]>> customSetupPacketHandler = null)20 public USBDeviceCore(IUSBDevice device, 21 USBClassCode classCode = USBClassCode.NotSpecified, 22 byte subClassCode = 0, 23 byte protocol = 0, 24 USBProtocol usbProtocolVersion = USBProtocol.USB_2_0, 25 short deviceReleaseNumber = 0, 26 PacketSize maximalPacketSize = PacketSize.Size64, 27 string manufacturerName = null, 28 string productName = null, 29 string serialNumber = null, 30 ushort vendorId = 0, 31 ushort productId = 0, 32 Action<SetupPacket, byte[], Action<byte[]>> customSetupPacketHandler = null) : base(18, (byte)DescriptorType.Device) 33 { 34 if(maximalPacketSize != PacketSize.Size8 35 && maximalPacketSize != PacketSize.Size16 36 && maximalPacketSize != PacketSize.Size32 37 && maximalPacketSize != PacketSize.Size64) 38 { 39 throw new ConstructionException("Unsupported maximal packet size."); 40 } 41 42 this.customSetupPacketHandler = customSetupPacketHandler; 43 this.device = device; 44 configurations = new List<USBConfiguration>(); 45 46 CompatibleProtocolVersion = usbProtocolVersion; 47 Class = classCode; 48 SubClass = subClassCode; 49 Protocol = protocol; 50 DeviceReleaseNumber = deviceReleaseNumber; 51 MaximalPacketSize = maximalPacketSize; 52 ManufacturerName = manufacturerName; 53 ProductName = productName; 54 SerialNumber = serialNumber; 55 VendorId = vendorId; 56 ProductId = productId; 57 58 RegisterSubdescriptors(configurations); 59 } 60 Reset()61 public void Reset() 62 { 63 Address = 0; 64 65 if(SelectedConfiguration == null) 66 { 67 return; 68 } 69 70 foreach(var iface in SelectedConfiguration.Interfaces) 71 { 72 foreach(var epoint in iface.Endpoints) 73 { 74 epoint.Reset(); 75 } 76 } 77 78 SelectedConfiguration = null; 79 } 80 GetEndpoint(int endpointNumber, Direction direction)81 public USBEndpoint GetEndpoint(int endpointNumber, Direction direction) 82 { 83 if(SelectedConfiguration == null) 84 { 85 return null; 86 } 87 88 foreach(var iface in SelectedConfiguration.Interfaces) 89 { 90 var ep = iface.Endpoints.FirstOrDefault(x => x.Identifier == endpointNumber && x.Direction == direction); 91 if(ep != null) 92 { 93 return ep; 94 } 95 } 96 97 return null; 98 } 99 HandleSetupPacket(SetupPacket packet, Action<byte[]> resultCallback, byte[] additionalData = null)100 public void HandleSetupPacket(SetupPacket packet, Action<byte[]> resultCallback, byte[] additionalData = null) 101 { 102 var result = BitStream.Empty; 103 104 device.Log(LogLevel.Noisy, "Handling setup packet: {0}", packet); 105 106 if(customSetupPacketHandler != null) 107 { 108 customSetupPacketHandler(packet, additionalData, receivedBytes => 109 { 110 SendSetupResult(resultCallback, receivedBytes); 111 }); 112 } 113 else 114 { 115 switch(packet.Recipient) 116 { 117 case PacketRecipient.Device: 118 result = HandleRequest(packet); 119 break; 120 case PacketRecipient.Interface: 121 if(SelectedConfiguration == null) 122 { 123 device.Log(LogLevel.Warning, "Trying to access interface before selecting a configuration"); 124 resultCallback(new byte[0]); 125 return; 126 } 127 var iface = SelectedConfiguration.Interfaces.FirstOrDefault(x => x.Identifier == packet.Index); 128 if(iface == null) 129 { 130 device.Log(LogLevel.Warning, "Trying to access a non-existing interface #{0}", packet.Index); 131 } 132 result = iface.HandleRequest(packet); 133 break; 134 default: 135 device.Log(LogLevel.Warning, "Unsupported recipient type: 0x{0:X}", packet.Recipient); 136 break; 137 } 138 139 SendSetupResult(resultCallback, result.AsByteArray(packet.Count * 8u)); 140 } 141 } 142 SendSetupResult(Action<byte[]> resultCallback, byte[] result)143 private void SendSetupResult(Action<byte[]> resultCallback, byte[] result) 144 { 145 device.Log(LogLevel.Noisy, "Sending setup packet response of length {0}", result.Length); 146 #if DEBUG_PACKET 147 device.Log(LogLevel.Noisy, Misc.PrettyPrintCollectionHex(result)); 148 #endif 149 resultCallback(result); 150 } 151 HandleRequest(SetupPacket packet)152 private BitStream HandleRequest(SetupPacket packet) 153 { 154 if(packet.Type != PacketType.Standard) 155 { 156 device.Log(LogLevel.Warning, "Non standard requests are not supported"); 157 } 158 else 159 { 160 switch((StandardRequest)packet.Request) 161 { 162 case StandardRequest.SetAddress: 163 Address = checked((byte)packet.Value); 164 break; 165 case StandardRequest.GetDescriptor: 166 if(packet.Direction != Direction.DeviceToHost) 167 { 168 device.Log(LogLevel.Warning, "Wrong direction of Get Descriptor Standard Request"); 169 break; 170 } 171 return HandleGetDescriptor(packet.Value); 172 case StandardRequest.SetConfiguration: 173 SelectedConfiguration = Configurations.SingleOrDefault(x => x.Identifier == packet.Value); 174 if(SelectedConfiguration == null) 175 { 176 device.Log(LogLevel.Warning, "Tried to select a non-existing configuration #{0}", packet.Value); 177 } 178 break; 179 default: 180 device.Log(LogLevel.Warning, "Unsupported standard request: 0x{0:X}", packet.Request); 181 break; 182 } 183 } 184 185 return BitStream.Empty; 186 } 187 HandleGetDescriptor(ushort value)188 private BitStream HandleGetDescriptor(ushort value) 189 { 190 var descriptorType = (DescriptorType)(value >> 8); 191 var descriptorIndex = (byte)value; 192 193 switch(descriptorType) 194 { 195 case DescriptorType.Device: 196 return GetDescriptor(false); 197 case DescriptorType.Configuration: 198 if(Configurations.Count < descriptorIndex) 199 { 200 device.Log(LogLevel.Warning, "Tried to access a non-existing configuration #{0}", descriptorIndex); 201 return BitStream.Empty; 202 } 203 return Configurations.ElementAt(descriptorIndex).GetDescriptor(true); 204 case DescriptorType.String: 205 { 206 if(descriptorIndex == 0) 207 { 208 // special String Index returning a list of supported languages 209 return USBString.GetSupportedLanguagesDescriptor(); 210 } 211 else 212 { 213 var usbString = USBString.FromId(descriptorIndex); 214 if(usbString == null) 215 { 216 device.Log(LogLevel.Warning, "Tried to get non-existing string #{0}", descriptorIndex); 217 return BitStream.Empty; 218 } 219 220 return usbString.GetDescriptor(false); 221 } 222 } 223 default: 224 device.Log(LogLevel.Warning, "Unsupported descriptor type: 0x{0:X}", descriptorType); 225 return BitStream.Empty; 226 } 227 } 228 WithConfiguration(string description = null, bool selfPowered = false, bool remoteWakeup = false, short maximalPower = 0, Action<USBConfiguration> configure = null)229 public USBDeviceCore WithConfiguration(string description = null, bool selfPowered = false, bool remoteWakeup = false, short maximalPower = 0, Action<USBConfiguration> configure = null) 230 { 231 var newConfiguration = new USBConfiguration(device, (byte)(configurations.Count + 1), description, selfPowered, remoteWakeup, maximalPower); 232 configurations.Add(newConfiguration); 233 configure?.Invoke(newConfiguration); 234 return this; 235 } 236 237 public IReadOnlyCollection<USBConfiguration> Configurations => configurations; 238 239 public USBConfiguration SelectedConfiguration { get; set; } 240 public byte Address { get; set; } 241 242 public USBProtocol CompatibleProtocolVersion { get; } 243 public USBClassCode Class { get; } 244 public byte SubClass { get; } 245 public byte Protocol { get; } 246 public PacketSize MaximalPacketSize { get; } 247 248 public ushort VendorId { get; } 249 public ushort ProductId { get; } 250 251 public short DeviceReleaseNumber { get; } 252 253 public string ManufacturerName { get; } 254 public string ProductName { get; } 255 public string SerialNumber { get; } 256 FillDescriptor(BitStream buffer)257 protected override void FillDescriptor(BitStream buffer) 258 { 259 buffer 260 .Append((short)CompatibleProtocolVersion) 261 .Append((byte)Class) 262 .Append(SubClass) 263 .Append(Protocol) 264 .Append((byte)MaximalPacketSize) 265 .Append(VendorId) 266 .Append(ProductId) 267 .Append(DeviceReleaseNumber) 268 .Append(USBString.FromString(ManufacturerName).Index) 269 .Append(USBString.FromString(ProductName).Index) 270 .Append(USBString.FromString(SerialNumber).Index) 271 .Append((byte)Configurations.Count); 272 } 273 274 private readonly List<USBConfiguration> configurations; 275 private readonly IUSBDevice device; 276 277 private Action<SetupPacket, byte[], Action<byte[]>> customSetupPacketHandler; 278 } 279 } 280