Coverage Report

Created: 2026-10-17 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-usb-endpoint.c
Line
Count
Source
1
/*
2
 * Copyright 2020 Emmanuel Pacaud <emmanuel@gnome.org>
3
 * Copyright 2024 Richard Hughes <richard@hughsie.com>
4
 *
5
 * SPDX-License-Identifier: LGPL-2.1-or-later
6
 */
7
8
/**
9
 * FuUsbEndpoint:
10
 *
11
 * This object is a thin glib wrapper around a libusb_endpoint_descriptor.
12
 *
13
 * All the data is copied when the object is created and the original
14
 * descriptor can be destroyed any at point.
15
 */
16
17
#include "config.h"
18
19
#include <string.h>
20
21
#include "fu-input-stream.h"
22
#include "fu-usb-endpoint-private.h"
23
24
struct _FuUsbEndpoint {
25
  FuUsbDescriptor parent_instance;
26
  struct libusb_endpoint_descriptor endpoint_descriptor;
27
};
28
29
static void
30
fu_usb_endpoint_codec_iface_init(FwupdCodecInterface *iface);
31
32
69.7k
G_DEFINE_TYPE_EXTENDED(FuUsbEndpoint,
33
69.7k
           fu_usb_endpoint,
34
69.7k
           FU_TYPE_USB_DESCRIPTOR,
35
69.7k
           0,
36
69.7k
           G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC, fu_usb_endpoint_codec_iface_init));
37
69.7k
38
69.7k
static gboolean
39
69.7k
fu_usb_endpoint_from_json(FwupdCodec *codec, FwupdJsonObject *json_obj, GError **error)
40
69.7k
{
41
0
  FuUsbEndpoint *self = FU_USB_ENDPOINT(codec);
42
0
  gint64 tmpi = 0;
43
44
  /* optional properties */
45
0
  if (!fwupd_json_object_get_integer_with_default(json_obj,
46
0
              "DescriptorType",
47
0
              &tmpi,
48
0
              0x0,
49
0
              error))
50
0
    return FALSE;
51
0
  self->endpoint_descriptor.bDescriptorType = tmpi;
52
0
  if (!fwupd_json_object_get_integer_with_default(json_obj,
53
0
              "EndpointAddress",
54
0
              &tmpi,
55
0
              0x0,
56
0
              error))
57
0
    return FALSE;
58
0
  self->endpoint_descriptor.bEndpointAddress = tmpi;
59
0
  if (!fwupd_json_object_get_integer_with_default(json_obj, "Refresh", &tmpi, 0x0, error))
60
0
    return FALSE;
61
0
  self->endpoint_descriptor.bRefresh = tmpi;
62
0
  if (!fwupd_json_object_get_integer_with_default(json_obj, "Interval", &tmpi, 0x0, error))
63
0
    return FALSE;
64
0
  self->endpoint_descriptor.bInterval = tmpi;
65
0
  if (!fwupd_json_object_get_integer_with_default(json_obj,
66
0
              "SynchAddress",
67
0
              &tmpi,
68
0
              0x0,
69
0
              error))
70
0
    return FALSE;
71
0
  self->endpoint_descriptor.bSynchAddress = tmpi;
72
0
  if (!fwupd_json_object_get_integer_with_default(json_obj,
73
0
              "MaxPacketSize",
74
0
              &tmpi,
75
0
              0x0,
76
0
              error))
77
0
    return FALSE;
78
0
  self->endpoint_descriptor.wMaxPacketSize = tmpi;
79
80
  /* success */
81
0
  return TRUE;
82
0
}
83
84
static void
85
fu_usb_endpoint_add_json(FwupdCodec *codec, FwupdJsonObject *json_obj, FwupdCodecFlags flags)
86
0
{
87
0
  FuUsbEndpoint *self = FU_USB_ENDPOINT(codec);
88
89
  /* optional properties */
90
0
  if (self->endpoint_descriptor.bDescriptorType != 0) {
91
0
    fwupd_json_object_add_integer(json_obj,
92
0
                "DescriptorType",
93
0
                self->endpoint_descriptor.bDescriptorType);
94
0
  }
95
0
  if (self->endpoint_descriptor.bEndpointAddress != 0) {
96
0
    fwupd_json_object_add_integer(json_obj,
97
0
                "EndpointAddress",
98
0
                self->endpoint_descriptor.bEndpointAddress);
99
0
  }
100
0
  if (self->endpoint_descriptor.bRefresh != 0) {
101
0
    fwupd_json_object_add_integer(json_obj,
102
0
                "Refresh",
103
0
                self->endpoint_descriptor.bRefresh);
104
0
  }
105
0
  if (self->endpoint_descriptor.bInterval != 0) {
106
0
    fwupd_json_object_add_integer(json_obj,
107
0
                "Interval",
108
0
                self->endpoint_descriptor.bInterval);
109
0
  }
110
0
  if (self->endpoint_descriptor.bSynchAddress != 0) {
111
0
    fwupd_json_object_add_integer(json_obj,
112
0
                "SynchAddress",
113
0
                self->endpoint_descriptor.bSynchAddress);
114
0
  }
115
0
  if (self->endpoint_descriptor.wMaxPacketSize != 0) {
116
0
    fwupd_json_object_add_integer(json_obj,
117
0
                "MaxPacketSize",
118
0
                self->endpoint_descriptor.wMaxPacketSize);
119
0
  }
120
0
}
121
122
/**
123
 * fu_usb_endpoint_get_maximum_packet_size:
124
 * @self: a #FuUsbEndpoint
125
 *
126
 * Gets the maximum packet size this endpoint is capable of sending/receiving.
127
 *
128
 * Return value: The maximum packet size
129
 *
130
 * Since: 2.0.0
131
 **/
