• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/staging/dream/qdsp5/
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