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 *******************************************************************************/ 41 static 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 *******************************************************************************/ 74 static 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 *******************************************************************************/ 99 static 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 *******************************************************************************/ 127 static 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 *******************************************************************************/ 191 tAVRC_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