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.Logging;
11 using Antmicro.Renode.Utilities;
12 
13 namespace Antmicro.Renode.Core.USB.HID
14 {
15     public class Interface : USBInterface
16     {
Interface(IUSBDevice device, byte identifier, byte subClassCode = (byte)SubclassCode.BootInterfaceSubclass, byte protocol = (byte)HID.Protocol.None, string description = null, ReportDescriptor reportDescriptor = null)17         public Interface(IUSBDevice device,
18                                byte identifier,
19                                byte subClassCode = (byte)SubclassCode.BootInterfaceSubclass,
20                                byte protocol = (byte)HID.Protocol.None,
21                                string description = null,
22                                ReportDescriptor reportDescriptor = null) : base(device, identifier, USBClassCode.HumanInterfaceDevice, subClassCode, protocol, description)
23         {
24             HID_ReportDescriptor = reportDescriptor ?? new ReportDescriptor();
25             HID_Descriptor = new HID.Descriptor(HID_ReportDescriptor);
26 
27             RegisterSubdescriptor(HID_Descriptor, 0);
28         }
29 
30         public HID.Descriptor HID_Descriptor { get; }
31         public ReportDescriptor HID_ReportDescriptor { get; }
32 
HandleRequest(SetupPacket packet)33         public override BitStream HandleRequest(SetupPacket packet)
34         {
35             switch(packet.Type)
36             {
37                 case PacketType.Standard:
38                     return HandleStandardRequest(packet.Direction, (StandardRequest)packet.Request, packet.Value);
39                 case PacketType.Class:
40                     return HandleClassRequest(packet.Direction, (HidClassRequest)packet.Request, packet.Value);
41                 default:
42                     device.Log(LogLevel.Warning, "Unsupported type: 0x{0:X}", packet.Type);
43                     return BitStream.Empty;
44             }
45         }
46 
HandleClassRequest(Direction direction, HidClassRequest request, ushort value)47         private BitStream HandleClassRequest(Direction direction, HidClassRequest request, ushort value)
48         {
49             switch(request)
50             {
51                 case HidClassRequest.SetIdle:
52                     // we simply ignore this as we don't implement any repeated interrupts at all
53                     return BitStream.Empty;
54                 default:
55                     device.Log(LogLevel.Warning, "Unsupported class request: 0x{0:X}", request);
56                     return BitStream.Empty;
57             }
58         }
59 
HandleStandardRequest(Direction direction, StandardRequest request, ushort value)60         private BitStream HandleStandardRequest(Direction direction, StandardRequest request, ushort value)
61         {
62             switch(request)
63             {
64                 case StandardRequest.GetDescriptor:
65                     if(direction != Direction.DeviceToHost)
66                     {
67                         device.Log(LogLevel.Warning, "Unexpected standard request direction");
68                         return BitStream.Empty;
69                     }
70                     return HandleGetDescriptor(value);
71                 default:
72                     device.Log(LogLevel.Warning, "Unsupported standard request: 0x{0:X}", request);
73                     return BitStream.Empty;
74             }
75         }
76 
HandleGetDescriptor(ushort value)77         private BitStream HandleGetDescriptor(ushort value)
78         {
79             var descriptorType = (DescriptorType)(value >> 8);
80 
81             switch(descriptorType)
82             {
83                 case DescriptorType.HID:
84                     return HID_Descriptor.GetDescriptor(false);
85                 case DescriptorType.Report:
86                     return HID_ReportDescriptor.GetDescriptor(false);
87                 default:
88                     device.Log(LogLevel.Warning, "Unsupported descriptor type: 0x{0:X}", descriptorType);
89                     return BitStream.Empty;
90             }
91         }
92 
93         private enum HidClassRequest
94         {
95             GetReport = 0x1,
96             GetIdle = 0x2,
97             GetProtocol = 0x3,
98             // 0x4 - 0x8: reserved
99             SetReport = 0x9,
100             SetIdle = 0xa,
101             SetProtocol = 0xb
102         }
103     }
104 }