Skip to content

Commit 20ef346

Browse files
committed
Implement V2 transport interface, fallbacks, and migrate hostcmd
1 parent 0d24159 commit 20ef346

4 files changed

Lines changed: 235 additions & 36 deletions

File tree

protocol/host_cmd.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -224,24 +224,22 @@ libhoth_error libhoth_hostcmd_exec_v2(struct libhoth_device* dev,
224224
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_POSIX,
225225
-status);
226226
}
227-
status = libhoth_send_request(dev, &req, sizeof(req.hdr) + req_payload_size);
228-
if (status != LIBHOTH_OK) {
229-
fprintf(stderr, "libhoth_send_request() failed: %d\n", status);
230-
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
231-
status);
227+
libhoth_error err = libhoth_send_request_v2(dev, &req, sizeof(req.hdr) + req_payload_size);
228+
if (err != HOTH_SUCCESS) {
229+
fprintf(stderr, "libhoth_send_request_v2() failed: 0x%016llx\n", (unsigned long long)err);
230+
return err;
232231
}
233232
struct {
234233
struct hoth_host_response hdr;
235234
uint8_t
236235
payload_buf[LIBHOTH_MAILBOX_SIZE - sizeof(struct hoth_host_response)];
237236
} resp;
238237
size_t resp_size = 0;
239-
status = libhoth_receive_response(dev, &resp, sizeof(resp), &resp_size,
238+
err = libhoth_receive_response_v2(dev, &resp, sizeof(resp), &resp_size,
240239
HOTH_CMD_TIMEOUT_MS_DEFAULT);
241-
if (status != LIBHOTH_OK) {
242-
fprintf(stderr, "libhoth_receive_response() failed: %d\n", status);
243-
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
244-
status);
240+
if (err != HOTH_SUCCESS) {
241+
fprintf(stderr, "libhoth_receive_response_v2() failed: 0x%016llx\n", (unsigned long long)err);
242+
return err;
245243
}
246244
status = validate_ec_response_header(&resp.hdr, resp.payload_buf, resp_size);
247245
if (status != 0) {

transports/BUILD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ cc_library(
66
name = "libhoth_device",
77
srcs = ["libhoth_device.c"],
88
hdrs = ["libhoth_device.h"],
9+
deps = [
10+
"//protocol:libhoth_status",
11+
],
912
)
1013

1114
cc_library(

transports/libhoth_device.c

Lines changed: 191 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,45 @@
2121

2222
#include "libhoth_device.h"
2323

24+
static libhoth_error libhoth_error_from_legacy(uint16_t context, int status) {
25+
if (status == 0) {
26+
return HOTH_SUCCESS;
27+
}
28+
if (status < 0) {
29+
return LIBHOTH_ERR_CONSTRUCT(context, HOTH_HOST_SPACE_POSIX, -status);
30+
}
31+
return LIBHOTH_ERR_CONSTRUCT(context, HOTH_HOST_SPACE_LIBHOTH, (uint32_t)status);
32+
}
33+
34+
static int libhoth_error_to_legacy(libhoth_error err) {
35+
if (err == HOTH_SUCCESS) {
36+
return 0;
37+
}
38+
uint32_t space = LIBHOTH_ERR_GET_SPACE(err);
39+
uint32_t code = LIBHOTH_ERR_GET_CODE(err);
40+
41+
if (space == HOTH_HOST_SPACE_LIBHOTH) {
42+
return (int)code;
43+
}
44+
if (space == HOTH_HOST_SPACE_POSIX || space == HOTH_HOST_SPACE_LIBUSB) {
45+
return -(int)code;
46+
}
47+
return LIBHOTH_ERR_FAIL;
48+
}
49+
2450
int libhoth_send_request(struct libhoth_device* dev, const void* request,
2551
size_t request_size) {
2652
if (dev == NULL) {
2753
return LIBHOTH_ERR_INVALID_PARAMETER;
2854
}
29-
return dev->send(dev, request, request_size);
55+
if (dev->send != NULL) {
56+
return dev->send(dev, request, request_size);
57+
}
58+
if (dev->send_v2 != NULL) {
59+
libhoth_error err = dev->send_v2(dev, request, request_size);
60+
return libhoth_error_to_legacy(err);
61+
}
62+
return LIBHOTH_ERR_FAIL;
3063
}
3164

3265
int libhoth_receive_response(struct libhoth_device* dev, void* response,
@@ -35,36 +68,150 @@ int libhoth_receive_response(struct libhoth_device* dev, void* response,
3568
if (dev == NULL) {
3669
return LIBHOTH_ERR_INVALID_PARAMETER;
3770
}
38-
return dev->receive(dev, response, max_response_size, actual_size,
39-
timeout_ms);
71+
if (dev->receive != NULL) {
72+
return dev->receive(dev, response, max_response_size, actual_size,
73+
timeout_ms);
74+
}
75+
if (dev->receive_v2 != NULL) {
76+
libhoth_error err = dev->receive_v2(dev, response, max_response_size,
77+
actual_size, timeout_ms);
78+
return libhoth_error_to_legacy(err);
79+
}
80+
return LIBHOTH_ERR_FAIL;
4081
}
4182

42-
int libhoth_device_reconnect(struct libhoth_device* dev) {
83+
libhoth_error libhoth_send_request_v2(struct libhoth_device* dev,
84+
const void* request,
85+
size_t request_size) {
4386
if (dev == NULL) {
44-
return LIBHOTH_ERR_INVALID_PARAMETER;
87+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
88+
LIBHOTH_ERR_INVALID_PARAMETER);
89+
}
90+
if (dev->send_v2 != NULL) {
91+
return dev->send_v2(dev, request, request_size);
92+
}
93+
if (dev->send != NULL) {
94+
int status = dev->send(dev, request, request_size);
95+
return libhoth_error_from_legacy(HOTH_CTX_NONE, status);
4596
}
97+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
98+
LIBHOTH_ERR_FAIL);
99+
}
46100

47-
if (dev->reconnect == NULL) {
48-
return LIBHOTH_ERR_UNSUPPORTED_VERSION;
101+
libhoth_error libhoth_receive_response_v2(struct libhoth_device* dev,
102+
void* response,
103+
size_t max_response_size,
104+
size_t* actual_size,
105+
int timeout_ms) {
106+
if (dev == NULL) {
107+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
108+
LIBHOTH_ERR_INVALID_PARAMETER);
49109
}
110+
if (dev->receive_v2 != NULL) {
111+
return dev->receive_v2(dev, response, max_response_size, actual_size,
112+
timeout_ms);
113+
}
114+
if (dev->receive != NULL) {
115+
int status = dev->receive(dev, response, max_response_size, actual_size,
116+
timeout_ms);
117+
return libhoth_error_from_legacy(HOTH_CTX_NONE, status);
118+
}
119+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
120+
LIBHOTH_ERR_FAIL);
121+
}
50122

51-
return dev->reconnect(dev);
123+
int libhoth_device_reconnect(struct libhoth_device* dev) {
124+
if (dev == NULL) {
125+
return LIBHOTH_ERR_INVALID_PARAMETER;
126+
}
127+
if (dev->reconnect != NULL) {
128+
return dev->reconnect(dev);
129+
}
130+
if (dev->reconnect_v2 != NULL) {
131+
libhoth_error err = dev->reconnect_v2(dev);
132+
return libhoth_error_to_legacy(err);
133+
}
134+
return LIBHOTH_ERR_UNSUPPORTED_VERSION;
52135
}
53136

54137
int libhoth_device_close(struct libhoth_device* dev) {
55138
if (dev == NULL) {
56139
return LIBHOTH_ERR_INVALID_PARAMETER;
57140
}
58-
59-
int status = dev->close(dev);
141+
int status = 0;
142+
if (dev->close != NULL) {
143+
status = dev->close(dev);
144+
} else if (dev->close_v2 != NULL) {
145+
libhoth_error err = dev->close_v2(dev);
146+
status = libhoth_error_to_legacy(err);
147+
} else {
148+
status = LIBHOTH_ERR_FAIL;
149+
}
60150
free(dev);
61151
return status;
62152
}
63153

154+
libhoth_error libhoth_device_reconnect_v2(struct libhoth_device* dev) {
155+
if (dev == NULL) {
156+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
157+
LIBHOTH_ERR_INVALID_PARAMETER);
158+
}
159+
if (dev->reconnect_v2 != NULL) {
160+
return dev->reconnect_v2(dev);
161+
}
162+
if (dev->reconnect != NULL) {
163+
int status = dev->reconnect(dev);
164+
return libhoth_error_from_legacy(HOTH_CTX_NONE, status);
165+
}
166+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
167+
LIBHOTH_ERR_UNSUPPORTED_VERSION);
168+
}
169+
170+
libhoth_error libhoth_device_close_v2(struct libhoth_device* dev) {
171+
if (dev == NULL) {
172+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
173+
LIBHOTH_ERR_INVALID_PARAMETER);
174+
}
175+
libhoth_error err = HOTH_SUCCESS;
176+
if (dev->close_v2 != NULL) {
177+
err = dev->close_v2(dev);
178+
} else if (dev->close != NULL) {
179+
int status = dev->close(dev);
180+
err = libhoth_error_from_legacy(HOTH_CTX_NONE, status);
181+
}
182+
free(dev);
183+
return err;
184+
}
185+
64186
int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) {
187+
if (dev == NULL) {
188+
return LIBHOTH_ERR_INVALID_PARAMETER;
189+
}
190+
libhoth_error err = libhoth_claim_device_v2(dev, timeout_us);
191+
return libhoth_error_to_legacy(err);
192+
}
193+
194+
int libhoth_release_device(struct libhoth_device* dev) {
195+
if (dev == NULL) {
196+
return LIBHOTH_ERR_INVALID_PARAMETER;
197+
}
198+
if (dev->release != NULL) {
199+
return dev->release(dev);
200+
}
201+
if (dev->release_v2 != NULL) {
202+
libhoth_error err = dev->release_v2(dev);
203+
return libhoth_error_to_legacy(err);
204+
}
205+
return LIBHOTH_ERR_FAIL;
206+
}
207+
208+
libhoth_error libhoth_claim_device_v2(struct libhoth_device* dev, uint32_t timeout_us) {
209+
if (dev == NULL) {
210+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
211+
LIBHOTH_ERR_INVALID_PARAMETER);
212+
}
213+
65214
enum {
66-
// The maximum time to sleep per attempt.
67-
// Limited by `usleep()` to <1 second.
68215
MAX_SINGLE_SLEEP_US = 1000 * 1000 - 1,
69216
BACKOFF_FACTOR = 2,
70217
INITIAL_WAIT_US = 10 * 1000,
@@ -74,43 +221,61 @@ int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) {
74221
uint32_t total_waiting_us = 0;
75222

76223
while (true) {
77-
int status = dev->claim(dev);
224+
libhoth_error err = HOTH_SUCCESS;
225+
if (dev->claim_v2 != NULL) {
226+
err = dev->claim_v2(dev);
227+
} else if (dev->claim != NULL) {
228+
int status = dev->claim(dev);
229+
err = libhoth_error_from_legacy(HOTH_CTX_NONE, status);
230+
} else {
231+
err = LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
232+
LIBHOTH_ERR_FAIL);
233+
}
78234

79-
if (status != LIBHOTH_ERR_INTERFACE_BUSY) {
80-
// We either claimed the device or encountered an unexpected error. Let
81-
// the caller know.
82-
return status;
235+
uint32_t space = LIBHOTH_ERR_GET_SPACE(err);
236+
uint32_t code = LIBHOTH_ERR_GET_CODE(err);
237+
if (err == HOTH_SUCCESS || space != HOTH_HOST_SPACE_LIBHOTH || code != LIBHOTH_ERR_INTERFACE_BUSY) {
238+
return err;
83239
}
84240

85241
if (total_waiting_us >= timeout_us) {
86-
// We've exhausted our waiting budget. We couldn't claim the device
87-
// within the configured timeout.
88242
fprintf(stderr, "libhoth: timed out claiming transport after %dus\n",
89243
timeout_us);
90-
return LIBHOTH_ERR_INTERFACE_BUSY;
244+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
245+
LIBHOTH_ERR_INTERFACE_BUSY);
91246
}
92247

93248
usleep(wait_us);
94249

95250
if (total_waiting_us <= UINT32_MAX - wait_us) {
96251
total_waiting_us += wait_us;
97252
} else {
98-
// Saturate at integer upper bound to prevent overflow.
99253
total_waiting_us = UINT32_MAX;
100254
}
101255

102256
if (wait_us <= MAX_SINGLE_SLEEP_US / BACKOFF_FACTOR) {
103257
wait_us *= BACKOFF_FACTOR;
104258
} else {
105-
// Saturate at the `usleep()` max sleep bound.
106259
wait_us = MAX_SINGLE_SLEEP_US;
107260
}
108261
}
109262

