blob: 2bfa1fe9145c668b7ea361789f82949007be0329 [file] [log] [blame]
// Copyright 2018 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 "device_ctx.h"
#include "amlogic-video.h"
#include "macros.h"
#include <zircon/device/media-codec.h>
namespace {
static zx_status_t amlogic_video_ioctl(void* ctx, uint32_t op,
const void* in_buf, size_t in_len,
void* out_buf, size_t out_len,
size_t* out_actual) {
// The only IOCTL we support is get channel.
if (op != MEDIA_CODEC_IOCTL_GET_CODEC_FACTORY_CHANNEL) {
return ZX_ERR_NOT_SUPPORTED;
}
if ((out_buf == nullptr) || (out_actual == nullptr) ||
(out_len != sizeof(zx_handle_t))) {
return ZX_ERR_INVALID_ARGS;
}
DeviceCtx* device = reinterpret_cast<DeviceCtx*>(ctx);
zx::channel codec_factory_client_endpoint;
device->device_fidl()->CreateChannelBoundCodecFactory(
&codec_factory_client_endpoint);
*(reinterpret_cast<zx_handle_t*>(out_buf)) =
codec_factory_client_endpoint.release();
*out_actual = sizeof(zx_handle_t);
return ZX_OK;
}
static zx_protocol_device_t amlogic_video_device_ops = {
DEVICE_OPS_VERSION, .ioctl = amlogic_video_ioctl,
// TODO(jbauman) or TODO(dustingreen): .suspend .resume, maybe .release if
// it would ever be run. Currently ~AmlogicVideo code sets lower power, but
// ~AmlogicVideo doesn't run yet.
};
} // namespace
DeviceCtx::DeviceCtx(DriverCtx* driver)
: driver_(driver),
codec_admission_control_(driver->shared_fidl_loop()->dispatcher()) {
video_ = std::make_unique<AmlogicVideo>();
device_fidl_ = std::make_unique<DeviceFidl>(this);
}
DeviceCtx::~DeviceCtx() {
// TODO(dustingreen): Depending on whether device .release() can get called on
// this deivce, we'll likely need to sequence the shutdown more explicitly.
// This destruction order seems like a reasonable starting point, but is not
// tested:
//
// ~device_fidl_
// ~video_
//
// There are two ways to destroy a fidl::Binding safely:
// * Switch to FIDL thread before Unbind() or ~Binding.
// * async::Loop Quit() + JoinThreads() before Unbind() or ~Binding
//
// For now this code (if implementation needed) will choose the first option
// by destructing DeviceFidl on the FIDL thread. The current way forces this
// thread to wait in this destructor until the shared_fidl_thread() is done
// processing ~DeviceFidl, which means we require that ~DeviceCtx is not
// itself running on the shared_fidl_thread() (or we could check which thread
// here, if we really need to).
//
// For now, it's not clear that we actually need to implement this destructor
// however, since this device is very likely to have a dedicated devhost and
// may not .release() the device - and even if it does .release() the device
// there is no clear need for the cleanup described above to actually be
// implemented.
// TODO(dustingreen): Implement this destructor iff it's actually used/called.
ZX_PANIC("not implemented");
}
zx_status_t DeviceCtx::Bind(zx_device_t* parent) {
device_add_args_t vc_video_args = {};
vc_video_args.version = DEVICE_ADD_ARGS_VERSION;
vc_video_args.name = "amlogic_video";
vc_video_args.ctx = this;
vc_video_args.ops = &amlogic_video_device_ops;
// ZX_PROTOCOL_MEDIA_CODEC causes /dev/class/media-codec to get created, and
// flags support for MEDIA_CODEC_IOCTL_GET_CODEC_FACTORY_CHANNEL. The
// proto_ops_ is empty but has a non-null address, so we don't break the
// invariant that devices with a protocol have non-null proto_ops.
vc_video_args.proto_id = ZX_PROTOCOL_MEDIA_CODEC;
vc_video_args.proto_ops = &proto_ops_;
zx_status_t status = device_add(parent, &vc_video_args, &device_);
if (status != ZX_OK) {
DECODE_ERROR("Failed to bind device");
return ZX_ERR_NO_MEMORY;
}
return ZX_OK;
}