![Iliyan Malchev](/assets/img/avatar_default.png)
QDSP code is neccessarry for communication with some hardware components on HTC Dream, including camera hardware. It also drives DSP coproccessor. Signed-off-by: Pavel Machek <pavel@ucw.cz> Cc: Brian Swetland <swetland@google.com> Cc: Iliyan Malchev <ibm@android.com> Cc: San Mehat <san@android.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
240 lines
6.8 KiB
C
240 lines
6.8 KiB
C
/* arch/arm/mach-msm/qdsp5/adsp_vfe_verify_cmd.c
|
|
*
|
|
* Verification code for aDSP VFE packets from userspace.
|
|
*
|
|
* Copyright (c) 2008 QUALCOMM Incorporated
|
|
* Copyright (C) 2008 Google, Inc.
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* 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 <mach/qdsp5/qdsp5vfecmdi.h>
|
|
#include "adsp.h"
|
|
|
|
static uint32_t size1_y, size2_y, size1_cbcr, size2_cbcr;
|
|
static uint32_t af_size = 4228;
|
|
static uint32_t awb_size = 8196;
|
|
|
|
static inline int verify_cmd_op_ack(struct msm_adsp_module *module,
|
|
void *cmd_data, size_t cmd_size)
|
|
{
|
|
vfe_cmd_op1_ack *cmd = (vfe_cmd_op1_ack *)cmd_data;
|
|
void **addr_y = (void **)&cmd->op1_buf_y_addr;
|
|
void **addr_cbcr = (void **)(&cmd->op1_buf_cbcr_addr);
|
|
|
|
if (cmd_size != sizeof(vfe_cmd_op1_ack))
|
|
return -1;
|
|
if ((*addr_y && adsp_pmem_fixup(module, addr_y, size1_y)) ||
|
|
(*addr_cbcr && adsp_pmem_fixup(module, addr_cbcr, size1_cbcr)))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static inline int verify_cmd_stats_autofocus_cfg(struct msm_adsp_module *module,
|
|
void *cmd_data, size_t cmd_size)
|
|
{
|
|
int i;
|
|
vfe_cmd_stats_autofocus_cfg *cmd =
|
|
(vfe_cmd_stats_autofocus_cfg *)cmd_data;
|
|
|
|
if (cmd_size != sizeof(vfe_cmd_stats_autofocus_cfg))
|
|
return -1;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
void **addr = (void **)(&cmd->af_stats_op_buf[i]);
|
|
if (*addr && adsp_pmem_fixup(module, addr, af_size))
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline int verify_cmd_stats_wb_exp_cfg(struct msm_adsp_module *module,
|
|
void *cmd_data, size_t cmd_size)
|
|
{
|
|
vfe_cmd_stats_wb_exp_cfg *cmd =
|
|
(vfe_cmd_stats_wb_exp_cfg *)cmd_data;
|
|
int i;
|
|
|
|
if (cmd_size != sizeof(vfe_cmd_stats_wb_exp_cfg))
|
|
return -1;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
void **addr = (void **)(&cmd->wb_exp_stats_op_buf[i]);
|
|
if (*addr && adsp_pmem_fixup(module, addr, awb_size))
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline int verify_cmd_stats_af_ack(struct msm_adsp_module *module,
|
|
void *cmd_data, size_t cmd_size)
|
|
{
|
|
vfe_cmd_stats_af_ack *cmd = (vfe_cmd_stats_af_ack *)cmd_data;
|
|
void **addr = (void **)&cmd->af_stats_op_buf;
|
|
|
|
if (cmd_size != sizeof(vfe_cmd_stats_af_ack))
|
|
return -1;
|
|
|
|
if (*addr && adsp_pmem_fixup(module, addr, af_size))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static inline int verify_cmd_stats_wb_exp_ack(struct msm_adsp_module *module,
|
|
void *cmd_data, size_t cmd_size)
|
|
{
|
|
vfe_cmd_stats_wb_exp_ack *cmd =
|
|
(vfe_cmd_stats_wb_exp_ack *)cmd_data;
|
|
void **addr = (void **)&cmd->wb_exp_stats_op_buf;
|
|
|
|
if (cmd_size != sizeof(vfe_cmd_stats_wb_exp_ack))
|
|
return -1;
|
|
|
|
if (*addr && adsp_pmem_fixup(module, addr, awb_size))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int verify_vfe_command(struct msm_adsp_module *module,
|
|
void *cmd_data, size_t cmd_size)
|
|
{
|
|
uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
|
|
switch (cmd_id) {
|
|
case VFE_CMD_OP1_ACK:
|
|
return verify_cmd_op_ack(module, cmd_data, cmd_size);
|
|
case VFE_CMD_OP2_ACK:
|
|
return verify_cmd_op_ack(module, cmd_data, cmd_size);
|
|
case VFE_CMD_STATS_AUTOFOCUS_CFG:
|
|
return verify_cmd_stats_autofocus_cfg(module, cmd_data,
|
|
cmd_size);
|
|
case VFE_CMD_STATS_WB_EXP_CFG:
|
|
return verify_cmd_stats_wb_exp_cfg(module, cmd_data, cmd_size);
|
|
case VFE_CMD_STATS_AF_ACK:
|
|
return verify_cmd_stats_af_ack(module, cmd_data, cmd_size);
|
|
case VFE_CMD_STATS_WB_EXP_ACK:
|
|
return verify_cmd_stats_wb_exp_ack(module, cmd_data, cmd_size);
|
|
default:
|
|
if (cmd_id > 29) {
|
|
printk(KERN_ERR "adsp: module %s: invalid VFE command id %d\n", module->name, cmd_id);
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int verify_vfe_command_scale(struct msm_adsp_module *module,
|
|
void *cmd_data, size_t cmd_size)
|
|
{
|
|
uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
|
|
// FIXME: check the size
|
|
if (cmd_id > 1) {
|
|
printk(KERN_ERR "adsp: module %s: invalid VFE SCALE command id %d\n", module->name, cmd_id);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static uint32_t get_size(uint32_t hw)
|
|
{
|
|
uint32_t height, width;
|
|
uint32_t height_mask = 0x3ffc;
|
|
uint32_t width_mask = 0x3ffc000;
|
|
|
|
height = (hw & height_mask) >> 2;
|
|
width = (hw & width_mask) >> 14 ;
|
|
return height * width;
|
|
}
|
|
|
|
static int verify_vfe_command_table(struct msm_adsp_module *module,
|
|
void *cmd_data, size_t cmd_size)
|
|
{
|
|
uint32_t cmd_id = ((uint32_t *)cmd_data)[0];
|
|
int i;
|
|
|
|
switch (cmd_id) {
|
|
case VFE_CMD_AXI_IP_CFG:
|
|
{
|
|
vfe_cmd_axi_ip_cfg *cmd = (vfe_cmd_axi_ip_cfg *)cmd_data;
|
|
uint32_t size;
|
|
if (cmd_size != sizeof(vfe_cmd_axi_ip_cfg)) {
|
|
printk(KERN_ERR "adsp: module %s: invalid VFE TABLE (VFE_CMD_AXI_IP_CFG) command size %d\n",
|
|
module->name, cmd_size);
|
|
return -1;
|
|
}
|
|
size = get_size(cmd->ip_cfg_part2);
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
void **addr = (void **)
|
|
&cmd->ip_buf_addr[i];
|
|
if (*addr && adsp_pmem_fixup(module, addr, size))
|
|
return -1;
|
|
}
|
|
}
|
|
case VFE_CMD_AXI_OP_CFG:
|
|
{
|
|
vfe_cmd_axi_op_cfg *cmd = (vfe_cmd_axi_op_cfg *)cmd_data;
|
|
void **addr1_y, **addr2_y, **addr1_cbcr, **addr2_cbcr;
|
|
|
|
if (cmd_size != sizeof(vfe_cmd_axi_op_cfg)) {
|
|
printk(KERN_ERR "adsp: module %s: invalid VFE TABLE (VFE_CMD_AXI_OP_CFG) command size %d\n",
|
|
module->name, cmd_size);
|
|
return -1;
|
|
}
|
|
size1_y = get_size(cmd->op1_y_cfg_part2);
|
|
size1_cbcr = get_size(cmd->op1_cbcr_cfg_part2);
|
|
size2_y = get_size(cmd->op2_y_cfg_part2);
|
|
size2_cbcr = get_size(cmd->op2_cbcr_cfg_part2);
|
|
for (i = 0; i < 8; i++) {
|
|
addr1_y = (void **)(&cmd->op1_buf1_addr[2*i]);
|
|
addr1_cbcr = (void **)(&cmd->op1_buf1_addr[2*i+1]);
|
|
addr2_y = (void **)(&cmd->op2_buf1_addr[2*i]);
|
|
addr2_cbcr = (void **)(&cmd->op2_buf1_addr[2*i+1]);
|
|
/*
|
|
printk("module %s: [%d] %p %p %p %p\n",
|
|
module->name, i,
|
|
*addr1_y, *addr1_cbcr, *addr2_y, *addr2_cbcr);
|
|
*/
|
|
if ((*addr1_y && adsp_pmem_fixup(module, addr1_y, size1_y)) ||
|
|
(*addr1_cbcr && adsp_pmem_fixup(module, addr1_cbcr, size1_cbcr)) ||
|
|
(*addr2_y && adsp_pmem_fixup(module, addr2_y, size2_y)) ||
|
|
(*addr2_cbcr && adsp_pmem_fixup(module, addr2_cbcr, size2_cbcr)))
|
|
return -1;
|
|
}
|
|
}
|
|
default:
|
|
if (cmd_id > 4) {
|
|
printk(KERN_ERR "adsp: module %s: invalid VFE TABLE command id %d\n",
|
|
module->name, cmd_id);
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int adsp_vfe_verify_cmd(struct msm_adsp_module *module,
|
|
unsigned int queue_id, void *cmd_data,
|
|
size_t cmd_size)
|
|
{
|
|
switch (queue_id) {
|
|
case QDSP_vfeCommandQueue:
|
|
return verify_vfe_command(module, cmd_data, cmd_size);
|
|
case QDSP_vfeCommandScaleQueue:
|
|
return verify_vfe_command_scale(module, cmd_data, cmd_size);
|
|
case QDSP_vfeCommandTableQueue:
|
|
return verify_vfe_command_table(module, cmd_data, cmd_size);
|
|
default:
|
|
printk(KERN_ERR "adsp: module %s: unknown queue id %d\n",
|
|
module->name, queue_id);
|
|
return -1;
|
|
}
|
|
}
|