1 /******************************************************************************
2 *
3 * Copyright 2003-2016 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 "avrc_api.h"
21 #include "avrc_defs.h"
22 #include "avrc_int.h"
23 #include "bt_common.h"
24 #include "log/log.h"
25
26 /*****************************************************************************
27 * Global data
28 ****************************************************************************/
29
30 /*******************************************************************************
31 *
32 * Function avrc_ctrl_pars_vendor_cmd
33 *
34 * Description This function parses the vendor specific commands defined by
35 * Bluetooth SIG for AVRCP Conroller.
36 *
37 * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
38 * successfully.
39 * Otherwise, the error code defined by AVRCP 1.4
40 *
41 ******************************************************************************/
avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR * p_msg,tAVRC_COMMAND * p_result)42 static tAVRC_STS avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg,
43 tAVRC_COMMAND* p_result) {
44 tAVRC_STS status = AVRC_STS_NO_ERROR;
45
46 uint8_t* p = p_msg->p_vendor_data;
47 p_result->pdu = *p++;
48 AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
49 if (!AVRC_IsValidAvcType(p_result->pdu, p_msg->hdr.ctype)) {
50 AVRC_TRACE_DEBUG("%s detects wrong AV/C type!", __func__);
51 status = AVRC_STS_BAD_CMD;
52 }
53
54 p++; /* skip the reserved byte */
55 uint16_t len;
56 BE_STREAM_TO_UINT16(len, p);
57 if ((len + 4) != (p_msg->vendor_len)) {
58 status = AVRC_STS_INTERNAL_ERR;
59 }
60
61 if (status != AVRC_STS_NO_ERROR) return status;
62
63 switch (p_result->pdu) {
64 case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
65 if (len != 1)
66 status = AVRC_STS_INTERNAL_ERR;
67 else {
68 BE_STREAM_TO_UINT8(p_result->volume.volume, p);
69 p_result->volume.volume = AVRC_MAX_VOLUME & p_result->volume.volume;
70 }
71 break;
72 }
73 case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
74 BE_STREAM_TO_UINT8(p_result->reg_notif.event_id, p);
75 BE_STREAM_TO_UINT32(p_result->reg_notif.param, p);
76 break;
77 default:
78 status = AVRC_STS_BAD_CMD;
79 break;
80 }
81 return status;
82 }
83
84 /*******************************************************************************
85 *
86 * Function avrc_pars_vendor_cmd
87 *
88 * Description This function parses the vendor specific commands defined by
89 * Bluetooth SIG
90 *
91 * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
92 * successfully.
93 * Otherwise, the error code defined by AVRCP 1.4
94 *
95 ******************************************************************************/
avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR * p_msg,tAVRC_COMMAND * p_result,uint8_t * p_buf,uint16_t buf_len)96 static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg,
97 tAVRC_COMMAND* p_result, uint8_t* p_buf,
98 uint16_t buf_len) {
99 tAVRC_STS status = AVRC_STS_NO_ERROR;
100 uint8_t* p;
101 uint16_t len;
102 uint8_t xx, yy;
103 uint8_t* p_u8;
104 uint16_t* p_u16;
105 uint32_t u32, u32_2, *p_u32;
106 tAVRC_APP_SETTING* p_app_set;
107 uint16_t size_needed;
108
109 /* Check the vendor data */
110 if (p_msg->vendor_len == 0) return AVRC_STS_NO_ERROR;
111 if (p_msg->p_vendor_data == NULL) return AVRC_STS_INTERNAL_ERR;
112
113 p = p_msg->p_vendor_data;
114 p_result->pdu = *p++;
115 AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
116 if (!AVRC_IsValidAvcType(p_result->pdu, p_msg->hdr.ctype)) {
117 AVRC_TRACE_DEBUG("%s detects wrong AV/C type(0x%x)!", __func__,
118 p_msg->hdr.ctype);
119 status = AVRC_STS_BAD_CMD;
120 }
121
122 p++; /* skip the reserved byte */
123 BE_STREAM_TO_UINT16(len, p);
124 if ((len + 4) != (p_msg->vendor_len)) {
125 AVRC_TRACE_ERROR("%s incorrect length :%d, %d", __func__, len,
126 p_msg->vendor_len);
127 status = AVRC_STS_INTERNAL_ERR;
128 }
129
130 if (status != AVRC_STS_NO_ERROR) return status;
131
132 switch (p_result->pdu) {
133 case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */
134 p_result->get_caps.capability_id = *p++;
135 if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id))
136 status = AVRC_STS_BAD_PARAM;
137 else if (len != 1)
138 status = AVRC_STS_INTERNAL_ERR;
139 break;
140
141 case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */
142 /* no additional parameters */
143 if (len != 0) status = AVRC_STS_INTERNAL_ERR;
144 break;
145
146 case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */
147 p_result->list_app_values.attr_id = *p++;
148 if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id))
149 status = AVRC_STS_BAD_PARAM;
150 else if (len != 1)
151 status = AVRC_STS_INTERNAL_ERR;
152 break;
153
154 case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
155 case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
156 BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_attr, p);
157 if (len != (p_result->get_cur_app_val.num_attr + 1)) {
158 status = AVRC_STS_INTERNAL_ERR;
159 break;
160 }
161
162 if (p_result->get_cur_app_val.num_attr > AVRC_MAX_APP_ATTR_SIZE) {
163 android_errorWriteLog(0x534e4554, "63146237");
164 p_result->get_cur_app_val.num_attr = AVRC_MAX_APP_ATTR_SIZE;
165 }
166
167 p_u8 = p_result->get_cur_app_val.attrs;
168 for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) {
169 /* only report the valid player app attributes */
170 if (AVRC_IsValidPlayerAttr(*p)) p_u8[yy++] = *p;
171 p++;
172 }
173 p_result->get_cur_app_val.num_attr = yy;
174 if (yy == 0) {
175 status = AVRC_STS_BAD_PARAM;
176 }
177 break;
178
179 case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
180 BE_STREAM_TO_UINT8(p_result->set_app_val.num_val, p);
181 size_needed = sizeof(tAVRC_APP_SETTING);
182 if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) {
183 p_result->set_app_val.p_vals = (tAVRC_APP_SETTING*)p_buf;
184 p_app_set = p_result->set_app_val.p_vals;
185 for (xx = 0;
186 ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed));
187 xx++) {
188 p_app_set[xx].attr_id = *p++;
189 p_app_set[xx].attr_val = *p++;
190 if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id,
191 p_app_set[xx].attr_val))
192 status = AVRC_STS_BAD_PARAM;
193 }
194 if (xx != p_result->set_app_val.num_val) {
195 AVRC_TRACE_ERROR(
196 "%s AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig "
197 "num_val:%d",
198 __func__, xx, p_result->set_app_val.num_val);
199 p_result->set_app_val.num_val = xx;
200 }
201 } else {
202 AVRC_TRACE_ERROR(
203 "%s AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len",
204 __func__);
205 status = AVRC_STS_INTERNAL_ERR;
206 }
207 break;
208
209 case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: /* 0x16 */
210 if (len < 3)
211 status = AVRC_STS_INTERNAL_ERR;
212 else {
213 BE_STREAM_TO_UINT8(p_result->get_app_val_txt.attr_id, p);
214 if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id))
215 status = AVRC_STS_BAD_PARAM;
216 else {
217 BE_STREAM_TO_UINT8(p_result->get_app_val_txt.num_val, p);
218 if ((len - 2 /* attr_id & num_val */) !=
219 p_result->get_app_val_txt.num_val)
220 status = AVRC_STS_INTERNAL_ERR;
221 else {
222 if (p_result->get_app_val_txt.num_val > AVRC_MAX_APP_ATTR_SIZE) {
223 android_errorWriteLog(0x534e4554, "63146237");
224 p_result->get_app_val_txt.num_val = AVRC_MAX_APP_ATTR_SIZE;
225 }
226
227 p_u8 = p_result->get_app_val_txt.vals;
228 for (xx = 0; xx < p_result->get_app_val_txt.num_val; xx++) {
229 p_u8[xx] = *p++;
230 if (!avrc_is_valid_player_attrib_value(
231 p_result->get_app_val_txt.attr_id, p_u8[xx])) {
232 status = AVRC_STS_BAD_PARAM;
233 break;
234 }
235 }
236 }
237 }
238 }
239 break;
240
241 case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */
242 if (len < 3)
243 status = AVRC_STS_INTERNAL_ERR;
244 else {
245 BE_STREAM_TO_UINT8(p_result->inform_charset.num_id, p);
246 if ((len - 1 /* num_id */) != p_result->inform_charset.num_id * 2)
247 status = AVRC_STS_INTERNAL_ERR;
248 else {
249 p_u16 = p_result->inform_charset.charsets;
250 if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE)
251 p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE;
252 for (xx = 0; xx < p_result->inform_charset.num_id; xx++) {
253 BE_STREAM_TO_UINT16(p_u16[xx], p);
254 }
255 }
256 }
257 break;
258
259 case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: /* 0x18 */
260 if (len != 1)
261 status = AVRC_STS_INTERNAL_ERR;
262 else {
263 p_result->inform_battery_status.battery_status = *p++;
264 if (!AVRC_IS_VALID_BATTERY_STATUS(
265 p_result->inform_battery_status.battery_status))
266 status = AVRC_STS_BAD_PARAM;
267 }
268 break;
269
270 case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
271 if (len < 9) /* UID/8 and num_attr/1 */
272 status = AVRC_STS_INTERNAL_ERR;
273 else {
274 BE_STREAM_TO_UINT32(u32, p);
275 BE_STREAM_TO_UINT32(u32_2, p);
276 if (u32 == 0 && u32_2 == 0) {
277 BE_STREAM_TO_UINT8(p_result->get_elem_attrs.num_attr, p);
278 if ((len - 9 /* UID/8 and num_attr/1 */) !=
279 (p_result->get_elem_attrs.num_attr * 4))
280 status = AVRC_STS_INTERNAL_ERR;
281 else {
282 p_u32 = p_result->get_elem_attrs.attrs;
283 if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE)
284 p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE;
285 for (xx = 0; xx < p_result->get_elem_attrs.num_attr; xx++) {
286 BE_STREAM_TO_UINT32(p_u32[xx], p);
287 }
288 }
289 } else
290 status = AVRC_STS_NOT_FOUND;
291 }
292 break;
293
294 case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */
295 /* no additional parameters */
296 if (len != 0) status = AVRC_STS_INTERNAL_ERR;
297 break;
298
299 case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
300 if (len != 5)
301 status = AVRC_STS_INTERNAL_ERR;
302 else {
303 BE_STREAM_TO_UINT8(p_result->reg_notif.event_id, p);
304 BE_STREAM_TO_UINT32(p_result->reg_notif.param, p);
305 }
306 break;
307
308 case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
309 if (len != 1)
310 status = AVRC_STS_INTERNAL_ERR;
311 else
312 p_result->volume.volume = *p++;
313 break;
314
315 case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
316 if (len != 1) {
317 status = AVRC_STS_INTERNAL_ERR;
318 }
319 BE_STREAM_TO_UINT8(p_result->continu.target_pdu, p);
320 break;
321
322 case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
323 if (len != 1) {
324 status = AVRC_STS_INTERNAL_ERR;
325 }
326 BE_STREAM_TO_UINT8(p_result->abort.target_pdu, p);
327 break;
328
329 case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */
330 if (len != 2) {
331 AVRC_TRACE_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER length is incorrect:%d",
332 len);
333 status = AVRC_STS_INTERNAL_ERR;
334 }
335 BE_STREAM_TO_UINT16(p_result->addr_player.player_id, p);
336 break;
337
338 case AVRC_PDU_PLAY_ITEM: /* 0x74 */
339 case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
340 if (len != (AVRC_UID_SIZE + 3)) status = AVRC_STS_INTERNAL_ERR;
341 BE_STREAM_TO_UINT8(p_result->play_item.scope, p);
342 if (p_result->play_item.scope > AVRC_SCOPE_NOW_PLAYING) {
343 status = AVRC_STS_BAD_SCOPE;
344 }
345 BE_STREAM_TO_ARRAY(p, p_result->play_item.uid, AVRC_UID_SIZE);
346 BE_STREAM_TO_UINT16(p_result->play_item.uid_counter, p);
347 break;
348
349 default:
350 status = AVRC_STS_BAD_CMD;
351 break;
352 }
353
354 return status;
355 }
356
357 /*******************************************************************************
358 *
359 * Function AVRC_Ctrl_ParsCommand
360 *
361 * Description This function is used to parse cmds received for CTRL
362 * Currently it is for SetAbsVolume and Volume Change
363 * Notification..
364 *
365 * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
366 * successfully.
367 * Otherwise, the error code defined by AVRCP 1.4
368 *
369 ******************************************************************************/
AVRC_Ctrl_ParsCommand(tAVRC_MSG * p_msg,tAVRC_COMMAND * p_result)370 tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) {
371 tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
372
373 if (p_msg && p_result) {
374 switch (p_msg->hdr.opcode) {
375 case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
376 status = avrc_ctrl_pars_vendor_cmd(&p_msg->vendor, p_result);
377 break;
378
379 default:
380 AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
381 break;
382 }
383 p_result->cmd.opcode = p_msg->hdr.opcode;
384 p_result->cmd.status = status;
385 }
386 AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
387 return status;
388 }
389
390 /*******************************************************************************
391 *
392 * Function avrc_pars_browsing_cmd
393 *
394 * Description This function parses the commands that go through the
395 * browsing channel
396 *
397 * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
398 * successfully.
399 * Otherwise, the error code defined by AVRCP+1
400 *
401 ******************************************************************************/
avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE * p_msg,tAVRC_COMMAND * p_result,uint8_t * p_buf,uint16_t buf_len)402 static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
403 tAVRC_COMMAND* p_result, uint8_t* p_buf,
404 uint16_t buf_len) {
405 tAVRC_STS status = AVRC_STS_NO_ERROR;
406 uint8_t* p = p_msg->p_browse_data;
407 int count;
408
409 p_result->pdu = *p++;
410 AVRC_TRACE_DEBUG("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu);
411 /* skip over len */
412 p += 2;
413
414 switch (p_result->pdu) {
415 case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */
416 // For current implementation all players are browsable.
417 BE_STREAM_TO_UINT16(p_result->br_player.player_id, p);
418 break;
419
420 case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
421 STREAM_TO_UINT8(p_result->get_items.scope, p);
422 // To be modified later here (Scope) when all browsing commands are
423 // supported
424 if (p_result->get_items.scope > AVRC_SCOPE_NOW_PLAYING) {
425 status = AVRC_STS_BAD_SCOPE;
426 }
427 BE_STREAM_TO_UINT32(p_result->get_items.start_item, p);
428 BE_STREAM_TO_UINT32(p_result->get_items.end_item, p);
429 if (p_result->get_items.start_item > p_result->get_items.end_item) {
430 status = AVRC_STS_BAD_RANGE;
431 }
432 STREAM_TO_UINT8(p_result->get_items.attr_count, p);
433 p_result->get_items.p_attr_list = NULL;
434 if (p_result->get_items.attr_count && p_buf &&
435 (p_result->get_items.attr_count != AVRC_FOLDER_ITEM_COUNT_NONE)) {
436 p_result->get_items.p_attr_list = (uint32_t*)p_buf;
437 count = p_result->get_items.attr_count;
438 if (buf_len < (count << 2))
439 p_result->get_items.attr_count = count = (buf_len >> 2);
440 for (int idx = 0; idx < count; idx++) {
441 BE_STREAM_TO_UINT32(p_result->get_items.p_attr_list[idx], p);
442 }
443 }
444 break;
445
446 case AVRC_PDU_CHANGE_PATH: /* 0x72 */
447 BE_STREAM_TO_UINT16(p_result->chg_path.uid_counter, p);
448 BE_STREAM_TO_UINT8(p_result->chg_path.direction, p);
449 if (p_result->chg_path.direction != AVRC_DIR_UP &&
450 p_result->chg_path.direction != AVRC_DIR_DOWN) {
451 status = AVRC_STS_BAD_DIR;
452 }
453 BE_STREAM_TO_ARRAY(p, p_result->chg_path.folder_uid, AVRC_UID_SIZE);
454 break;
455
456 case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */
457 BE_STREAM_TO_UINT8(p_result->get_attrs.scope, p);
458 if (p_result->get_attrs.scope > AVRC_SCOPE_NOW_PLAYING) {
459 status = AVRC_STS_BAD_SCOPE;
460 break;
461 }
462 BE_STREAM_TO_ARRAY(p, p_result->get_attrs.uid, AVRC_UID_SIZE);
463 BE_STREAM_TO_UINT16(p_result->get_attrs.uid_counter, p);
464 BE_STREAM_TO_UINT8(p_result->get_attrs.attr_count, p);
465 p_result->get_attrs.p_attr_list = NULL;
466 if (p_result->get_attrs.attr_count && p_buf) {
467 p_result->get_attrs.p_attr_list = (uint32_t*)p_buf;
468 count = p_result->get_attrs.attr_count;
469 if (buf_len < (count << 2))
470 p_result->get_attrs.attr_count = count = (buf_len >> 2);
471 for (int idx = 0, count = 0; idx < p_result->get_attrs.attr_count;
472 idx++) {
473 BE_STREAM_TO_UINT32(p_result->get_attrs.p_attr_list[count], p);
474 if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(
475 p_result->get_attrs.p_attr_list[count])) {
476 count++;
477 }
478 }
479
480 if (p_result->get_attrs.attr_count != count && count == 0)
481 status = AVRC_STS_BAD_PARAM;
482 else
483 p_result->get_attrs.attr_count = count;
484 }
485 break;
486
487 case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS: /* 0x75 */
488 BE_STREAM_TO_UINT8(p_result->get_num_of_items.scope, p);
489 if (p_result->get_num_of_items.scope > AVRC_SCOPE_NOW_PLAYING) {
490 status = AVRC_STS_BAD_SCOPE;
491 }
492 break;
493
494 case AVRC_PDU_SEARCH: /* 0x80 */
495 BE_STREAM_TO_UINT16(p_result->search.string.charset_id, p);
496 BE_STREAM_TO_UINT16(p_result->search.string.str_len, p);
497 p_result->search.string.p_str = p_buf;
498 if (p_buf) {
499 if (p_result->search.string.str_len > buf_len) {
500 p_result->search.string.str_len = buf_len;
501 } else {
502 android_errorWriteLog(0x534e4554, "63146237");
503 }
504 BE_STREAM_TO_ARRAY(p, p_buf, p_result->search.string.str_len);
505 } else {
506 status = AVRC_STS_INTERNAL_ERR;
507 }
508 break;
509
510 default:
511 status = AVRC_STS_BAD_CMD;
512 break;
513 }
514 return status;
515 }
516
517 /*******************************************************************************
518 *
519 * Function AVRC_ParsCommand
520 *
521 * Description This function is a superset of AVRC_ParsMetadata to parse
522 * the command.
523 *
524 * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
525 * successfully.
526 * Otherwise, the error code defined by AVRCP 1.4
527 *
528 ******************************************************************************/
AVRC_ParsCommand(tAVRC_MSG * p_msg,tAVRC_COMMAND * p_result,uint8_t * p_buf,uint16_t buf_len)529 tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result,
530 uint8_t* p_buf, uint16_t buf_len) {
531 tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
532 uint16_t id;
533
534 if (p_msg && p_result) {
535 switch (p_msg->hdr.opcode) {
536 case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
537 status = avrc_pars_vendor_cmd(&p_msg->vendor, p_result, p_buf, buf_len);
538 break;
539
540 case AVRC_OP_PASS_THRU: /* 0x7C panel subunit opcode */
541 status = avrc_pars_pass_thru(&p_msg->pass, &id);
542 if (status == AVRC_STS_NO_ERROR) {
543 p_result->pdu = (uint8_t)id;
544 }
545 break;
546
547 case AVRC_OP_BROWSE:
548 status =
549 avrc_pars_browsing_cmd(&p_msg->browse, p_result, p_buf, buf_len);
550 break;
551
552 default:
553 AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
554 break;
555 }
556 p_result->cmd.opcode = p_msg->hdr.opcode;
557 p_result->cmd.status = status;
558 }
559 AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
560 return status;
561 }
562