diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index 4527f417483ee..7220ac16b77cb 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -101,24 +101,33 @@ struct usbd_str_desc_data { * Example callback code fragment: * * @code{.c} - * static int foo_to_host_cb(const struct usbd_context *const ctx, - * const struct usb_setup_packet *const setup, - * struct net_buf *const buf) + * static net_buf *foo_to_host_cb(const struct usbd_context *const ctx, + * const struct usb_setup_packet *const setup) * { * if (setup->wIndex == WEBUSB_REQ_GET_URL) { + * struct net_buf *buf; + * uint16_t len; * uint8_t index = USB_GET_DESCRIPTOR_INDEX(setup->wValue); * * if (index != SAMPLE_WEBUSB_LANDING_PAGE) { - * return -ENOTSUP; + * errno = -ENOTSUP; + * return NULL; * } * - * net_buf_add_mem(buf, &webusb_origin_url, - * MIN(net_buf_tailroom(buf), sizeof(webusb_origin_url))); + * len = MIN(setup->wLength, sizeof(webusb_origin_url)); + * buf = usbd_ep_ctrl_data_in_alloc(ctx, len); + * if (buf == NULL) { + * errno = -ENOMEM; + * return NULL; + * } + * + * net_buf_add_mem(buf, &webusb_origin_url, len); * - * return 0; + * return buf; * } * - * return -ENOTSUP; + * errno = -ENOTSUP; + * return NULL; * } * @endcode */ @@ -128,9 +137,8 @@ struct usbd_vreq_node { /** Vendor code (bRequest value) */ const uint8_t code; /** Vendor request callback for device-to-host direction */ - int (*to_host)(const struct usbd_context *const ctx, - const struct usb_setup_packet *const setup, - struct net_buf *const buf); + struct net_buf *(*to_host)(const struct usbd_context *const ctx, + const struct usb_setup_packet *const setup); /** Vendor request callback for host-to-device direction */ int (*to_dev)(const struct usbd_context *const ctx, const struct usb_setup_packet *const setup, @@ -342,9 +350,8 @@ struct usbd_class_api { const struct net_buf *const buf); /** USB control request handler to host */ - int (*control_to_host)(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf); + struct net_buf *(*control_to_host)(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup); /** Endpoint request completion event handler */ int (*request)(struct usbd_class_data *const c_data, diff --git a/samples/subsys/dap/src/msosv2.h b/samples/subsys/dap/src/msosv2.h index c00d614c3508e..684e6f51ab333 100644 --- a/samples/subsys/dap/src/msosv2.h +++ b/samples/subsys/dap/src/msosv2.h @@ -113,23 +113,31 @@ struct bos_msosv2_descriptor bos_msosv2_desc = { }, }; -static int msosv2_to_host_cb(const struct usbd_context *const ctx, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *msosv2_to_host_cb(const struct usbd_context *const ctx, + const struct usb_setup_packet *const setup) { LOG_INF("Vendor callback to host"); if (setup->bRequest == SAMPLE_MSOS2_VENDOR_CODE && setup->wIndex == MS_OS_20_DESCRIPTOR_INDEX) { + struct net_buf *buf; + uint16_t len = MIN(setup->wLength, sizeof(msosv2_desc)); + LOG_INF("Get MS OS 2.0 Descriptor Set"); - net_buf_add_mem(buf, &msosv2_desc, - MIN(net_buf_tailroom(buf), sizeof(msosv2_desc))); + buf = usbd_ep_ctrl_data_in_alloc(ctx, len); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; + } + + net_buf_add_mem(buf, &msosv2_desc, len); - return 0; + return buf; } - return -ENOTSUP; + errno = -ENOTSUP; + return NULL; } USBD_DESC_BOS_VREQ_DEFINE(bos_vreq_msosv2, sizeof(bos_msosv2_desc), &bos_msosv2_desc, diff --git a/samples/subsys/dap/src/webusb.h b/samples/subsys/dap/src/webusb.h index c1cda8924ec12..f632e514d508b 100644 --- a/samples/subsys/dap/src/webusb.h +++ b/samples/subsys/dap/src/webusb.h @@ -63,27 +63,36 @@ static const uint8_t webusb_origin_url[] = { 'o', 'r', 'g', '/', }; -static int webusb_to_host_cb(const struct usbd_context *const ctx, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *webusb_to_host_cb(const struct usbd_context *const ctx, + const struct usb_setup_packet *const setup) { LOG_INF("Vendor callback to host"); if (setup->wIndex == WEBUSB_REQ_GET_URL) { + struct net_buf *buf; + uint16_t len; uint8_t index = USB_GET_DESCRIPTOR_INDEX(setup->wValue); if (index != SAMPLE_WEBUSB_LANDING_PAGE) { - return -ENOTSUP; + errno = -ENOTSUP; + return NULL; + } + + len = MIN(setup->wLength, sizeof(webusb_origin_url)); + buf = usbd_ep_ctrl_data_in_alloc(ctx, len); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; } LOG_INF("Get URL request, index %u", index); - net_buf_add_mem(buf, &webusb_origin_url, - MIN(net_buf_tailroom(buf), sizeof(webusb_origin_url))); + net_buf_add_mem(buf, &webusb_origin_url, len); - return 0; + return buf; } - return -ENOTSUP; + errno = -ENOTSUP; + return NULL; } USBD_DESC_BOS_VREQ_DEFINE(bos_vreq_webusb, sizeof(bos_cap_webusb), &bos_cap_webusb, diff --git a/samples/subsys/usb/webusb/src/msosv2.h b/samples/subsys/usb/webusb/src/msosv2.h index 88fc592737fa4..a00a3543fdb77 100644 --- a/samples/subsys/usb/webusb/src/msosv2.h +++ b/samples/subsys/usb/webusb/src/msosv2.h @@ -113,23 +113,32 @@ struct bos_msosv2_descriptor bos_msosv2_desc = { }, }; -static int msosv2_to_host_cb(const struct usbd_context *const ctx, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *msosv2_to_host_cb(const struct usbd_context *const ctx, + const struct usb_setup_packet *const setup) { LOG_INF("Vendor callback to host"); if (setup->bRequest == SAMPLE_MSOS2_VENDOR_CODE && setup->wIndex == MS_OS_20_DESCRIPTOR_INDEX) { + struct net_buf *buf; + uint16_t len; + LOG_INF("Get MS OS 2.0 Descriptor Set"); - net_buf_add_mem(buf, &msosv2_desc, - MIN(net_buf_tailroom(buf), sizeof(msosv2_desc))); + len = MIN(setup->wLength, sizeof(msosv2_desc)); + buf = usbd_ep_ctrl_data_in_alloc(ctx, len); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; + } + + net_buf_add_mem(buf, &msosv2_desc, len); - return 0; + return buf; } - return -ENOTSUP; + errno = -ENOTSUP; + return NULL; } USBD_DESC_BOS_VREQ_DEFINE(bos_vreq_msosv2, sizeof(bos_msosv2_desc), &bos_msosv2_desc, diff --git a/samples/subsys/usb/webusb/src/webusb.h b/samples/subsys/usb/webusb/src/webusb.h index 329626d4587b6..1c9d388b2f98e 100644 --- a/samples/subsys/usb/webusb/src/webusb.h +++ b/samples/subsys/usb/webusb/src/webusb.h @@ -61,27 +61,36 @@ static const uint8_t webusb_origin_url[] = { 'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't', ':', '8', '0', '0', '0' }; -static int webusb_to_host_cb(const struct usbd_context *const ctx, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *webusb_to_host_cb(const struct usbd_context *const ctx, + const struct usb_setup_packet *const setup) { LOG_INF("Vendor callback to host"); if (setup->wIndex == WEBUSB_REQ_GET_URL) { + struct net_buf *buf; + uint16_t len; uint8_t index = USB_GET_DESCRIPTOR_INDEX(setup->wValue); if (index != SAMPLE_WEBUSB_LANDING_PAGE) { - return -ENOTSUP; + errno = -ENOTSUP; + return NULL; + } + + len = MIN(setup->wLength, sizeof(webusb_origin_url)); + buf = usbd_ep_ctrl_data_in_alloc(ctx, len); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; } LOG_INF("Get URL request, index %u", index); - net_buf_add_mem(buf, &webusb_origin_url, - MIN(net_buf_tailroom(buf), sizeof(webusb_origin_url))); + net_buf_add_mem(buf, &webusb_origin_url, len); - return 0; + return buf; } - return -ENOTSUP; + errno = -ENOTSUP; + return NULL; } USBD_DESC_BOS_VREQ_DEFINE(bos_vreq_webusb, sizeof(bos_cap_webusb), &bos_cap_webusb, diff --git a/subsys/usb/device_next/class/loopback.c b/subsys/usb/device_next/class/loopback.c index 911a3f060b632..9fa27db49d71d 100644 --- a/subsys/usb/device_next/class/loopback.c +++ b/subsys/usb/device_next/class/loopback.c @@ -202,29 +202,35 @@ static void lb_update(struct usbd_class_data *c_data, c_data, iface, alternate); } -static int lb_control_to_host(struct usbd_class_data *c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *lb_control_to_host(struct usbd_class_data *c_data, + const struct usb_setup_packet *const setup) { if (setup->RequestType.recipient != USB_REQTYPE_RECIPIENT_DEVICE) { errno = -ENOTSUP; - return 0; + return NULL; } if (setup->bRequest == LB_VENDOR_REQ_IN) { - net_buf_add_mem(buf, lb_buf, - MIN(sizeof(lb_buf), setup->wLength)); + struct net_buf *buf; + uint16_t len = MIN(sizeof(lb_buf), setup->wLength); + + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), len); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; + } - LOG_WRN("Device-to-Host, wLength %u | %zu", setup->wLength, - MIN(sizeof(lb_buf), setup->wLength)); + net_buf_add_mem(buf, lb_buf, len); - return 0; + LOG_WRN("Device-to-Host, wLength %u | %zu", setup->wLength, len); + + return buf; } LOG_ERR("Class request 0x%x not supported", setup->bRequest); errno = -ENOTSUP; - return 0; + return NULL; } static int lb_control_to_dev(struct usbd_class_data *c_data, diff --git a/subsys/usb/device_next/class/usbd_cdc_acm.c b/subsys/usb/device_next/class/usbd_cdc_acm.c index cff61406d68c8..dd6afef74f62c 100644 --- a/subsys/usb/device_next/class/usbd_cdc_acm.c +++ b/subsys/usb/device_next/class/usbd_cdc_acm.c @@ -484,31 +484,33 @@ static void cdc_acm_update_linestate(struct cdc_acm_uart_data *const data) } } -static int usbd_cdc_acm_cth(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *usbd_cdc_acm_cth(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { const struct device *dev = usbd_class_get_private(c_data); struct cdc_acm_uart_data *data = dev->data; + struct net_buf *buf; size_t min_len; if (setup->bRequest == GET_LINE_CODING) { + min_len = MIN(sizeof(data->line_coding), setup->wLength); + + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), min_len); if (buf == NULL) { errno = -ENOMEM; - return 0; + return NULL; } - min_len = MIN(sizeof(data->line_coding), setup->wLength); net_buf_add_mem(buf, &data->line_coding, min_len); - return 0; + return buf; } LOG_DBG("bmRequestType 0x%02x bRequest 0x%02x unsupported", setup->bmRequestType, setup->bRequest); errno = -ENOTSUP; - return 0; + return NULL; } static int usbd_cdc_acm_ctd(struct usbd_class_data *const c_data, diff --git a/subsys/usb/device_next/class/usbd_cdc_ncm.c b/subsys/usb/device_next/class/usbd_cdc_ncm.c index 7bd04a42b068c..86b525db50772 100644 --- a/subsys/usb/device_next/class/usbd_cdc_ncm.c +++ b/subsys/usb/device_next/class/usbd_cdc_ncm.c @@ -918,9 +918,25 @@ static int usbd_cdc_ncm_ctd(struct usbd_class_data *const c_data, return 0; } -static int usbd_cdc_ncm_cth(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *cdc_ncm_cth_response(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup, + const void *data, uint16_t data_len) +{ + struct net_buf *buf; + uint16_t len = MIN(setup->wLength, data_len); + + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), len); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; + } + + net_buf_add_mem(buf, data, len); + return buf; +} + +static struct net_buf *usbd_cdc_ncm_cth(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { LOG_DBG("%d: %d %d %d %d", setup->RequestType.type, setup->bRequest, setup->wLength, setup->wIndex, setup->wValue); @@ -948,8 +964,7 @@ static int usbd_cdc_ncm_cth(struct usbd_class_data *const c_data, }; LOG_DBG("GET_NTB_PARAMETERS"); - net_buf_add_mem(buf, &ntb_params, sizeof(ntb_params)); - break; + return cdc_ncm_cth_response(c_data, setup, &ntb_params, sizeof(ntb_params)); } case GET_NTB_INPUT_SIZE: { @@ -960,8 +975,7 @@ static int usbd_cdc_ncm_cth(struct usbd_class_data *const c_data, }; LOG_DBG("GET_NTB_INPUT_SIZE"); - net_buf_add_mem(buf, &input_size, sizeof(input_size)); - break; + return cdc_ncm_cth_response(c_data, setup, &input_size, sizeof(input_size)); } default: @@ -971,7 +985,7 @@ static int usbd_cdc_ncm_cth(struct usbd_class_data *const c_data, } out: - return 0; + return NULL; } static int usbd_cdc_ncm_init(struct usbd_class_data *const c_data) diff --git a/subsys/usb/device_next/class/usbd_dfu.c b/subsys/usb/device_next/class/usbd_dfu.c index de9e924b9b520..d40c282642fe5 100644 --- a/subsys/usb/device_next/class/usbd_dfu.c +++ b/subsys/usb/device_next/class/usbd_dfu.c @@ -516,16 +516,22 @@ static int dfu_set_next_state(struct usbd_class_data *const c_data, /* Run-Time mode instance implementation, for instance "dfu_runtime" */ -static int handle_get_status(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *handle_get_status(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { struct usbd_dfu_data *data = usbd_class_get_private(c_data); - size_t len = MIN(setup->wLength, net_buf_tailroom(buf)); + struct net_buf *buf; const size_t getstatus_len = 6; - if (len != getstatus_len) { - return -ENOTSUP; + if (setup->wLength != getstatus_len) { + errno = -ENOTSUP; + return NULL; + } + + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), getstatus_len); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; } /* @@ -538,41 +544,48 @@ static int handle_get_status(struct usbd_class_data *const c_data, net_buf_add_u8(buf, data->state); net_buf_add_u8(buf, 0); - return 0; + return buf; } -static int handle_get_state(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *handle_get_state(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { struct usbd_dfu_data *data = usbd_class_get_private(c_data); - size_t len = MIN(setup->wLength, net_buf_tailroom(buf)); + struct net_buf *buf; const size_t getstate_len = 1; - if (len != getstate_len) { - return -ENOTSUP; + if (setup->wLength != getstate_len) { + errno = -ENOTSUP; + return NULL; + } + + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), getstate_len); + + if (buf == NULL) { + errno = -ENOMEM; + return NULL; } net_buf_add_u8(buf, data->state); - return 0; + return buf; } -static int runtime_mode_control_to_host(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *runtime_mode_control_to_host(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { struct usbd_dfu_data *data = usbd_class_get_private(c_data); + struct net_buf *buf = NULL; errno = dfu_set_next_state(c_data, setup); if (errno == 0) { switch (setup->bRequest) { case USB_DFU_REQ_GETSTATUS: - errno = handle_get_status(c_data, setup, buf); + buf = handle_get_status(c_data, setup); break; case USB_DFU_REQ_GETSTATE: - errno = handle_get_state(c_data, setup, buf); + buf = handle_get_state(c_data, setup); break; default: break; @@ -581,7 +594,7 @@ static int runtime_mode_control_to_host(struct usbd_class_data *const c_data, data->state = data->next; - return 0; + return buf; } static int runtime_mode_control_to_dev(struct usbd_class_data *const c_data, @@ -637,15 +650,26 @@ USBD_DEFINE_CLASS(dfu_runtime, &runtime_mode_api, &dfu_data, NULL); /* DFU mode instance implementation, for instance "dfu_dfu" */ -static int handle_upload(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *handle_upload(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { struct usbd_dfu_data *data = usbd_class_get_private(c_data); - uint16_t size = MIN(setup->wLength, net_buf_tailroom(buf)); + uint16_t size; struct usbd_dfu_image *const image = data->image; + struct net_buf *buf; int ret; + /* read_cb() requires buffer size CONFIG_USBD_DFU_TRANSFER_SIZE */ + size = CONFIG_USBD_DFU_TRANSFER_SIZE; + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), size); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; + } + + /* Do not return more than requested */ + size = MIN(setup->wLength, size); + ret = image->read_cb(image->priv, setup->wValue, size, buf->data); if (ret >= 0) { net_buf_add(buf, ret); @@ -654,10 +678,10 @@ static int handle_upload(struct usbd_class_data *const c_data, } } else { dfu_error(c_data, DFU_ERROR, ERR_UNKNOWN); - return -ENOTSUP; + errno = -ENOTSUP; } - return 0; + return buf; } static int handle_download(struct usbd_class_data *const c_data, @@ -678,24 +702,24 @@ static int handle_download(struct usbd_class_data *const c_data, return 0; } -static int dfu_mode_control_to_host(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *dfu_mode_control_to_host(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { struct usbd_dfu_data *data = usbd_class_get_private(c_data); + struct net_buf *buf = NULL; errno = dfu_set_next_state(c_data, setup); if (errno == 0) { switch (setup->bRequest) { case USB_DFU_REQ_GETSTATUS: - errno = handle_get_status(c_data, setup, buf); + buf = handle_get_status(c_data, setup); break; case USB_DFU_REQ_GETSTATE: - errno = handle_get_state(c_data, setup, buf); + buf = handle_get_state(c_data, setup); break; case USB_DFU_REQ_UPLOAD: - errno = handle_upload(c_data, setup, buf); + buf = handle_upload(c_data, setup); break; default: break; @@ -704,7 +728,7 @@ static int dfu_mode_control_to_host(struct usbd_class_data *const c_data, data->state = data->next; - return 0; + return buf; } static int dfu_mode_control_to_dev(struct usbd_class_data *const c_data, diff --git a/subsys/usb/device_next/class/usbd_hid.c b/subsys/usb/device_next/class/usbd_hid.c index 54da756a6293b..168a844c559d6 100644 --- a/subsys/usb/device_next/class/usbd_hid.c +++ b/subsys/usb/device_next/class/usbd_hid.c @@ -397,13 +397,24 @@ static int usbd_hid_ctd(struct usbd_class_data *const c_data, return ret; } -static int usbd_hid_cth(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *usbd_hid_cth(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { const struct device *dev = usbd_class_get_private(c_data); + struct net_buf *buf; int ret = 0; + /* Get Report is problematic because ops->get_report() currently does + * not make it possible to determine report size without passing + * sufficiently large buffer first. For the time being, just allocate + * setup->wLength bytes. + */ + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), setup->wLength); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; + } + switch (setup->bRequest) { case USB_HID_GET_IDLE: ret = handle_get_idle(dev, setup, buf); @@ -422,7 +433,7 @@ static int usbd_hid_cth(struct usbd_class_data *const c_data, break; } - return ret; + return buf; } static void usbd_hid_sof(struct usbd_class_data *const c_data) diff --git a/subsys/usb/device_next/class/usbd_midi2.c b/subsys/usb/device_next/class/usbd_midi2.c index 78b8fa4ccc41c..0121e7f028046 100644 --- a/subsys/usb/device_next/class/usbd_midi2.c +++ b/subsys/usb/device_next/class/usbd_midi2.c @@ -287,13 +287,13 @@ static void usbd_midi_class_resumed(struct usbd_class_data *const class_data) k_work_submit(&data->rx_work); } -static int usbd_midi_class_cth(struct usbd_class_data *const class_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *usbd_midi_class_cth(struct usbd_class_data *const class_data, + const struct usb_setup_packet *const setup) { const struct device *dev = usbd_class_get_private(class_data); const struct usbd_midi_config *config = dev->config; struct usbd_midi_data *data = dev->data; + struct net_buf *buf; size_t head_len = config->desc->grptrm_header.bLength; size_t total_len = sys_le16_to_cpu(config->desc->grptrm_header.wTotalLength); @@ -310,7 +310,14 @@ static int usbd_midi_class_cth(struct usbd_class_data *const class_data, setup->bRequest != USB_SREQ_GET_DESCRIPTOR || setup->wValue != ((CS_GR_TRM_BLOCK << 8) | MIDI2_ALTERNATE)) { errno = -ENOTSUP; - return 0; + return NULL; + } + + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(class_data), + MIN(total_len, setup->wLength)); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; } /* Group terminal block header */ @@ -324,7 +331,7 @@ static int usbd_midi_class_cth(struct usbd_class_data *const class_data, } LOG_HEXDUMP_DBG(buf->data, buf->len, "Control to host"); - return 0; + return buf; } static int usbd_midi_class_init(struct usbd_class_data *const class_data) diff --git a/subsys/usb/device_next/class/usbd_msc.c b/subsys/usb/device_next/class/usbd_msc.c index 0d336f75e8821..1f83102ae2676 100644 --- a/subsys/usb/device_next/class/usbd_msc.c +++ b/subsys/usb/device_next/class/usbd_msc.c @@ -825,11 +825,11 @@ static int msc_bot_control_to_dev(struct usbd_class_data *const c_data, } /* USB control request handler to host */ -static int msc_bot_control_to_host(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *msc_bot_control_to_host(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { struct msc_bot_ctx *ctx = usbd_class_get_private(c_data); + struct net_buf *buf = NULL; uint8_t max_lun; if (setup->bRequest == GET_MAX_LUN && @@ -839,12 +839,19 @@ static int msc_bot_control_to_host(struct usbd_class_data *const c_data, * support multiple LUNs and host should only address LUN 0. */ max_lun = ctx->registered_luns ? ctx->registered_luns - 1 : 0; + + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), 1); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; + } + net_buf_add_mem(buf, &max_lun, 1); } else { errno = -ENOTSUP; } - return 0; + return buf; } /* Endpoint request completion event handler */ diff --git a/subsys/usb/device_next/class/usbd_uac2.c b/subsys/usb/device_next/class/usbd_uac2.c index 0c2585e0400a2..347b4de396478 100644 --- a/subsys/usb/device_next/class/usbd_uac2.c +++ b/subsys/usb/device_next/class/usbd_uac2.c @@ -571,14 +571,24 @@ static uint32_t find_closest(const uint32_t input, const uint32_t *values, } /* Table 5-6: 4-byte Control CUR Parameter Block */ -static void layout3_cur_response(struct net_buf *const buf, uint16_t length, - const uint32_t value) +static struct net_buf *layout3_cur_response(struct usbd_class_data *const c_data, + uint16_t length, const uint32_t value) { + struct net_buf *buf; uint8_t tmp[4]; + length = MIN(length, 4); + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), length); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; + } + /* dCUR */ sys_put_le32(value, tmp); - net_buf_add_mem(buf, tmp, MIN(length, 4)); + net_buf_add_mem(buf, tmp, length); + + return buf; } static int layout3_cur_request(const struct net_buf *const buf, uint32_t *out) @@ -595,15 +605,28 @@ static int layout3_cur_request(const struct net_buf *const buf, uint32_t *out) } /* Table 5-7: 4-byte Control RANGE Parameter Block */ -static void layout3_range_response(struct net_buf *const buf, uint16_t length, - const uint32_t *min, const uint32_t *max, - const uint32_t *res, int n) +static struct net_buf *layout3_range_response(struct usbd_class_data *const c_data, + uint16_t length, + const uint32_t *min, const uint32_t *max, + const uint32_t *res, int n) { + struct net_buf *buf; uint16_t to_add; uint8_t tmp[4]; int i; int item; + /* Host can set wLength as large as it wants, but we only need to + * allocate memory for maximum number of entries consisting of: + * 2 (wNumSubRanges) + 12 (dMIN, dMAX, dRES) * n + */ + length = MIN(2 + 12 * n, length); + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), length); + if (buf == NULL) { + errno = -ENOMEM; + return NULL; + } + /* wNumSubRanges */ sys_put_le16(n, tmp); to_add = MIN(length, 2); @@ -635,11 +658,12 @@ static void layout3_range_response(struct net_buf *const buf, uint16_t length, i++; } } + + return buf; } -static int get_clock_source_request(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *get_clock_source_request(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { const struct device *dev = usbd_class_get_private(c_data); struct uac2_ctx *ctx = dev->data; @@ -652,7 +676,7 @@ static int get_clock_source_request(struct usbd_class_data *const c_data, LOG_DBG("Clock source control with channel %d", CONTROL_CHANNEL_NUMBER(setup)); errno = -EINVAL; - return 0; + return NULL; } count = clock_frequencies(c_data, clock_id, &frequencies); @@ -660,9 +684,8 @@ static int get_clock_source_request(struct usbd_class_data *const c_data, if (CONTROL_SELECTOR(setup) == CS_SAM_FREQ_CONTROL) { if (CONTROL_ATTRIBUTE(setup) == CUR) { if (count == 1) { - layout3_cur_response(buf, setup->wLength, - frequencies[0]); - return 0; + return layout3_cur_response(c_data, setup->wLength, + frequencies[0]); } if (ctx->ops->get_sample_rate) { @@ -670,13 +693,11 @@ static int get_clock_source_request(struct usbd_class_data *const c_data, hz = ctx->ops->get_sample_rate(dev, clock_id, ctx->user_data); - layout3_cur_response(buf, setup->wLength, hz); - return 0; + return layout3_cur_response(c_data, setup->wLength, hz); } } else if (CONTROL_ATTRIBUTE(setup) == RANGE) { - layout3_range_response(buf, setup->wLength, frequencies, - frequencies, NULL, count); - return 0; + return layout3_range_response(c_data, setup->wLength, frequencies, + frequencies, NULL, count); } } else { LOG_DBG("Unhandled clock control selector 0x%02x", @@ -684,7 +705,7 @@ static int get_clock_source_request(struct usbd_class_data *const c_data, } errno = -ENOTSUP; - return 0; + return NULL; } static int set_clock_source_request(struct usbd_class_data *const c_data, @@ -769,27 +790,26 @@ static int uac2_control_to_dev(struct usbd_class_data *const c_data, return 0; } -static int uac2_control_to_host(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *uac2_control_to_host(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { entity_type_t entity_type; if ((CONTROL_ATTRIBUTE(setup) != CUR) && (CONTROL_ATTRIBUTE(setup) != RANGE)) { errno = -ENOTSUP; - return 0; + return NULL; } if (setup->bmRequestType == GET_CLASS_REQUEST_TYPE) { entity_type = id_type(c_data, CONTROL_ENTITY_ID(setup)); if (entity_type == ENTITY_TYPE_CLOCK_SOURCE) { - return get_clock_source_request(c_data, setup, buf); + return get_clock_source_request(c_data, setup); } } errno = -ENOTSUP; - return 0; + return NULL; } static int uac2_request(struct usbd_class_data *const c_data, struct net_buf *buf, diff --git a/subsys/usb/device_next/class/usbd_uvc.c b/subsys/usb/device_next/class/usbd_uvc.c index 40b507ed81669..ad7f04c743baf 100644 --- a/subsys/usb/device_next/class/usbd_uvc.c +++ b/subsys/usb/device_next/class/usbd_uvc.c @@ -1016,12 +1016,13 @@ static int uvc_get_control_op(const struct device *dev, const struct usb_setup_p return UVC_OP_RETURN_ERROR; } -static int uvc_control_to_host(struct usbd_class_data *const c_data, - const struct usb_setup_packet *const setup, - struct net_buf *const buf) +static struct net_buf *uvc_control_to_host(struct usbd_class_data *const c_data, + const struct usb_setup_packet *const setup) { const struct device *dev = usbd_class_get_private(c_data); const struct uvc_control_map *map = NULL; + struct net_buf *buf; + const size_t size = MIN(sizeof(struct uvc_probe), setup->wLength); uint8_t request = setup->bRequest; LOG_INF("Host sent a %s request, wValue 0x%04x, wIndex 0x%04x, wLength %u", @@ -1031,6 +1032,12 @@ static int uvc_control_to_host(struct usbd_class_data *const c_data, request == UVC_GET_INFO ? "GET_INFO" : "bad", setup->wValue, setup->wIndex, setup->wLength); + buf = usbd_ep_ctrl_data_in_alloc(usbd_class_get_ctx(c_data), size); + if (buf == NULL) { + errno = ENOMEM; + return NULL; + } + switch (uvc_get_control_op(dev, setup, &map)) { case UVC_OP_VS_PROBE: errno = -uvc_get_vs_probe(dev, buf, setup); @@ -1046,7 +1053,8 @@ static int uvc_control_to_host(struct usbd_class_data *const c_data, break; case UVC_OP_RETURN_ERROR: errno = EINVAL; - return 0; + net_buf_unref(buf); + return NULL; default: LOG_WRN("Unhandled operation, stalling control command"); errno = EINVAL; @@ -1054,7 +1062,7 @@ static int uvc_control_to_host(struct usbd_class_data *const c_data, uvc_set_errno(dev, errno); - return 0; + return buf; } static int uvc_control_to_dev(struct usbd_class_data *const c_data, diff --git a/subsys/usb/device_next/usbd_ch9.c b/subsys/usb/device_next/usbd_ch9.c index 666a9ba49d739..3c8dde6304892 100644 --- a/subsys/usb/device_next/usbd_ch9.c +++ b/subsys/usb/device_next/usbd_ch9.c @@ -28,7 +28,7 @@ LOG_MODULE_REGISTER(usbd_ch9, CONFIG_USBD_LOG_LEVEL); #define SF_TEST_LOWER_BYTE(wIndex) ((uint8_t)(wIndex)) static int nonstd_request(struct usbd_context *const uds_ctx, - struct net_buf *const dbuf); + struct net_buf **const pbuf); static bool reqtype_is_to_host(const struct usb_setup_packet *const setup) { @@ -381,9 +381,10 @@ static int std_request_to_device(struct usbd_context *const uds_ctx, } static int sreq_get_status(struct usbd_context *const uds_ctx, - struct net_buf *const buf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + struct net_buf *buf; uint8_t ep = setup->wIndex; uint16_t response = 0; @@ -427,11 +428,14 @@ static int sreq_get_status(struct usbd_context *const uds_ctx, break; } - if (net_buf_tailroom(buf) < setup->wLength) { + buf = usbd_ep_ctrl_data_in_alloc(uds_ctx, sizeof(response)); + if (buf == NULL) { errno = -ENOMEM; return 0; } + *pbuf = buf; + LOG_DBG("Get Status response 0x%04x", response); net_buf_add_le16(buf, response); @@ -443,7 +447,7 @@ static int sreq_get_status(struct usbd_context *const uds_ctx, * descriptor type requests. */ static int sreq_get_desc_cfg(struct usbd_context *const uds_ctx, - struct net_buf *const buf, + struct net_buf **const pbuf, const uint8_t idx, const bool other_cfg) { @@ -454,6 +458,7 @@ static int sreq_get_desc_cfg(struct usbd_context *const uds_ctx, struct usbd_config_node *cfg_nd; enum usbd_speed get_desc_speed; struct usbd_class_node *c_nd; + struct net_buf *buf; uint16_t len; /* @@ -493,6 +498,15 @@ static int sreq_get_desc_cfg(struct usbd_context *const uds_ctx, cfg_desc = cfg_nd->desc; } + len = MIN(sys_le16_to_cpu(cfg_desc->wTotalLength), setup->wLength); + buf = usbd_ep_ctrl_data_in_alloc(uds_ctx, len); + if (buf == NULL) { + errno = -ENOMEM; + return 0; + } + + *pbuf = buf; + net_buf_add_mem(buf, cfg_desc, MIN(net_buf_tailroom(buf), cfg_desc->bLength)); SYS_SLIST_FOR_EACH_CONTAINER(&cfg_nd->class_list, c_nd, node) { @@ -549,13 +563,15 @@ static ssize_t get_sn_from_hwid(uint8_t sn[static USBD_SN_ASCII7_LENGTH]) } /* Copy and convert ASCII-7 string descriptor to UTF16-LE */ -static void string_ascii7_to_utf16le(struct usbd_desc_node *const dn, - struct net_buf *const buf, const uint16_t wLength) +static void string_ascii7_to_utf16le(struct usbd_context *const uds_ctx, + struct usbd_desc_node *const dn, + struct net_buf **const pbuf, const uint16_t wLength) { uint8_t sn_ascii7_str[USBD_SN_ASCII7_LENGTH]; struct usb_desc_header head = { .bDescriptorType = dn->bDescriptorType, }; + struct net_buf *buf; const uint8_t *ascii7_str; size_t len; size_t i; @@ -576,10 +592,16 @@ static void string_ascii7_to_utf16le(struct usbd_desc_node *const dn, ascii7_str = (uint8_t *)dn->ptr; } - LOG_DBG("wLength %u, bLength %u, tailroom %zu", - wLength, head.bLength, net_buf_tailroom(buf)); + LOG_DBG("wLength %u, bLength %u", wLength, head.bLength); - len = MIN(net_buf_tailroom(buf), MIN(head.bLength, wLength)); + len = MIN(head.bLength, wLength); + buf = usbd_ep_ctrl_data_in_alloc(uds_ctx, len); + if (buf == NULL) { + errno = -ENOMEM; + return; + } + + *pbuf = buf; /* Add bLength and bDescriptorType */ net_buf_add_mem(buf, &head, MIN(len, sizeof(head))); @@ -598,14 +620,13 @@ static void string_ascii7_to_utf16le(struct usbd_desc_node *const dn, } static int sreq_get_desc_dev(struct usbd_context *const uds_ctx, - struct net_buf *const buf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); struct usb_desc_header *head; + struct net_buf *buf; size_t len; - len = MIN(setup->wLength, net_buf_tailroom(buf)); - switch (usbd_bus_speed(uds_ctx)) { case USBD_SPEED_FS: head = uds_ctx->fs_desc; @@ -622,13 +643,22 @@ static int sreq_get_desc_dev(struct usbd_context *const uds_ctx, return -EINVAL; } - net_buf_add_mem(buf, head, MIN(len, head->bLength)); + len = MIN(setup->wLength, head->bLength); + buf = usbd_ep_ctrl_data_in_alloc(uds_ctx, len); + if (buf == NULL) { + errno = -ENOMEM; + return 0; + } + + *pbuf = buf; + + net_buf_add_mem(buf, head, len); return 0; } static int sreq_get_desc_str(struct usbd_context *const uds_ctx, - struct net_buf *const buf, const uint8_t idx) + struct net_buf **const pbuf, const uint8_t idx) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); struct usbd_desc_node *d_nd; @@ -648,19 +678,28 @@ static int sreq_get_desc_str(struct usbd_context *const uds_ctx, .bDescriptorType = d_nd->bDescriptorType, .bString = *(uint16_t *)d_nd->ptr, }; + struct net_buf *buf; + + len = MIN(setup->wLength, langid.bLength); + buf = usbd_ep_ctrl_data_in_alloc(uds_ctx, len); + if (buf == NULL) { + errno = -ENOMEM; + return 0; + } - len = MIN(setup->wLength, net_buf_tailroom(buf)); - net_buf_add_mem(buf, &langid, MIN(len, langid.bLength)); + *pbuf = buf; + + net_buf_add_mem(buf, &langid, len); } else { /* String descriptors in ASCII7 format */ - string_ascii7_to_utf16le(d_nd, buf, setup->wLength); + string_ascii7_to_utf16le(uds_ctx, d_nd, pbuf, setup->wLength); } return 0; } static int sreq_get_dev_qualifier(struct usbd_context *const uds_ctx, - struct net_buf *const buf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); /* At Full-Speed we want High-Speed descriptor and vice versa */ @@ -672,6 +711,7 @@ static int sreq_get_dev_qualifier(struct usbd_context *const uds_ctx, .bDescriptorType = USB_DESC_DEVICE_QUALIFIER, .bReserved = 0U, }; + struct net_buf *buf; size_t len; /* @@ -696,8 +736,17 @@ static int sreq_get_dev_qualifier(struct usbd_context *const uds_ctx, q_desc.bNumConfigurations = d_desc->bNumConfigurations; LOG_DBG("Get Device Qualifier"); - len = MIN(setup->wLength, net_buf_tailroom(buf)); - net_buf_add_mem(buf, &q_desc, MIN(len, q_desc.bLength)); + + len = MIN(setup->wLength, q_desc.bLength); + buf = usbd_ep_ctrl_data_in_alloc(uds_ctx, len); + if (buf == NULL) { + errno = -ENOMEM; + return 0; + } + + *pbuf = buf; + + net_buf_add_mem(buf, &q_desc, len); return 0; } @@ -721,12 +770,13 @@ static void desc_fill_bos_root(struct usbd_context *const uds_ctx, } static int sreq_get_desc_bos(struct usbd_context *const uds_ctx, - struct net_buf *const buf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); struct usb_device_descriptor *dev_dsc; struct usb_bos_descriptor bos; struct usbd_desc_node *desc_nd; + struct net_buf *buf; size_t len; if (!IS_ENABLED(CONFIG_USBD_BOS_SUPPORT)) { @@ -756,13 +806,23 @@ static int sreq_get_desc_bos(struct usbd_context *const uds_ctx, } desc_fill_bos_root(uds_ctx, &bos); - len = MIN(net_buf_tailroom(buf), MIN(setup->wLength, bos.wTotalLength)); + + len = MIN(setup->wLength, bos.wTotalLength); + buf = usbd_ep_ctrl_data_in_alloc(uds_ctx, len); + if (buf == NULL) { + errno = -ENOMEM; + return 0; + } + + *pbuf = buf; + LOG_DBG("wLength %u, bLength %u, wTotalLength %u, tailroom %zu", setup->wLength, bos.bLength, bos.wTotalLength, net_buf_tailroom(buf)); + bos.wTotalLength = sys_le16_to_cpu(bos.wTotalLength); net_buf_add_mem(buf, &bos, MIN(len, bos.bLength)); - len -= MIN(len, sizeof(bos)); + len -= MIN(len, bos.bLength); if (len == 0) { return 0; } @@ -784,7 +844,7 @@ static int sreq_get_desc_bos(struct usbd_context *const uds_ctx, } static int sreq_get_descriptor(struct usbd_context *const uds_ctx, - struct net_buf *const buf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); uint8_t desc_type = USB_GET_DESCRIPTOR_TYPE(setup->wValue); @@ -800,22 +860,22 @@ static int sreq_get_descriptor(struct usbd_context *const uds_ctx, * number or endpoint and not the language ID. e.g. HID * Class Get Descriptor request. */ - return nonstd_request(uds_ctx, buf); + return nonstd_request(uds_ctx, pbuf); } switch (desc_type) { case USB_DESC_DEVICE: - return sreq_get_desc_dev(uds_ctx, buf); + return sreq_get_desc_dev(uds_ctx, pbuf); case USB_DESC_CONFIGURATION: - return sreq_get_desc_cfg(uds_ctx, buf, desc_idx, false); + return sreq_get_desc_cfg(uds_ctx, pbuf, desc_idx, false); case USB_DESC_OTHER_SPEED: - return sreq_get_desc_cfg(uds_ctx, buf, desc_idx, true); + return sreq_get_desc_cfg(uds_ctx, pbuf, desc_idx, true); case USB_DESC_STRING: - return sreq_get_desc_str(uds_ctx, buf, desc_idx); + return sreq_get_desc_str(uds_ctx, pbuf, desc_idx); case USB_DESC_DEVICE_QUALIFIER: - return sreq_get_dev_qualifier(uds_ctx, buf); + return sreq_get_dev_qualifier(uds_ctx, pbuf); case USB_DESC_BOS: - return sreq_get_desc_bos(uds_ctx, buf); + return sreq_get_desc_bos(uds_ctx, pbuf); case USB_DESC_INTERFACE: case USB_DESC_ENDPOINT: default: @@ -827,10 +887,11 @@ static int sreq_get_descriptor(struct usbd_context *const uds_ctx, } static int sreq_get_configuration(struct usbd_context *const uds_ctx, - struct net_buf *const buf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + struct net_buf *buf; uint8_t cfg = usbd_get_config_value(uds_ctx); /* Not specified in default state, treat as error */ @@ -844,22 +905,26 @@ static int sreq_get_configuration(struct usbd_context *const uds_ctx, return 0; } - if (net_buf_tailroom(buf) < setup->wLength) { + buf = usbd_ep_ctrl_data_in_alloc(uds_ctx, sizeof(cfg)); + if (buf == NULL) { errno = -ENOMEM; return 0; } + *pbuf = buf; + net_buf_add_u8(buf, cfg); return 0; } static int sreq_get_interface(struct usbd_context *const uds_ctx, - struct net_buf *const buf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); struct usb_cfg_descriptor *cfg_desc; struct usbd_config_node *cfg_nd; + struct net_buf *buf; uint8_t cur_alt; if (setup->RequestType.recipient != USB_REQTYPE_RECIPIENT_INTERFACE) { @@ -895,34 +960,37 @@ static int sreq_get_interface(struct usbd_context *const uds_ctx, return 0; } - if (net_buf_tailroom(buf) < setup->wLength) { + buf = usbd_ep_ctrl_data_in_alloc(uds_ctx, sizeof(cur_alt)); + if (buf == NULL) { errno = -ENOMEM; return 0; } + *pbuf = buf; + net_buf_add_u8(buf, cur_alt); return 0; } static int std_request_to_host(struct usbd_context *const uds_ctx, - struct net_buf *const buf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); int ret; switch (setup->bRequest) { case USB_SREQ_GET_STATUS: - ret = sreq_get_status(uds_ctx, buf); + ret = sreq_get_status(uds_ctx, pbuf); break; case USB_SREQ_GET_DESCRIPTOR: - ret = sreq_get_descriptor(uds_ctx, buf); + ret = sreq_get_descriptor(uds_ctx, pbuf); break; case USB_SREQ_GET_CONFIGURATION: - ret = sreq_get_configuration(uds_ctx, buf); + ret = sreq_get_configuration(uds_ctx, pbuf); break; case USB_SREQ_GET_INTERFACE: - ret = sreq_get_interface(uds_ctx, buf); + ret = sreq_get_interface(uds_ctx, pbuf); break; default: errno = -ENOTSUP; @@ -934,7 +1002,7 @@ static int std_request_to_host(struct usbd_context *const uds_ctx, } static int vendor_device_request(struct usbd_context *const uds_ctx, - struct net_buf *const buf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); struct usbd_vreq_node *vreq_nd; @@ -952,13 +1020,16 @@ static int vendor_device_request(struct usbd_context *const uds_ctx, if (reqtype_is_to_device(setup) && vreq_nd->to_dev != NULL) { LOG_DBG("Vendor request 0x%02x to device", setup->bRequest); - errno = vreq_nd->to_dev(uds_ctx, setup, buf); + errno = vreq_nd->to_dev(uds_ctx, setup, *pbuf); return 0; } if (reqtype_is_to_host(setup) && vreq_nd->to_host != NULL) { LOG_DBG("Vendor request 0x%02x to host", setup->bRequest); - errno = vreq_nd->to_host(uds_ctx, setup, buf); + *pbuf = vreq_nd->to_host(uds_ctx, setup); + if (*pbuf == NULL && errno == 0) { + errno = -ENODATA; + } return 0; } @@ -967,7 +1038,7 @@ static int vendor_device_request(struct usbd_context *const uds_ctx, } static int nonstd_request(struct usbd_context *const uds_ctx, - struct net_buf *const dbuf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); struct usbd_class_node *c_nd = NULL; @@ -989,19 +1060,22 @@ static int nonstd_request(struct usbd_context *const uds_ctx, if (c_nd != NULL) { if (reqtype_is_to_device(setup)) { - ret = usbd_class_control_to_dev(c_nd->c_data, setup, dbuf); + ret = usbd_class_control_to_dev(c_nd->c_data, setup, *pbuf); } else { - ret = usbd_class_control_to_host(c_nd->c_data, setup, dbuf); + *pbuf = usbd_class_control_to_host(c_nd->c_data, setup); + if (*pbuf == NULL && errno == 0) { + errno = -ENODATA; + } } } else { - return vendor_device_request(uds_ctx, dbuf); + return vendor_device_request(uds_ctx, pbuf); } return ret; } static int handle_setup_request(struct usbd_context *const uds_ctx, - struct net_buf *const buf) + struct net_buf **const pbuf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); int ret; @@ -1011,14 +1085,14 @@ static int handle_setup_request(struct usbd_context *const uds_ctx, switch (setup->RequestType.type) { case USB_REQTYPE_TYPE_STANDARD: if (reqtype_is_to_device(setup)) { - ret = std_request_to_device(uds_ctx, buf); + ret = std_request_to_device(uds_ctx, *pbuf); } else { - ret = std_request_to_host(uds_ctx, buf); + ret = std_request_to_host(uds_ctx, pbuf); } break; case USB_REQTYPE_TYPE_CLASS: case USB_REQTYPE_TYPE_VENDOR: - ret = nonstd_request(uds_ctx, buf); + ret = nonstd_request(uds_ctx, pbuf); break; default: errno = -ENOTSUP; @@ -1180,25 +1254,16 @@ int usbd_handle_ctrl_xfer(struct usbd_context *const uds_ctx, ret = usbd_ep_ctrl_enqueue(uds_ctx, next_buf); return ret; } - - if (setup->wLength) { - /* Stack is supposed to allocate buffer */ - next_buf = usbd_ep_ctrl_data_in_alloc(uds_ctx, setup->wLength); - if (next_buf == NULL) { - err = -ENOMEM; - goto ctrl_xfer_stall; - } - } } else { /* Data OUT received */ next_buf = buf; } /* - * Handle request and data stage, next_buf is either - * data buffer or is NULL. + * Handle request and data stage, next_buf holds either received + * data OUT buffer or is NULL. */ - ret = handle_setup_request(uds_ctx, next_buf); + ret = handle_setup_request(uds_ctx, &next_buf); if ((ret || errno) && next_buf) { net_buf_unref(next_buf); } @@ -1224,6 +1289,10 @@ int usbd_handle_ctrl_xfer(struct usbd_context *const uds_ctx, ret = usbd_enqueue_status_in(uds_ctx); } else { /* Enqueue Data IN */ + if (next_buf == NULL) { + goto ctrl_xfer_stall; + } + ret = usbd_ep_ctrl_enqueue(uds_ctx, next_buf); if (ret) { net_buf_unref(next_buf); diff --git a/subsys/usb/device_next/usbd_class_api.h b/subsys/usb/device_next/usbd_class_api.h index 88207ccc39cd6..28aad59b1d102 100644 --- a/subsys/usb/device_next/usbd_class_api.h +++ b/subsys/usb/device_next/usbd_class_api.h @@ -55,22 +55,21 @@ static inline int usbd_class_request(struct usbd_class_data *const c_data, * * @param[in] c_data Pointer to USB device class data * @param[in] setup Pointer to USB Setup Packet - * @param[in] buf Control Request Data buffer * - * @return 0 on success, other values on fail. + * @return Buffer with data to send to host on success, NULL on fail. */ -static inline int usbd_class_control_to_host(struct usbd_class_data *const c_data, - struct usb_setup_packet *const setup, - struct net_buf *const buf) +static inline struct net_buf * +usbd_class_control_to_host(struct usbd_class_data *const c_data, + struct usb_setup_packet *const setup) { const struct usbd_class_api *api = c_data->api; if (api->control_to_host != NULL) { - return api->control_to_host(c_data, setup, buf); + return api->control_to_host(c_data, setup); } errno = -ENOTSUP; - return 0; + return NULL; } /**