/* * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include "usbh_internal.h" #include "usbh_device.h" #include LOG_MODULE_REGISTER(uhs, CONFIG_USBH_LOG_LEVEL); static K_KERNEL_STACK_DEFINE(usbh_stack, CONFIG_USBH_STACK_SIZE); static struct k_thread usbh_thread_data; K_MSGQ_DEFINE(usbh_msgq, sizeof(struct uhc_event), CONFIG_USBH_MAX_UHC_MSG, sizeof(uint32_t)); static int usbh_event_carrier(const struct device *dev, const struct uhc_event *const event) { return k_msgq_put(&usbh_msgq, event, K_NO_WAIT); } static int discard_ep_request(struct usbh_contex *const ctx, struct uhc_transfer *const xfer) { const struct device *dev = ctx->dev; if (xfer->buf) { LOG_HEXDUMP_INF(xfer->buf->data, xfer->buf->len, "buf"); uhc_xfer_buf_free(dev, xfer->buf); } return uhc_xfer_free(dev, xfer); } static ALWAYS_INLINE int usbh_event_handler(struct usbh_contex *const ctx, struct uhc_event *const event) { int ret = 0; if (event->type == UHC_EVT_EP_REQUEST) { struct usb_device *const udev = event->xfer->udev; usbh_udev_cb_t cb = event->xfer->cb; if (event->xfer->cb) { ret = cb(udev, event->xfer); } else { ret = discard_ep_request(ctx, event->xfer); } return ret; } switch (event->type) { case UHC_EVT_DEV_CONNECTED_LS: case UHC_EVT_DEV_CONNECTED_FS: case UHC_EVT_DEV_CONNECTED_HS: LOG_DBG("Device connected event"); break; case UHC_EVT_DEV_REMOVED: LOG_DBG("Device removed event"); break; case UHC_EVT_RESETED: LOG_DBG("Bus reset"); break; case UHC_EVT_SUSPENDED: LOG_DBG("Bus suspended"); break; case UHC_EVT_RESUMED: LOG_DBG("Bus resumed"); break; case UHC_EVT_RWUP: LOG_DBG("RWUP event"); break; case UHC_EVT_ERROR: LOG_DBG("Error event %d", event->status); break; default: break; }; return ret; } static void usbh_thread(void *p1, void *p2, void *p3) { ARG_UNUSED(p1); ARG_UNUSED(p2); ARG_UNUSED(p3); struct uhc_event event; while (true) { k_msgq_get(&usbh_msgq, &event, K_FOREVER); STRUCT_SECTION_FOREACH(usbh_contex, uhs_ctx) { if (uhs_ctx->dev == event.dev) { usbh_event_handler(uhs_ctx, &event); } } } } int usbh_init_device_intl(struct usbh_contex *const uhs_ctx) { int ret; ret = uhc_init(uhs_ctx->dev, usbh_event_carrier); if (ret != 0) { LOG_ERR("Failed to init device driver"); return ret; } STRUCT_SECTION_FOREACH(usbh_class_data, cdata) { /* * For now, we have not implemented any class drivers, * so just keep it as placeholder. */ break; } return 0; } static int uhs_pre_init(void) { k_thread_create(&usbh_thread_data, usbh_stack, K_KERNEL_STACK_SIZEOF(usbh_stack), usbh_thread, NULL, NULL, NULL, K_PRIO_COOP(9), 0, K_NO_WAIT); k_thread_name_set(&usbh_thread_data, "usbh"); return 0; } SYS_INIT(uhs_pre_init, POST_KERNEL, CONFIG_USBH_INIT_PRIO);