/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/hash.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <media/videobuf2-v4l2.h>
#include "core.h"
#include "hfi.h"
#include "hfi_helper.h"
#include "hfi_msgs.h"
static void event_seq_changed(struct venus_core *core, struct venus_inst *inst,
struct hfi_msg_event_notify_pkt *pkt)
{
struct hfi_event_data event = {0};
int num_properties_changed;
struct hfi_framesize *frame_sz;
struct hfi_profile_level *profile_level;
u8 *data_ptr;
u32 ptype;
inst->error = HFI_ERR_NONE;
switch (pkt->event_data1) {
case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES:
case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES:
break;
default:
inst->error = HFI_ERR_SESSION_INVALID_PARAMETER;
goto done;
}
event.event_type = pkt->event_data1;
num_properties_changed = pkt->event_data2;
if (!num_properties_changed) {
inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES;
goto done;
}
data_ptr = (u8 *)&pkt->ext_event_data[0];
do {
ptype = *((u32 *)data_ptr);
switch (ptype) {
case HFI_PROPERTY_PARAM_FRAME_SIZE:
data_ptr += sizeof(u32);
frame_sz = (struct hfi_framesize *)data_ptr;
event.width = frame_sz->width;
event.height = frame_sz->height;
data_ptr += sizeof(*frame_sz);
break;
case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
data_ptr += sizeof(u32);
profile_level = (struct hfi_profile_level *)data_ptr;
event.profile = profile_level->profile;
event.level = profile_level->level;
data_ptr += sizeof(*profile_level);
break;
default:
break;
}
num_properties_changed--;
} while (num_properties_changed > 0);
done:
inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
}
static void event_release_buffer_ref(struct venus_core *core,
struct venus_inst *inst,
struct hfi_msg_event_notify_pkt *pkt)
{
struct hfi_event_data event = {0};
struct hfi_msg_event_release_buffer_ref_pkt *data;
data = (struct hfi_msg_event_release_buffer_ref_pkt *)
pkt->ext_event_data;
event.event_type = HFI_EVENT_RELEASE_BUFFER_REFERENCE;
event.packet_buffer = data->packet_buffer;
event.extradata_buffer = data->extradata_buffer;
event.tag = data->output_tag;
inst->error = HFI_ERR_NONE;
inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
}
static void event_sys_error(struct venus_core *core, u32 event,
struct hfi_msg_event_notify_pkt *pkt)
{
if (pkt)
dev_dbg(core->dev,
"sys error (session id:%x, data1:%x, data2:%x)\n",
pkt->shdr.session_id, pkt->event_data1,
pkt->event_data2);
core->core_ops->event_notify(core, event);
}
static void
event_session_error(struct venus_core *core, struct venus_inst *inst,
struct hfi_msg_event_notify_pkt *pkt)
{
struct device *dev = core->dev;
dev_dbg(dev, "session error: event id:%x, session id:%x\n",
pkt->event_data1, pkt->shdr.session_id);
if (!inst)
return;
switch (pkt->event_data1) {
/* non fatal session errors */
case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE