[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_