/* arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c * * Verificion code for aDSP VENC 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 #define ADSP_DEBUG_MSGS 0 #if ADSP_DEBUG_MSGS #define DLOG(fmt,args...) \ do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \ ##args); } \ while (0) #else #define DLOG(x...) do {} while (0) #endif #include #include "adsp.h" static unsigned short x_dimension, y_dimension; static inline void *high_low_short_to_ptr(unsigned short high, unsigned short low) { return (void *)((((unsigned long)high) << 16) | ((unsigned long)low)); } static inline void ptr_to_high_low_short(void *ptr, unsigned short *high, unsigned short *low) { *high = (unsigned short)((((unsigned long)ptr) >> 16) & 0xffff); *low = (unsigned short)((unsigned long)ptr & 0xffff); } static int pmem_fixup_high_low(unsigned short *high, unsigned short *low, unsigned short size_high, unsigned short size_low, struct msm_adsp_module *module, unsigned long *addr, unsigned long *size) { void *phys_addr; unsigned long phys_size; unsigned long kvaddr; phys_addr = high_low_short_to_ptr(*high, *low); phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low); DLOG("virt %x %x\n", phys_addr, phys_size); if (adsp_pmem_fixup_kvaddr(module, &phys_addr, &kvaddr, phys_size)) { DLOG("ah%x al%x sh%x sl%x addr %x size %x\n", *high, *low, size_high, size_low, phys_addr, phys_size); return -1; } ptr_to_high_low_short(phys_addr, high, low); DLOG("phys %x %x\n", phys_addr, phys_size); if (addr) *addr = kvaddr; if (size) *size = phys_size; return 0; } static int verify_venc_cmd(struct msm_adsp_module *module, void *cmd_data, size_t cmd_size) { unsigned short cmd_id = ((unsigned short *)cmd_data)[0]; unsigned long frame_buf_size, luma_buf_size, chroma_buf_size; unsigned short frame_buf_size_high, frame_buf_size_low; unsigned short luma_buf_size_high, luma_buf_size_low; unsigned short chroma_buf_size_high, chroma_buf_size_low; videnc_cmd_cfg *config_cmd; videnc_cmd_frame_start *frame_cmd; videnc_cmd_dis *dis_cmd; DLOG("cmd_size %d cmd_id %d cmd_data %x\n", cmd_size, cmd_id, cmd_data); switch (cmd_id) { case VIDENC_CMD_ACTIVE: if (cmd_size < sizeof(videnc_cmd_active)) return -1; break; case VIDENC_CMD_IDLE: if (cmd_size < sizeof(videnc_cmd_idle)) return -1; x_dimension = y_dimension = 0; break; case VIDENC_CMD_STATUS_QUERY: if (cmd_size < sizeof(videnc_cmd_status_query)) return -1; break; case VIDENC_CMD_RC_CFG: if (cmd_size < sizeof(videnc_cmd_rc_cfg)) return -1; break; case VIDENC_CMD_INTRA_REFRESH: if (cmd_size < sizeof(videnc_cmd_intra_refresh)) return -1; break; case VIDENC_CMD_DIGITAL_ZOOM: if (cmd_size < sizeof(videnc_cmd_digital_zoom)) return -1; break; case VIDENC_CMD_DIS_CFG: if (cmd_size < sizeof(videnc_cmd_dis_cfg)) return -1; break; case VIDENC_CMD_CFG: if (cmd_size < sizeof(videnc_cmd_cfg)) return -1; config_cmd = (videnc_cmd_cfg *)cmd_data; x_dimension = ((config_cmd->venc_frame_dim) & 0xFF00)>>8; x_dimension = x_dimension*16; y_dimension = (config_cmd->venc_frame_dim) & 0xFF; y_dimension = y_dimension * 16; break; case VIDENC_CMD_FRAME_START: if (cmd_size < sizeof(videnc_cmd_frame_start)) return -1; frame_cmd = (videnc_cmd_frame_start *)cmd_data; luma_buf_size = x_dimension * y_dimension; chroma_buf_size = luma_buf_size>>1; frame_buf_size = luma_buf_size + chroma_buf_size; ptr_to_high_low_short((void *)luma_buf_size, &luma_buf_size_high, &luma_buf_size_low); ptr_to_high_low_short((void *)chroma_buf_size, &chroma_buf_size_high, &chroma_buf_size_low); ptr_to_high_low_short((void *)frame_buf_size, &frame_buf_size_high, &frame_buf_size_low); /* Address of raw Y data. */ if (pmem_fixup_high_low(&frame_cmd->input_luma_addr_high, &frame_cmd->input_luma_addr_low, luma_buf_size_high, luma_buf_size_low, module, NULL, NULL)) return -1; /* Address of raw CbCr data */ if (pmem_fixup_high_low(&frame_cmd->input_chroma_addr_high, &frame_cmd->input_chroma_addr_low, chroma_buf_size_high, chroma_buf_size_low, module, NULL, NULL)) return -1; /* Reference VOP */ if (pmem_fixup_high_low(&frame_cmd->ref_vop_buf_ptr_high, &frame_cmd->ref_vop_buf_ptr_low, frame_buf_size_high, frame_buf_size_low, module, NULL, NULL)) return -1; /* Encoded Packet Address */ if (pmem_fixup_high_low(&frame_cmd->enc_pkt_buf_ptr_high, &frame_cmd->enc_pkt_buf_ptr_low, frame_cmd->enc_pkt_buf_size_high, frame_cmd->enc_pkt_buf_size_low, module, NULL, NULL)) return -1; /* Unfiltered VOP Buffer Address */ if (pmem_fixup_high_low( &frame_cmd->unfilt_recon_vop_buf_ptr_high, &frame_cmd->unfilt_recon_vop_buf_ptr_low, frame_buf_size_high, frame_buf_size_low, module, NULL, NULL)) return -1; /* Filtered VOP Buffer Address */ if (pmem_fixup_high_low(&frame_cmd->filt_recon_vop_buf_ptr_high, &frame_cmd->filt_recon_vop_buf_ptr_low, frame_buf_size_high, frame_buf_size_low, module, NULL, NULL)) return -1; break; case VIDENC_CMD_DIS: if (cmd_size < sizeof(videnc_cmd_dis)) return -1; dis_cmd = (videnc_cmd_dis *)cmd_data; luma_buf_size = x_dimension * y_dimension; ptr_to_high_low_short((void *)luma_buf_size, &luma_buf_size_high, &luma_buf_size_low); /* Prev VFE Luma Output Address */ if (pmem_fixup_high_low(&dis_cmd->vfe_out_prev_luma_addr_high, &dis_cmd->vfe_out_prev_luma_addr_low, luma_buf_size_high, luma_buf_size_low, module, NULL, NULL)) return -1; break; default: printk(KERN_INFO "adsp_video:unknown encoder video command %u\n", cmd_id); return 0; } return 0; } int adsp_videoenc_verify_cmd(struct msm_adsp_module *module, unsigned int queue_id, void *cmd_data, size_t cmd_size) { switch (queue_id) { case QDSP_mpuVEncCmdQueue: DLOG("\n"); return verify_venc_cmd(module, cmd_data, cmd_size); default: printk(KERN_INFO "unknown video queue %u\n", queue_id); return 0; } }