diff options
| author | Ha Thach <[email protected]> | 2023-06-15 16:28:33 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-06-15 16:28:33 +0700 |
| commit | 433ffe2152ea3763fcd8d5b108f694d2c6cb826d (patch) | |
| tree | 8f748442aee7a8f8beb02e89494e8ec6f7af325e /src | |
| parent | 81450bc71d37fce73241f7a683b51872860cb7b7 (diff) | |
| parent | 5ce60c5d207b9e7de419be6956164aebde14c3f2 (diff) | |
Merge pull request #1985 from kkitayam/uvc_bulk
Add the capability for video class to handle a bulk endpoint in the streaming interface.
Diffstat (limited to 'src')
| -rw-r--r-- | src/class/video/video_device.c | 85 |
1 files changed, 60 insertions, 25 deletions
diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index d6e98602b..91f452afc 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -37,6 +37,10 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ +#define VS_STATE_PROBING 0 /* Configuration in progress */ +#define VS_STATE_COMMITTED 1 /* Ready for streaming or Streaming via bulk endpoint */ +#define VS_STATE_STREAMING 2 /* Streaming via isochronous endpoint */ + typedef struct { tusb_desc_interface_t std; tusb_desc_cs_video_ctl_itf_hdr_t ctl; @@ -102,6 +106,7 @@ typedef struct TU_ATTR_PACKED { uint32_t offset; /* offset for the next payload transfer */ uint32_t max_payload_transfer_size; uint8_t error_code;/* error code */ + uint8_t state; /* 0:probing 1:committed 2:streaming */ /*------------- From this point, data is not cleared by bus reset -------------*/ CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */ } videod_streaming_interface_t; @@ -639,6 +644,17 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t return true; } +static bool _init_vs_configuration(videod_streaming_interface_t *stm) +{ + /* initialize streaming settings */ + stm->state = VS_STATE_PROBING; + stm->max_payload_transfer_size = 0; + video_probe_and_commit_control_t *param = + (video_probe_and_commit_control_t *)&stm->ep_buf; + tu_memclr(param, sizeof(*param)); + return _update_streaming_parameters(stm, param); +} + /** Set the alternate setting to own video streaming interface. * * @param[in,out] stm Streaming interface context. @@ -672,42 +688,32 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints; TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep)); - stm->desc.cur = (uint16_t) (cur - desc); /* Save the offset of the new settings */ - if (!altnum) { - /* initialize streaming settings */ - stm->max_payload_transfer_size = 0; - video_probe_and_commit_control_t *param = - (video_probe_and_commit_control_t *)&stm->ep_buf; - tu_memclr(param, sizeof(*param)); - TU_LOG2(" done 0\n"); - return _update_streaming_parameters(stm, param); + stm->desc.cur = (uint16_t)(cur - desc); /* Save the offset of the new settings */ + if (!altnum && (VS_STATE_COMMITTED != stm->state)) { + TU_VERIFY(_init_vs_configuration(stm)); } - /* Open endpoints of the new settings. */ + /* Open bulk or isochronous endpoints of the new settings. */ for (i = 0, cur = tu_desc_next(cur); i < numeps; ++i, cur = tu_desc_next(cur)) { cur = _find_desc_ep(cur, end); TU_ASSERT(cur < end); tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)cur; - if (!stm->max_payload_transfer_size) { - video_probe_and_commit_control_t const *param = (video_probe_and_commit_control_t const*)&stm->ep_buf; - uint_fast32_t max_size = param->dwMaxPayloadTransferSize; + uint_fast32_t max_size = stm->max_payload_transfer_size; + if (altnum) { if ((TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer) && - (tu_edpt_packet_size(ep) < max_size)) - { + (tu_edpt_packet_size(ep) < max_size)) { /* FS must be less than or equal to max packet size */ return false; } - /* Set the negotiated value */ - stm->max_payload_transfer_size = max_size; + } else { + TU_VERIFY(TUSB_XFER_BULK == ep->bmAttributes.xfer); } TU_ASSERT(usbd_edpt_open(rhport, ep)); stm->desc.ep[i] = (uint16_t) (cur - desc); TU_LOG2(" open EP%02x\n", _desc_ep_addr(cur)); } - /* initialize payload header */ - tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf; - hdr->bHeaderLength = sizeof(*hdr); - hdr->bmHeaderInfo = 0; - + if (altnum) { + stm->state = VS_STATE_STREAMING; + } TU_LOG2(" done\n"); return true; } @@ -920,6 +926,10 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, break; case VIDEO_VS_CTL_PROBE: + if (self->state != VS_STATE_PROBING) { + self->state = VS_STATE_PROBING; + _init_vs_configuration(self); + } switch (request->bRequest) { case VIDEO_REQUEST_SET_CUR: if (stage == CONTROL_STAGE_SETUP) { @@ -982,9 +992,23 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN); TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); } else if (stage == CONTROL_STAGE_DATA) { - TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + video_probe_and_commit_control_t *param = (video_probe_and_commit_control_t*)self->ep_buf; + TU_VERIFY(_update_streaming_parameters(self, param), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + /* Set the negotiated value */ + self->max_payload_transfer_size = param->dwMaxPayloadTransferSize; + int ret = VIDEO_ERROR_NONE; if (tud_video_commit_cb) { - return tud_video_commit_cb(self->index_vc, self->index_vs, (video_probe_and_commit_control_t*)self->ep_buf); + ret = tud_video_commit_cb(self->index_vc, self->index_vs, param); + } + if (VIDEO_ERROR_NONE == ret) { + self->state = VS_STATE_COMMITTED; + self->buffer = NULL; + self->bufsize = 0; + self->offset = 0; + /* initialize payload header */ + tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)self->ep_buf; + hdr->bHeaderLength = sizeof(*hdr); + hdr->bmHeaderInfo = 0; } } return VIDEO_ERROR_NONE; @@ -1069,6 +1093,7 @@ bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING); videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); if (!stm || !stm->desc.ep[0]) return false; + if (stm->state == VS_STATE_PROBING) return false; return true; } @@ -1079,6 +1104,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu if (!buffer || !bufsize) return false; videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); if (!stm || !stm->desc.ep[0] || stm->buffer) return false; + if (stm->state == VS_STATE_PROBING) return false; /* Find EP address */ uint8_t const *desc = _videod_itf[stm->index_vc].beg; @@ -1174,6 +1200,16 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin stm->desc.beg = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); cur = _next_desc_itf(cur, end); stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); + stm->state = VS_STATE_PROBING; + if (0 == stm_idx && 1 == bInCollection) { + /* If there is only one streaming interface and no alternate settings, + * host may not issue set_interface so open the streaming interface here. */ + uint8_t const *sbeg = (uint8_t const*)itf_desc + stm->desc.beg; + uint8_t const *send = (uint8_t const*)itf_desc + stm->desc.end; + if (end == _find_desc_itf(sbeg, send, _desc_itfnum(sbeg), 1)) { + TU_VERIFY(_open_vs_itf(rhport, stm, 0), 0); + } + } } self->len = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); return (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc); @@ -1187,7 +1223,6 @@ bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_ int err; TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); uint_fast8_t itfnum = tu_u16_low(request->wIndex); - /* Identify which control interface to use */ uint_fast8_t itf; for (itf = 0; itf < CFG_TUD_VIDEO; ++itf) { |