110-
// Unreachable
111-
return LIBHOTH_ERR_FAIL;
263+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
264+
LIBHOTH_ERR_FAIL);
112265
}
113266

114-
int libhoth_release_device(struct libhoth_device* dev) {
115-
return dev->release(dev);
267+
libhoth_error libhoth_release_device_v2(struct libhoth_device* dev) {
268+
if (dev == NULL) {
269+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
270+
LIBHOTH_ERR_INVALID_PARAMETER);
271+
}
272+
if (dev->release_v2 != NULL) {
273+
return dev->release_v2(dev);
274+
}
275+
if (dev->release != NULL) {
276+
int status = dev->release(dev);
277+
return libhoth_error_from_legacy(HOTH_CTX_NONE, status);
278+
}
279+
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH,
280+
LIBHOTH_ERR_FAIL);
116281
}

transports/libhoth_device.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <stddef.h>
1919
#include <stdint.h>
2020

21+
#include "protocol/status.h"
22+
2123
#ifdef __cplusplus
2224
extern "C" {
2325
#endif
@@ -53,6 +55,17 @@ struct libhoth_device {
5355
int (*reconnect)(struct libhoth_device* dev);
5456

5557
void* user_ctx;
58+
59+
// --- New Interface (V2) ---
60+
libhoth_error (*send_v2)(struct libhoth_device* dev, const void* request,
61+
size_t request_size);
62+
libhoth_error (*receive_v2)(struct libhoth_device* dev, void* response,
63+
size_t max_response_size, size_t* actual_size,
64+
int timeout_ms);
65+
libhoth_error (*close_v2)(struct libhoth_device* dev);
66+
libhoth_error (*claim_v2)(struct libhoth_device* dev);
67+
libhoth_error (*release_v2)(struct libhoth_device* dev);
68+
libhoth_error (*reconnect_v2)(struct libhoth_device* dev);
5669
};
5770

5871
// Request is a buffer containing the EC request header and trailing payload.
@@ -84,6 +97,26 @@ int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us);
8497

8598
int libhoth_release_device(struct libhoth_device* dev);
8699

100+
// --- New V2 Helper Functions ---
101+
libhoth_error libhoth_send_request_v2(struct libhoth_device* dev,
102+
const void* request,
103+
size_t request_size);
104+
105+
libhoth_error libhoth_receive_response_v2(struct libhoth_device* dev,
106+
void* response,
107+
size_t max_response_size,
108+
size_t* actual_size,
109+
int timeout_ms);
110+
111+
libhoth_error libhoth_device_reconnect_v2(struct libhoth_device* dev);
112+
113+
libhoth_error libhoth_device_close_v2(struct libhoth_device* dev);
114+
115+
libhoth_error libhoth_claim_device_v2(struct libhoth_device* dev,
116+
uint32_t timeout_us);
117+
118+
libhoth_error libhoth_release_device_v2(struct libhoth_device* dev);
119+
87120
#ifdef __cplusplus
88121
}
89122
#endif

0 commit comments

Comments
 (0)