blob: be4b3f57db7e5df59ee08ae271926bc5c33d63f0 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ddk/debug.h>
#include <usb/usb.h>
#include <string.h>
#include "garnet/drivers/usb_video/video-util.h"
static void print_controls(usb_video_vc_probe_and_commit_controls* proposal) {
zxlogf(TRACE, "bmHint 0x%x\n", proposal->bmHint);
zxlogf(TRACE, "bFormatIndex: %u\n", proposal->bFormatIndex);
zxlogf(TRACE, "bFrameIndex: %u\n", proposal->bFrameIndex);
zxlogf(TRACE, "dwFrameInterval: %u\n", proposal->dwFrameInterval);
zxlogf(TRACE, "dwMaxVideoFrameSize: %u\n", proposal->dwMaxVideoFrameSize);
zxlogf(TRACE, "dwMaxPayloadTransferSize: %u\n",
proposal->dwMaxPayloadTransferSize);
}
zx_status_t usb_video_negotiate_probe(
usb_protocol_t* usb, uint8_t vs_interface_num,
usb_video_vc_probe_and_commit_controls* proposal,
usb_video_vc_probe_and_commit_controls* out_result) {
zx_status_t status;
size_t out_length;
zxlogf(TRACE, "usb_video_negotiate_probe: PROBE_CONTROL SET_CUR\n");
print_controls(proposal);
// The wValue field (the fourth parameter) specifies the Control Selector
// (in this case USB_VIDEO_VS_PROBE_CONTROL) in the high byte,
// and the low byte must be set to zero.
// See UVC 1.5 Spec. 4.2.1 Interface Control Requests.
status = usb_control_out(usb, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
USB_VIDEO_SET_CUR, USB_VIDEO_VS_PROBE_CONTROL << 8,
vs_interface_num, ZX_TIME_INFINITE,
proposal, sizeof(*proposal));
if (status != ZX_OK)
goto out;
// The length of returned result varies, so zero this out before hand.
memset(out_result, 0, sizeof(usb_video_vc_probe_and_commit_controls));
zxlogf(TRACE, "usb_video_negotiate_probe: PROBE_CONTROL GET_CUR\n");
status = usb_control_in(usb, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
USB_VIDEO_GET_CUR, USB_VIDEO_VS_PROBE_CONTROL << 8,
vs_interface_num, ZX_TIME_INFINITE,
out_result, sizeof(*out_result), &out_length);
if (status != ZX_OK) {
goto out;
}
// Fields after dwMaxPayloadTransferSize are optional, only 26 bytes are
// guaranteed.
if (out_length < 26) {
zxlogf(ERROR, "usb_video_negotiate_probe: got length %lu, want >= 26\n",
out_length);
goto out;
}
print_controls(out_result);
out:
if (status == ZX_ERR_IO_REFUSED || status == ZX_ERR_IO_INVALID) {
// clear the stall/error
usb_reset_endpoint(usb, 0);
}
return status;
}
zx_status_t usb_video_negotiate_commit(
usb_protocol_t* usb, uint8_t vs_interface_num,
usb_video_vc_probe_and_commit_controls* ctrls) {
zxlogf(TRACE, "usb_video_negotiate_commit: COMMIT_CONTROL SET_CUR\n");
zx_status_t status = usb_control_out(
usb, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
USB_VIDEO_SET_CUR, USB_VIDEO_VS_COMMIT_CONTROL << 8, vs_interface_num,
ZX_TIME_INFINITE, ctrls, sizeof(*ctrls));
if (status == ZX_ERR_IO_REFUSED || status == ZX_ERR_IO_INVALID) {
// clear the stall/error
usb_reset_endpoint(usb, 0);
}
return status;
}