132
guint16
133
fu_usb_endpoint_get_maximum_packet_size(FuUsbEndpoint *self)
134
0
{
135
0
  g_return_val_if_fail(FU_IS_USB_ENDPOINT(self), 0);
136
0
  return self->endpoint_descriptor.wMaxPacketSize;
137
0
}
138
139
/**
140
 * fu_usb_endpoint_get_polling_interval:
141
 * @self: a #FuUsbEndpoint
142
 *
143
 * Gets the endpoint polling interval.
144
 *
145
 * Return value: The endpoint polling interval
146
 *
147
 * Since: 2.0.0
148
 **/
149
guint8
150
fu_usb_endpoint_get_polling_interval(FuUsbEndpoint *self)
151
0
{
152
0
  g_return_val_if_fail(FU_IS_USB_ENDPOINT(self), 0);
153
0
  return self->endpoint_descriptor.bInterval;
154
0
}
155
156
/**
157
 * fu_usb_endpoint_get_address:
158
 * @self: a #FuUsbEndpoint
159
 *
160
 * Gets the address of the endpoint.
161
 *
162
 * Return value: The 4-bit endpoint address
163
 *
164
 * Since: 2.0.0
165
 **/
166
guint8
167
fu_usb_endpoint_get_address(FuUsbEndpoint *self)
168
0
{
169
0
  g_return_val_if_fail(FU_IS_USB_ENDPOINT(self), 0);
170
0
  return self->endpoint_descriptor.bEndpointAddress;
171
0
}
172
173
/**
174
 * fu_usb_endpoint_get_number:
175
 * @self: a #FuUsbEndpoint
176
 *
177
 * Gets the number part of endpoint address.
178
 *
179
 * Return value: The lower 4-bit of endpoint address
180
 *
181
 * Since: 2.0.0
182
 **/
183
guint8
184
fu_usb_endpoint_get_number(FuUsbEndpoint *self)
185
15.3k
{
186
15.3k
  g_return_val_if_fail(FU_IS_USB_ENDPOINT(self), 0);
187
15.3k
  return (self->endpoint_descriptor.bEndpointAddress) & 0xf;
188
15.3k
}
189
190
/**
191
 * fu_usb_endpoint_get_direction:
192
 * @self: a #FuUsbEndpoint
193
 *
194
 * Gets the direction of the endpoint.
195
 *
196
 * Return value: The endpoint direction
197
 *
198
 * Since: 2.0.0
199
 **/
