1 //
2 // Copyright (c) 2010-2018 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.Linq;
10 using Antmicro.Renode.Exceptions;
11 using Antmicro.Renode.Utilities;
12 
13 namespace Antmicro.Renode.Core.USB
14 {
15     public class USBConfiguration : DescriptorProvider
16     {
USBConfiguration(IUSBDevice device, byte identifier, string description = null, bool selfPowered = false, bool remoteWakeup = false, short maximalPower = 0)17         public USBConfiguration(IUSBDevice device,
18                                 byte identifier,
19                                 string description = null,
20                                 bool selfPowered = false,
21                                 bool remoteWakeup = false,
22                                 short maximalPower = 0) : base(9, (byte)DescriptorType.Configuration)
23         {
24             if(maximalPower > 500 || maximalPower < 0)
25             {
26                 throw new ConstructionException("Maximal power should be between 0 and 500 mA");
27             }
28 
29             this.device = device;
30 
31             interfaces = new List<USBInterface>();
32 
33             Identifier = identifier;
34             Description = description;
35             MaximalPower = maximalPower;
36             SelfPowered = selfPowered;
37             RemoteWakeup = remoteWakeup;
38 
39             RegisterSubdescriptors(interfaces);
40         }
41 
42         public USBConfiguration WithInterface<T>(byte subClassCode,
43                                                  byte protocol,
44                                                  string description = null,
45                                                  Action<T> configure = null) where T : USBInterface
46         {
47             var newInterface = (T)Activator.CreateInstance(typeof(T), device, (byte)interfaces.Count, subClassCode, protocol, description);
48             configure?.Invoke(newInterface);
49             return WithInterface(newInterface);
50         }
51 
WithInterface(USBInterface iface)52         public USBConfiguration WithInterface(USBInterface iface)
53         {
54             if(interfaces.Count == byte.MaxValue)
55             {
56                 throw new ConstructionException("The maximal number of interfaces reached");
57             }
58 
59             interfaces.Add(iface);
60             return this;
61         }
62 
63         public USBConfiguration WithInterface<T>(T iface, Action<USBInterface> configure = null) where T : USBInterface
64         {
65             if(interfaces.Count == byte.MaxValue)
66             {
67                 throw new ConstructionException("The maximal number of interfaces reached");
68             }
69 
70             configure?.Invoke(iface);
71             interfaces.Add(iface);
72             return this;
73         }
74 
WithInterface(USBClassCode classCode = USBClassCode.NotSpecified, byte subClassCode = 0, byte protocol = 0, string description = null, Action<USBInterface> configure = null)75         public USBConfiguration WithInterface(USBClassCode classCode = USBClassCode.NotSpecified,
76                                               byte subClassCode = 0,
77                                               byte protocol = 0,
78                                               string description = null,
79                                               Action<USBInterface> configure = null)
80         {
81             var newInterface = new USBInterface(device, (byte)interfaces.Count, classCode, subClassCode, protocol, description);
82             configure?.Invoke(newInterface);
83             return WithInterface(newInterface);
84         }
85 
86         public byte Identifier { get; }
87         public string Description { get; }
88         public short MaximalPower { get; }
89         public bool SelfPowered { get; }
90         public bool RemoteWakeup { get; }
91 
92         public IReadOnlyCollection<USBInterface> Interfaces => interfaces;
93 
FillDescriptor(BitStream buffer)94         protected override void FillDescriptor(BitStream buffer)
95         {
96             buffer
97                 .Append((short)RecursiveDescriptorLength)
98                 .Append((byte)Interfaces.Count)
99                 .Append(Identifier)
100                 .Append(USBString.FromString(Description).Index)
101                 .Append((byte)(((SelfPowered ? 1 : 0) << 6) | ((RemoteWakeup ? 1 : 0) << 5)))
102                 .Append((byte)((MaximalPower + 1) / 2));
103         }
104 
105         private readonly List<USBInterface> interfaces;
106         private readonly IUSBDevice device;
107     }
108 }