[usb_testutils] Endpoint removal and finalization
Defer configuration and enabling of endpoint zero until the
callback handlers have been registered, except for enabling
SETUP reception which is unique to this endpoint.
Change-Id: Id9e3bdc34e28804e5eeeb9431d69ba50ce4c45f2
Signed-off-by: Adrian Lees <a.lees@lowrisc.org>
diff --git a/sw/device/lib/testing/usb_testutils.c b/sw/device/lib/testing/usb_testutils.c
index e0605b6..4831f9b 100644
--- a/sw/device/lib/testing/usb_testutils.c
+++ b/sw/device/lib/testing/usb_testutils.c
@@ -77,6 +77,7 @@
if (ctx->out[ep].rx_callback) {
ctx->out[ep].rx_callback(ctx->out[ep].ep_ctx, packet_info, buffer);
} else {
+ // Note: this could happen following endpoint removal
TRC_S("USB: unexpected RX ");
TRC_I(endpoint, 8);
CHECK_DIF_OK(
@@ -214,7 +215,7 @@
}
void usb_testutils_endpoint_setup(
- usb_testutils_ctx_t *ctx, int ep,
+ usb_testutils_ctx_t *ctx, uint8_t ep,
usb_testutils_out_transfer_mode_t out_mode, void *ep_ctx,
void (*tx_done)(void *),
void (*rx)(void *, dif_usbdev_rx_packet_info_t, dif_usbdev_buffer_t),
@@ -226,6 +227,46 @@
usb_testutils_out_endpoint_setup(ctx, ep, out_mode, ep_ctx, rx, NULL);
}
+void usb_testutils_in_endpoint_remove(usb_testutils_ctx_t *ctx, uint8_t ep) {
+ // Disable IN traffic
+ dif_usbdev_endpoint_id_t endpoint = {
+ .number = ep,
+ .direction = USBDEV_ENDPOINT_DIR_IN,
+ };
+ CHECK_DIF_OK(
+ dif_usbdev_endpoint_enable(ctx->dev, endpoint, kDifToggleDisabled));
+
+ // Remove callback handlers
+ ctx->in[ep].tx_done_callback = NULL;
+ ctx->in[ep].flush = NULL;
+ ctx->in[ep].reset = NULL;
+}
+
+void usb_testutils_out_endpoint_remove(usb_testutils_ctx_t *ctx, uint8_t ep) {
+ // Disable OUT traffic
+ dif_usbdev_endpoint_id_t endpoint = {
+ .number = ep,
+ .direction = USBDEV_ENDPOINT_DIR_OUT,
+ };
+ CHECK_DIF_OK(
+ dif_usbdev_endpoint_enable(ctx->dev, endpoint, kDifToggleDisabled));
+
+ // Return the rest of the OUT endpoint configuration to its default state
+ CHECK_DIF_OK(dif_usbdev_endpoint_set_nak_out_enable(ctx->dev, endpoint.number,
+ kDifToggleDisabled));
+ CHECK_DIF_OK(dif_usbdev_endpoint_out_enable(ctx->dev, endpoint.number,
+ kDifToggleDisabled));
+
+ // Remove callback handlers
+ ctx->out[ep].rx_callback = NULL;
+ ctx->out[ep].reset = NULL;
+}
+
+void usb_testutils_endpoint_remove(usb_testutils_ctx_t *ctx, uint8_t ep) {
+ usb_testutils_in_endpoint_remove(ctx, ep);
+ usb_testutils_out_endpoint_remove(ctx, ep);
+}
+
void usb_testutils_init(usb_testutils_ctx_t *ctx, bool pinflip,
bool en_diff_rcvr, bool tx_use_d_se0) {
CHECK(ctx != NULL);
@@ -258,27 +299,24 @@
// All about polling...
CHECK_DIF_OK(dif_usbdev_irq_disable_all(ctx->dev, NULL));
- // Provide buffers for any reception
+ // Provide buffers for any packet reception
CHECK_DIF_OK(dif_usbdev_fill_available_fifo(ctx->dev, ctx->buffer_pool));
- dif_usbdev_endpoint_id_t endpoint = {
- .number = 0,
- .direction = 1,
- };
+ // Preemptively enable SETUP reception on endpoint zero for the
+ // Default Control Pipe; all other settings for that endpoint will be applied
+ // once the callback handlers are registered by a call to _endpoint_setup()
CHECK_DIF_OK(
- dif_usbdev_endpoint_enable(ctx->dev, endpoint, kDifToggleEnabled));
- CHECK_DIF_OK(
- dif_usbdev_endpoint_stall_enable(ctx->dev, endpoint, kDifToggleDisabled));
+ dif_usbdev_endpoint_setup_enable(ctx->dev, 0, kDifToggleEnabled));
+}
- endpoint.direction = 0;
- CHECK_DIF_OK(
- dif_usbdev_endpoint_enable(ctx->dev, endpoint, kDifToggleEnabled));
- CHECK_DIF_OK(
- dif_usbdev_endpoint_stall_enable(ctx->dev, endpoint, kDifToggleDisabled));
- CHECK_DIF_OK(dif_usbdev_endpoint_setup_enable(ctx->dev, endpoint.number,
- kDifToggleEnabled));
- CHECK_DIF_OK(dif_usbdev_endpoint_out_enable(ctx->dev, endpoint.number,
- kDifToggleEnabled));
+void usb_testutils_fin(usb_testutils_ctx_t *ctx) {
+ // Remove the endpoints in reverse order so that Endpoint Zero goes down last
+ for (int ep = USBDEV_NUM_ENDPOINTS - 1; ep >= 0; ep--) {
+ usb_testutils_endpoint_remove(ctx, ep);
+ }
+
+ // Disconnect from the bus
+ CHECK_DIF_OK(dif_usbdev_interface_enable(ctx->dev, kDifToggleDisabled));
}
// `extern` declarations to give the inline functions in the
diff --git a/sw/device/lib/testing/usb_testutils.h b/sw/device/lib/testing/usb_testutils.h
index 910d511..ee3cb0c 100644
--- a/sw/device/lib/testing/usb_testutils.h
+++ b/sw/device/lib/testing/usb_testutils.h
@@ -69,13 +69,6 @@
} out[USBDEV_NUM_ENDPOINTS];
};
-/**
- * Call regularly to poll the usbdev interface
- *
- * @param ctx usbdev context pointer
- */
-void usb_testutils_poll(usb_testutils_ctx_t *ctx);
-
typedef enum usb_testutils_out_transfer_mode {
/**
* The endpoint does not support OUT transactions.
@@ -128,7 +121,7 @@
void (*reset)(void *));
/**
- * Call to set up a pairt of IN and OUT endpoints.
+ * Call to set up a pair of IN and OUT endpoints.
*
* @param ctx usbdev context pointer
* @param ep endpoint number
@@ -140,7 +133,7 @@
* @param flush(void *ep_ctx) called every 16ms based USB host timebase
* @param reset(void *ep_ctx) called when an USB link reset is detected
*/
-void usb_testutils_endpoint_setup(usb_testutils_ctx_t *ctx, int ep,
+void usb_testutils_endpoint_setup(usb_testutils_ctx_t *ctx, uint8_t ep,
usb_testutils_out_transfer_mode_t out_mode,
void *ep_ctx, void (*tx_done)(void *),
void (*rx)(void *,
@@ -149,6 +142,30 @@
void (*flush)(void *), void (*reset)(void *));
/**
+ * Remove an IN endpoint.
+ *
+ * @param ctx usbdev context pointer
+ * @param ep endpoint number
+ */
+void usb_testutils_in_endpoint_remove(usb_testutils_ctx_t *ctx, uint8_t ep);
+
+/**
+ * Remove an OUT endpoint.
+ *
+ * @param ctx usbdev context pointer
+ * @param ep endpoint number
+ */
+void usb_testutils_out_endpoint_remove(usb_testutils_ctx_t *ctx, uint8_t ep);
+
+/**
+ * Remove a pair of IN and OUT endpoints
+ *
+ * @param ctx usbdev context pointer
+ * @param ep endpoint number
+ */
+void usb_testutils_endpoint_remove(usb_testutils_ctx_t *ctx, uint8_t ep);
+
+/**
* Returns an indication of whether an endpoint is currently halted because
* of the occurrence of an error.
*
@@ -176,4 +193,18 @@
void usb_testutils_init(usb_testutils_ctx_t *ctx, bool pinflip,
bool en_diff_rcvr, bool tx_use_d_se0);
+/**
+ * Call regularly to poll the usbdev interface
+ *
+ * @param ctx usbdev context pointer
+ */
+void usb_testutils_poll(usb_testutils_ctx_t *ctx);
+
+/**
+ * Finalize the usbdev interface
+ *
+ * @param ctx initialized usbdev context pointer
+ */
+void usb_testutils_fin(usb_testutils_ctx_t *ctx);
+
#endif // OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_H_