1/****************************************************************************** 2 * 3 * Copyright (C) 2006-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 29 30#if (AVRC_METADATA_INCLUDED == TRUE) 31/******************************************************************************* 32** 33** Function avrc_bld_next_cmd 34** 35** Description This function builds the Request Continue or Abort command. 36** 37** Returns AVRC_STS_NO_ERROR, if the command is built successfully 38** Otherwise, the error code. 39** 40*******************************************************************************/ 41static tAVRC_STS avrc_bld_next_cmd (tAVRC_NEXT_CMD *p_cmd, BT_HDR *p_pkt) 42{ 43 UINT8 *p_data, *p_start; 44 45 AVRC_TRACE_API("avrc_bld_next_cmd"); 46 47 /* get the existing length, if any, and also the num attributes */ 48 p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; 49 p_data = p_start + 2; /* pdu + rsvd */ 50 51 /* add fixed lenth 1 - pdu_id (1) */ 52 UINT16_TO_BE_STREAM(p_data, 1); 53 UINT8_TO_BE_STREAM(p_data, p_cmd->target_pdu); 54 p_pkt->len = (p_data - p_start); 55 56 return AVRC_STS_NO_ERROR; 57} 58 59/***************************************************************************** 60** the following commands are introduced in AVRCP 1.4 61*****************************************************************************/ 62 63#if (AVRC_ADV_CTRL_INCLUDED == TRUE) 64/******************************************************************************* 65** 66** Function avrc_bld_set_abs_volume_cmd 67** 68** Description This function builds the Set Absolute Volume command. 69** 70** Returns AVRC_STS_NO_ERROR, if the command is built successfully 71** Otherwise, the error code. 72** 73*******************************************************************************/ 74static tAVRC_STS avrc_bld_set_abs_volume_cmd (tAVRC_SET_VOLUME_CMD *p_cmd, BT_HDR *p_pkt) 75{ 76 UINT8 *p_data, *p_start; 77 78 AVRC_TRACE_API("avrc_bld_set_abs_volume_cmd"); 79 /* get the existing length, if any, and also the num attributes */ 80 p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; 81 p_data = p_start + 2; /* pdu + rsvd */ 82 /* add fixed lenth 1 - volume (1) */ 83 UINT16_TO_BE_STREAM(p_data, 1); 84 UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_cmd->volume)); 85 p_pkt->len = (p_data - p_start); 86 return AVRC_STS_NO_ERROR; 87} 88 89/******************************************************************************* 90** 91** Function avrc_bld_vol_change_notfn 92** 93** Description This function builds the register notification for volume change. 94** 95** Returns AVRC_STS_NO_ERROR, if the command is built successfully 96** Otherwise, the error code. 97** 98*******************************************************************************/ 99static tAVRC_STS avrc_bld_vol_change_notfn(BT_HDR * p_pkt) 100{ 101 UINT8 *p_data, *p_start; 102 103 AVRC_TRACE_API("avrc_bld_vol_change"); 104 /* get the existing length, if any, and also the num attributes */ 105 // Set the notify value 106 p_start = (UINT8 *)(p_pkt + 1) + p_pkt->offset; 107 p_data = p_start + 2; /* pdu + rsvd */ 108 /* add fixed length 5 -*/ 109 UINT16_TO_BE_STREAM(p_data, 5); 110 UINT8_TO_BE_STREAM(p_data,AVRC_EVT_VOLUME_CHANGE); 111 UINT32_TO_BE_STREAM(p_data, 0); 112 p_pkt->len = (p_data - p_start); 113 return AVRC_STS_NO_ERROR; 114} 115#endif 116 117/******************************************************************************* 118** 119** Function avrc_bld_init_cmd_buffer 120** 121** Description This function initializes the command buffer based on PDU 122** 123** Returns NULL, if no GKI buffer or failure to build the message. 124** Otherwise, the GKI buffer that contains the initialized message. 125** 126*******************************************************************************/ 127static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd) 128{ 129 UINT16 offset = 0, chnl = AVCT_DATA_CTRL, len=AVRC_META_CMD_POOL_SIZE; 130 BT_HDR *p_pkt=NULL; 131 UINT8 opcode; 132 133 opcode = avrc_opcode_from_pdu(p_cmd->pdu); 134 AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode); 135 136 switch (opcode) 137 { 138 case AVRC_OP_PASS_THRU: 139 offset = AVRC_MSG_PASS_THRU_OFFSET; 140 break; 141 142 case AVRC_OP_VENDOR: 143 offset = AVRC_MSG_VENDOR_OFFSET; 144 break; 145 } 146 147 /* allocate and initialize the buffer */ 148 p_pkt = (BT_HDR *)GKI_getbuf(len); 149 if (p_pkt) 150 { 151 UINT8 *p_data, *p_start; 152 153 p_pkt->layer_specific = chnl; 154 p_pkt->event = opcode; 155 p_pkt->offset = offset; 156 p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset; 157 p_start = p_data; 158 159 /* pass thru - group navigation - has a two byte op_id, so dont do it here */ 160 if (opcode != AVRC_OP_PASS_THRU) 161 *p_data++ = p_cmd->pdu; 162 163 switch (opcode) 164 { 165 case AVRC_OP_VENDOR: 166 /* reserved 0, packet_type 0 */ 167 UINT8_TO_BE_STREAM(p_data, 0); 168 /* continue to the next "case to add length */ 169 /* add fixed lenth - 0 */ 170 UINT16_TO_BE_STREAM(p_data, 0); 171 break; 172 } 173 174 p_pkt->len = (p_data - p_start); 175 } 176 p_cmd->cmd.opcode = opcode; 177 return p_pkt; 178} 179 180/******************************************************************************* 181** 182** Function AVRC_BldCommand 183** 184** Description This function builds the given AVRCP command to the given 185** GKI buffer 186** 187** Returns AVRC_STS_NO_ERROR, if the command is built successfully 188** Otherwise, the error code. 189** 190*******************************************************************************/ 191tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt) 192{ 193 tAVRC_STS status = AVRC_STS_BAD_PARAM; 194 BT_HDR *p_pkt; 195 BOOLEAN alloc = FALSE; 196 197 AVRC_TRACE_API("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, p_cmd->cmd.status); 198 if (!p_cmd || !pp_pkt) 199 { 200 AVRC_TRACE_API("AVRC_BldCommand. Invalid parameters passed. p_cmd=%p, pp_pkt=%p", 201 p_cmd, pp_pkt); 202 return AVRC_STS_BAD_PARAM; 203 } 204 205 if (*pp_pkt == NULL) 206 { 207 if ((*pp_pkt = avrc_bld_init_cmd_buffer(p_cmd)) == NULL) 208 { 209 AVRC_TRACE_API("AVRC_BldCommand: Failed to initialize command buffer"); 210 return AVRC_STS_INTERNAL_ERR; 211 } 212 alloc = TRUE; 213 } 214 status = AVRC_STS_NO_ERROR; 215 p_pkt = *pp_pkt; 216 217 switch (p_cmd->pdu) 218 { 219 case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */ 220 status = avrc_bld_next_cmd(&p_cmd->continu, p_pkt); 221 break; 222 223 case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */ 224 status = avrc_bld_next_cmd(&p_cmd->abort, p_pkt); 225 break; 226#if (AVRC_ADV_CTRL_INCLUDED == TRUE) 227 case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */ 228 status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt); 229 break; 230#endif 231 232 case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ 233#if (AVRC_ADV_CTRL_INCLUDED == TRUE) 234 if(AVRC_EVT_VOLUME_CHANGE==p_cmd->reg_notif.event_id) 235 status=avrc_bld_vol_change_notfn(p_pkt); 236#endif 237 break; 238 239 } 240 241 if (alloc && (status != AVRC_STS_NO_ERROR) ) 242 { 243 GKI_freebuf(p_pkt); 244 *pp_pkt = NULL; 245 } 246 AVRC_TRACE_API("AVRC_BldCommand: returning %d", status); 247 return status; 248} 249#endif /* (AVRC_METADATA_INCLUDED == TRUE) */ 250 251