]>
Commit | Line | Data |
---|---|---|
caff4cae IM |
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 | ||
34 | static 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 | ||
40 | static 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 | ||
47 | static 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 | ||
75 | static 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 | ||
150 | int 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 |