200
FuUsbDirection
201
fu_usb_endpoint_get_direction(FuUsbEndpoint *self)
202
0
{
203
0
  g_return_val_if_fail(FU_IS_USB_ENDPOINT(self), 0);
204
0
  return (self->endpoint_descriptor.bEndpointAddress & 0x80)
205
0
       ? FU_USB_DIRECTION_DEVICE_TO_HOST
206
0
       : FU_USB_DIRECTION_HOST_TO_DEVICE;
207
0
}
208
209
static gboolean
210
fu_usb_endpoint_parse(FuFirmware *firmware,
211
          FuInputStream *stream,
212
          FuFirmwareParseFlags flags,
213
          GError **error)
214
34.9k
{
215
34.9k
  FuUsbEndpoint *self = FU_USB_ENDPOINT(firmware);
216
34.9k
  g_autoptr(FuUsbEndpointHdr) st = NULL;
217
218
  /* FuUsbDescriptor */
219
34.9k
  if (!FU_FIRMWARE_CLASS(fu_usb_endpoint_parent_class)->parse(firmware, stream, flags, error))
220
0
    return FALSE;
221
222
  /* parse */
223
34.9k
  st = fu_usb_endpoint_hdr_parse_stream(stream, 0x0, error);
224
34.9k
  if (st == NULL)
225
41
    return FALSE;
226
34.8k
  self->endpoint_descriptor.bLength = fu_usb_endpoint_hdr_get_length(st);
227
34.8k
  self->endpoint_descriptor.bDescriptorType = fu_usb_endpoint_hdr_get_descriptor_type(st);
228
34.8k
  self->endpoint_descriptor.bEndpointAddress = fu_usb_endpoint_hdr_get_endpoint_address(st);
229
34.8k
  self->endpoint_descriptor.bmAttributes = fu_usb_endpoint_hdr_get_attributes(st);
230
34.8k
  self->endpoint_descriptor.wMaxPacketSize = fu_usb_endpoint_hdr_get_max_packet_size(st);
231
34.8k
  self->endpoint_descriptor.bInterval = fu_usb_endpoint_hdr_get_interval(st);
232
34.8k
  self->endpoint_descriptor.bRefresh = 0;
233
34.8k
  self->endpoint_descriptor.bSynchAddress = 0;
234
235
  /* success */
236
34.8k
  return TRUE;
237
34.9k
}
238
239
static void
240
fu_usb_endpoint_codec_iface_init(FwupdCodecInterface *iface)
241
1
{
242
1
  iface->add_json = fu_usb_endpoint_add_json;
243
1
  iface->from_json = fu_usb_endpoint_from_json;
244
1
}
245
246
static void
247
fu_usb_endpoint_init(FuUsbEndpoint *self)
248
34.9k
{
249
34.9k
}
250
251
static void
252
fu_usb_endpoint_class_init(FuUsbEndpointClass *klass)
253
1
{
254
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
255
1
  firmware_class->parse = fu_usb_endpoint_parse;
256
1
}
257
258
/**
259
 * fu_usb_endpoint_new:
260
 *
261
 * Return value: a new #FuUsbEndpoint object.
262
 *
263
 * Since: 2.0.0
264
 **/
265
FuUsbEndpoint *
266
fu_usb_endpoint_new(const struct libusb_endpoint_descriptor *endpoint_descriptor)
267
0
{
268
0
  FuUsbEndpoint *self = g_object_new(FU_TYPE_USB_ENDPOINT, NULL);
269
270
  /* copy the data */
271
0
  memcpy(&self->endpoint_descriptor, /* nocheck:blocked */
272
0
         endpoint_descriptor,
273
0
         sizeof(struct libusb_endpoint_descriptor));
274
0
  return FU_USB_ENDPOINT(self);
275
0
}