1/* arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c 2 * 3 * Verificion code for aDSP VDEC packets from userspace. 4 * 5 * Copyright (c) 2008 QUALCOMM Incorporated 6 * Copyright (C) 2008 Google, Inc. 7 * 8 * This software is licensed under the terms of the GNU General Public 9 * License version 2, as published by the Free Software Foundation, and 10 * may be copied, distributed, and modified under those terms. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 */ 18#include <linux/io.h> 19 20#define ADSP_DEBUG_MSGS 0 21#if ADSP_DEBUG_MSGS 22#define DLOG(fmt,args...) \ 23 do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \ 24 ##args); } \ 25 while (0) 26#else 27#define DLOG(x...) do {} while (0) 28#endif 29 30 31#include <mach/qdsp5/qdsp5vdeccmdi.h> 32#include "adsp.h" 33 34static inline void *high_low_short_to_ptr(unsigned short high, 35 unsigned short low) 36{ 37 return (void *)((((unsigned long)high) << 16) | ((unsigned long)low)); 38} 39 40static inline void ptr_to_high_low_short(void *ptr, unsigned short *high, 41 unsigned short *low) 42{ 43 *high = (unsigned short)((((unsigned long)ptr) >> 16) & 0xffff); 44 *low = (unsigned short)((unsigned long)ptr & 0xffff); 45} 46 47static int pmem_fixup_high_low(unsigned short *high, 48 unsigned short *low, 49 unsigned short size_high, 50 unsigned short size_low, 51 struct msm_adsp_module *module, 52 unsigned long *addr, unsigned long *size) 53{ 54 void *phys_addr; 55 unsigned long phys_size; 56 unsigned long kvaddr; 57 58 phys_addr = high_low_short_to_ptr(*high, *low); 59 phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low); 60 DLOG("virt %x %x\n", phys_addr, phys_size); 61 if (adsp_pmem_fixup_kvaddr(module, &phys_addr, &kvaddr, phys_size)) { 62 DLOG("ah%x al%x sh%x sl%x addr %x size %x\n", 63 *high, *low, size_high, size_low, phys_addr, phys_size); 64 return -1; 65 } 66 ptr_to_high_low_short(phys_addr, high, low); 67 DLOG("phys %x %x\n", phys_addr, phys_size); 68 if (addr) 69 *addr = kvaddr; 70 if (size) 71 *size = phys_size; 72 return 0; 73} 74 75static int verify_vdec_pkt_cmd(struct msm_adsp_module *module, 76 void *cmd_data, size_t cmd_size) 77{ 78 unsigned short cmd_id = ((unsigned short *)cmd_data)[0]; 79 viddec_cmd_subframe_pkt *pkt; 80 unsigned long subframe_pkt_addr; 81 unsigned long subframe_pkt_size; 82 viddec_cmd_frame_header_packet *frame_header_pkt; 83 int i, num_addr, skip; 84 unsigned short *frame_buffer_high, *frame_buffer_low; 85 unsigned long frame_buffer_size; 86 unsigned short frame_buffer_size_high, frame_buffer_size_low; 87 88 DLOG("cmd_size %d cmd_id %d cmd_data %x\n", cmd_size, cmd_id, cmd_data); 89 if (cmd_id != VIDDEC_CMD_SUBFRAME_PKT) { 90 printk(KERN_INFO "adsp_video: unknown video packet %u\n", 91 cmd_id); 92 return 0; 93 } 94 if (cmd_size < sizeof(viddec_cmd_subframe_pkt)) 95 return -1; 96 97 pkt = (viddec_cmd_subframe_pkt *)cmd_data; 98 99 if (pmem_fixup_high_low(&(pkt->subframe_packet_high), 100 &(pkt->subframe_packet_low), 101 pkt->subframe_packet_size_high, 102 pkt->subframe_packet_size_low, 103 module, 104 &subframe_pkt_addr, 105 &subframe_pkt_size)) 106 return -1; 107 108 /* deref those ptrs and check if they are a frame header packet */ 109 frame_header_pkt = (viddec_cmd_frame_header_packet *)subframe_pkt_addr; 110 111 switch (frame_header_pkt->packet_id) { 112 case 0xB201: /* h.264 */ 113 num_addr = skip = 8; 114 break; 115 case 0x4D01: /* mpeg-4 and h.263 */ 116 num_addr = 3; 117 skip = 0; 118 break; 119 default: 120 return 0; 121 } 122 123 frame_buffer_high = &frame_header_pkt->frame_buffer_0_high; 124 frame_buffer_low = &frame_header_pkt->frame_buffer_0_low; 125 frame_buffer_size = (frame_header_pkt->x_dimension * 126 frame_header_pkt->y_dimension * 3) / 2; 127 ptr_to_high_low_short((void *)frame_buffer_size, 128 &frame_buffer_size_high, 129 &frame_buffer_size_low); 130 for (i = 0; i < num_addr; i++) { 131 if (pmem_fixup_high_low(frame_buffer_high, frame_buffer_low, 132 frame_buffer_size_high, 133 frame_buffer_size_low, 134 module, 135 NULL, NULL)) 136 return -1; 137 frame_buffer_high += 2; 138 frame_buffer_low += 2; 139 } 140 /* Patch the output buffer. */ 141 frame_buffer_high += 2*skip; 142 frame_buffer_low += 2*skip; 143 if (pmem_fixup_high_low(frame_buffer_high, frame_buffer_low, 144 frame_buffer_size_high, 145 frame_buffer_size_low, module, NULL, NULL)) 146 return -1; 147 return 0; 148} 149 150int adsp_video_verify_cmd(struct msm_adsp_module *module, 151 unsigned int queue_id, void *cmd_data, 152 size_t cmd_size) 153{ 154 switch (queue_id) { 155 case QDSP_mpuVDecPktQueue: 156 DLOG("\n"); 157 return verify_vdec_pkt_cmd(module, cmd_data, cmd_size); 158 default: 159 printk(KERN_INFO "unknown video queue %u\n", queue_id); 160 return 0; 161 } 162} 163