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