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