/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 | } |