hc
2024-03-22 a0752693d998599af469473b8dc239ef973a012f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * @file UsbDescriptors.c
 * @brief Functions to read USB Interface and Capabilities descriptors
 *
 * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-2-Clause-Patent
 *
**/
 
#include "UsbDisplayLink.h"
#include "UsbDescriptors.h"
 
/**
 *
 * @param UsbIo
 * @param descriptorType
 * @param index
 * @param Buffer
 * @param Length
 * @param UsbStatus
 * @return
 */
STATIC EFI_STATUS
ReadDescriptor (
    IN EFI_USB_IO_PROTOCOL *UsbIo,
    UINT8 DescriptorType,
    UINT8 Index,
    VOID* Buffer,
    UINT16 Length,
    UINT32* UsbStatus)
{
  EFI_STATUS Status;
 
  UINT8 Header[2];
  ZeroMem (Header, sizeof (Header));
 
  EFI_USB_DEVICE_REQUEST Request;
  ZeroMem (&Request, sizeof (Request));
  Request.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_STANDARD | USB_TARGET_DEVICE;
  Request.Request = USB_REQ_GET_DESCRIPTOR;
  Request.Index = 0;
  Request.Value = DescriptorType << 8 | Index;
  Request.Length = sizeof (Header);
 
  // Read the descriptor header to see how many bytes it contains
  Status = UsbIo->UsbControlTransfer (
      UsbIo,
      &Request,
      EfiUsbDataIn,
      DISPLAYLINK_USB_CTRL_TIMEOUT,
      Header,
      sizeof (Header),
      UsbStatus);
 
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "Failed to read length of descriptor type x%x, index %u (code %r, USB status x%x)\n",
          DescriptorType, Index, Status, *UsbStatus));
    return Status;
  }
  CONST UINT16 TotalLength = Header[0];
 
  // Now we know the size of it, we can read the entire descriptor
  Request.Length = TotalLength;
 
  Status = UsbIo->UsbControlTransfer (
      UsbIo,
      &Request,
      EfiUsbDataIn,
      DISPLAYLINK_USB_CTRL_TIMEOUT,
      Buffer,
      TotalLength,
      UsbStatus);
 
  return Status;
}
 
/**
  Perform a USB control transfer to read the DisplayLink vendor descriptor.
 
  @param UsbIo   Pointer to the instance of the USBIO protocol
  @param Buffer  Pointer to the buffer where descriptor should be written
  @param Length  Length of buffer (and the maximum amount of descriptor data that shall be read)
 
  @retval EFI_SUCCESS  The descriptor has been copied into Buffer
  @retval Other        The descriptor could not be read
**/
EFI_STATUS
ReadCapabilitiesDescriptor (
    IN EFI_USB_IO_PROTOCOL *UsbIo,
    OUT VOID* Buffer,
    IN UINT16 Length)
{
  UINT32 UsbStatus;
  EFI_STATUS Status;
 
  Status = ReadDescriptor (
      UsbIo,
      DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY,
      0,
      Buffer,
      Length,
      &UsbStatus);
 
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "Could not read capabilities descriptor from DL device (code %r, USB status x%x). Unrecognised firmware version?\n", Status, UsbStatus));
  }
 
  return Status;
}
 
 
/**
 An alternative to the UBSIO protocol function EFI_USB_IO_GET_INTERFACE_DESCRIPTOR.
 This version allows you to specify an index.
 * @param UsbIo                 Pointer to the instance of the USBIO protocol
 * @param interfaceDescriptor   Where the descriptor should be written
 * @param index                 The index of the descriptor required (the standard USBIO function doesn't let you do this)
 * @return
 */
EFI_STATUS
UsbDisplayLinkGetInterfaceDescriptor (
    IN EFI_USB_IO_PROTOCOL *UsbIo,
    OUT EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
    UINT8 Index
    )
{
  UINT32 UsbStatus;
  EFI_STATUS Status;
 
  Status = ReadDescriptor (
      UsbIo,
      USB_DESC_TYPE_INTERFACE,
      Index,
      InterfaceDescriptor,
      sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
      &UsbStatus);
 
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "USB control transfer failed while reading interface descriptor (code %r, USB status x%x)\n", Status, UsbStatus));
  }
 
  return Status;
}