1 /******************************************************************************
2 *
3 * Copyright (C) 2003-2013 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18 #include <string.h>
19 #include "common/bt_target.h"
20 #include "stack/avrc_api.h"
21 #include "stack/avrc_defs.h"
22 #include "avrc_int.h"
23
24 #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE)
25
26 /*****************************************************************************
27 ** Global data
28 *****************************************************************************/
29 #if (AVRC_METADATA_INCLUDED == TRUE)
30
31 /*******************************************************************************
32 **
33 ** Function avrc_pars_vendor_cmd
34 **
35 ** Description This function parses the vendor specific commands defined by
36 ** Bluetooth SIG
37 **
38 ** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
39 ** Otherwise, the error code defined by AVRCP 1.4
40 **
41 *******************************************************************************/
avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR * p_msg,tAVRC_COMMAND * p_result,UINT8 * p_buf,UINT16 buf_len)42 static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result,
43 UINT8 *p_buf, UINT16 buf_len)
44 {
45 tAVRC_STS status = AVRC_STS_NO_ERROR;
46 UINT8 *p;
47 UINT16 len;
48 UINT8 xx, yy;
49 UINT8 *p_u8;
50 UINT16 *p_u16;
51 UINT32 u32, u32_2, *p_u32;
52 tAVRC_APP_SETTING *p_app_set;
53 UINT16 size_needed;
54
55 /* Check the vendor data */
56 if (p_msg->vendor_len == 0) {
57 return AVRC_STS_NO_ERROR;
58 }
59 if (p_msg->p_vendor_data == NULL) {
60 return AVRC_STS_INTERNAL_ERR;
61 }
62
63 p = p_msg->p_vendor_data;
64 p_result->pdu = *p++;
65 AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() pdu:0x%x", p_result->pdu);
66 if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype)) {
67 AVRC_TRACE_DEBUG("avrc_pars_vendor_cmd() detects wrong AV/C type!");
68 status = AVRC_STS_BAD_CMD;
69 }
70
71 p++; /* skip the reserved byte */
72 BE_STREAM_TO_UINT16 (len, p);
73 if ((len + 4) != (p_msg->vendor_len)) {
74 status = AVRC_STS_INTERNAL_ERR;
75 }
76
77 if (status != AVRC_STS_NO_ERROR) {
78 return status;
79 }
80
81 switch (p_result->pdu) {
82 case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */
83 p_result->get_caps.capability_id = *p++;
84 if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id)) {
85 status = AVRC_STS_BAD_PARAM;
86 } else if (len != 1) {
87 status = AVRC_STS_INTERNAL_ERR;
88 }
89 break;
90
91 case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */
92 /* no additional parameters */
93 if (len != 0) {
94 status = AVRC_STS_INTERNAL_ERR;
95 }
96 break;
97
98 case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */
99 p_result->list_app_values.attr_id = *p++;
100 if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id)) {
101 status = AVRC_STS_BAD_PARAM;
102 } else if (len != 1) {
103 status = AVRC_STS_INTERNAL_ERR;
104 }
105 break;
106
107 case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
108 case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
109 BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p);
110 if (len != (p_result->get_cur_app_val.num_attr + 1)) {
111 status = AVRC_STS_INTERNAL_ERR;
112 break;
113 }
114 p_u8 = p_result->get_cur_app_val.attrs;
115 for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) {
116 /* only report the valid player app attributes */
117 if (AVRC_IsValidPlayerAttr(*p)) {
118 p_u8[yy++] = *p;
119 }
120 p++;
121 }
122 p_result->get_cur_app_val.num_attr = yy;
123 if (yy == 0) {
124 status = AVRC_STS_BAD_PARAM;
125 }
126 break;
127
128 case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
129 BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p);
130 size_needed = sizeof(tAVRC_APP_SETTING);
131 if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) {
132 p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf;
133 p_app_set = p_result->set_app_val.p_vals;
134 for (xx = 0; ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++) {
135 p_app_set[xx].attr_id = *p++;
136 p_app_set[xx].attr_val = *p++;
137 if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id, p_app_set[xx].attr_val)) {
138 status = AVRC_STS_BAD_PARAM;
139 }
140 }
141 if (xx != p_result->set_app_val.num_val) {
142 AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
143 xx, p_result->set_app_val.num_val);
144 p_result->set_app_val.num_val = xx;
145 }
146 } else {
147 AVRC_TRACE_ERROR("AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len");
148 status = AVRC_STS_INTERNAL_ERR;
149 }
150 break;
151
152 case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:/* 0x16 */
153 if (len < 3) {
154 status = AVRC_STS_INTERNAL_ERR;
155 } else {
156 BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.attr_id, p);
157 if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id)) {
158 status = AVRC_STS_BAD_PARAM;
159 } else {
160 BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.num_val, p);
161 if ( (len - 2/* attr_id & num_val */) != p_result->get_app_val_txt.num_val) {
162 status = AVRC_STS_INTERNAL_ERR;
163 } else {
164 p_u8 = p_result->get_app_val_txt.vals;
165 for (xx = 0; xx < p_result->get_app_val_txt.num_val; xx++) {
166 p_u8[xx] = *p++;
167 if (!avrc_is_valid_player_attrib_value(p_result->get_app_val_txt.attr_id,
168 p_u8[xx])) {
169 status = AVRC_STS_BAD_PARAM;
170 break;
171 }
172 }
173 }
174 }
175 }
176 break;
177
178 case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */
179 if (len < 3) {
180 status = AVRC_STS_INTERNAL_ERR;
181 } else {
182 BE_STREAM_TO_UINT8 (p_result->inform_charset.num_id, p);
183 if ( (len - 1/* num_id */) != p_result->inform_charset.num_id * 2) {
184 status = AVRC_STS_INTERNAL_ERR;
185 } else {
186 p_u16 = p_result->inform_charset.charsets;
187 if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE) {
188 p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE;
189 }
190 for (xx = 0; xx < p_result->inform_charset.num_id; xx++) {
191 BE_STREAM_TO_UINT16 (p_u16[xx], p);
192 }
193 }
194 }
195 break;
196
197 case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:/* 0x18 */
198 if (len != 1) {
199 status = AVRC_STS_INTERNAL_ERR;
200 } else {
201 p_result->inform_battery_status.battery_status = *p++;
202 if (!AVRC_IS_VALID_BATTERY_STATUS(p_result->inform_battery_status.battery_status)) {
203 status = AVRC_STS_BAD_PARAM;
204 }
205 }
206 break;
207
208 case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
209 if (len < 9) { /* UID/8 and num_attr/1 */
210 status = AVRC_STS_INTERNAL_ERR;
211 } else {
212 BE_STREAM_TO_UINT32 (u32, p);
213 BE_STREAM_TO_UINT32 (u32_2, p);
214 if (u32 == 0 && u32_2 == 0) {
215 BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p);
216 if ( (len - 9/* UID/8 and num_attr/1 */) != (p_result->get_elem_attrs.num_attr * 4)) {
217 status = AVRC_STS_INTERNAL_ERR;
218 } else {
219 p_u32 = p_result->get_elem_attrs.attrs;
220 if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE) {
221 p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE;
222 }
223 for (xx = 0; xx < p_result->get_elem_attrs.num_attr; xx++) {
224 BE_STREAM_TO_UINT32 (p_u32[xx], p);
225 }
226 }
227 } else {
228 status = AVRC_STS_NOT_FOUND;
229 }
230 }
231 break;
232
233 case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */
234 /* no additional parameters */
235 if (len != 0) {
236 status = AVRC_STS_INTERNAL_ERR;
237 }
238 break;
239
240 case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
241 if (len != 5) {
242 status = AVRC_STS_INTERNAL_ERR;
243 } else {
244 BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p);
245 BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p);
246 }
247 break;
248
249 case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
250 if (len != 1) {
251 status = AVRC_STS_INTERNAL_ERR;
252 } else {
253 BE_STREAM_TO_UINT8 (p_result->volume.volume, p);
254 p_result->volume.volume &= 0x7F; // remove the top bit
255 }
256 break;
257 }
258
259 /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
260 /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */
261
262 default:
263 status = AVRC_STS_BAD_CMD;
264 break;
265 }
266
267 return status;
268 }
269
270 /*******************************************************************************
271 **
272 ** Function AVRC_ParsCommand
273 **
274 ** Description This function is a superset of AVRC_ParsMetadata to parse the command.
275 **
276 ** Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
277 ** Otherwise, the error code defined by AVRCP 1.4
278 **
279 *******************************************************************************/
AVRC_ParsCommand(tAVRC_MSG * p_msg,tAVRC_COMMAND * p_result,UINT8 * p_buf,UINT16 buf_len)280 tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_buf, UINT16 buf_len)
281 {
282 tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
283 UINT16 id;
284
285 if (p_msg && p_result) {
286 switch (p_msg->hdr.opcode) {
287 case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
288 status = avrc_pars_vendor_cmd(&p_msg->vendor, p_result, p_buf, buf_len);
289 break;
290
291 case AVRC_OP_PASS_THRU: /* 0x7C panel subunit opcode */
292 status = avrc_pars_pass_thru(&p_msg->pass, &id);
293 if (status == AVRC_STS_NO_ERROR) {
294 p_result->pdu = (UINT8)id;
295 }
296 break;
297
298 default:
299 AVRC_TRACE_ERROR("AVRC_ParsCommand() unknown opcode:0x%x", p_msg->hdr.opcode);
300 break;
301 }
302 p_result->cmd.opcode = p_msg->hdr.opcode;
303 p_result->cmd.status = status;
304 }
305 AVRC_TRACE_DEBUG("AVRC_ParsCommand() return status:0x%x", status);
306 return status;
307 }
308
309 #endif /* (AVRC_METADATA_INCLUDED == TRUE) */
310
311 #endif /* #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) */
312