1/****************************************************************************** 2 * 3 * Copyright (C) 2003-2012 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 19/****************************************************************************** 20 * 21 * nterface to AVRCP mandatory commands 22 * 23 ******************************************************************************/ 24#include <string.h> 25 26#include "gki.h" 27#include "avrc_api.h" 28#include "avrc_int.h" 29#include "wcassert.h" 30 31/***************************************************************************** 32** Global data 33*****************************************************************************/ 34 35 36#define AVRC_MAX_RCV_CTRL_EVT AVCT_BROWSE_UNCONG_IND_EVT 37 38static const UINT8 avrc_ctrl_event_map[] = 39{ 40 AVRC_OPEN_IND_EVT, /* AVCT_CONNECT_CFM_EVT */ 41 AVRC_OPEN_IND_EVT, /* AVCT_CONNECT_IND_EVT */ 42 AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_CFM_EVT */ 43 AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_IND_EVT */ 44 AVRC_CONG_IND_EVT, /* AVCT_CONG_IND_EVT */ 45 AVRC_UNCONG_IND_EVT,/* AVCT_UNCONG_IND_EVT */ 46 AVRC_BROWSE_OPEN_IND_EVT, /* AVCT_BROWSE_CONN_CFM_EVT */ 47 AVRC_BROWSE_OPEN_IND_EVT, /* AVCT_BROWSE_CONN_IND_EVT */ 48 AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_CFM_EVT */ 49 AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_IND_EVT */ 50 AVRC_BROWSE_CONG_IND_EVT, /* AVCT_BROWSE_CONG_IND_EVT */ 51 AVRC_BROWSE_UNCONG_IND_EVT /* AVCT_BROWSE_UNCONG_IND_EVT */ 52}; 53 54#define AVRC_OP_DROP 0xFE /* use this unused opcode to indication no need to call the callback function */ 55#define AVRC_OP_DROP_N_FREE 0xFD /* use this unused opcode to indication no need to call the callback function & free buffer */ 56 57/****************************************************************************** 58** 59** Function avrc_ctrl_cback 60** 61** Description This is the callback function used by AVCTP to report 62** received link events. 63** 64** Returns Nothing. 65** 66******************************************************************************/ 67static void avrc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result, 68 BD_ADDR peer_addr) 69{ 70 UINT8 avrc_event; 71 72 if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback) 73 { 74 avrc_event = avrc_ctrl_event_map[event]; 75 if (event == AVCT_CONNECT_CFM_EVT) 76 { 77 if (result != 0) /* failed */ 78 avrc_event = AVRC_CLOSE_IND_EVT; 79 } 80 (*avrc_cb.ccb[handle].p_ctrl_cback)(handle, avrc_event, result, peer_addr); 81 } 82 /* else drop the unknown event*/ 83} 84 85/****************************************************************************** 86** 87** Function avrc_get_data_ptr 88** 89** Description If the offset in the received buffer is smaller than required 90** move the portion of data AVRC cares. 91** 92** Returns Nothing. 93** 94******************************************************************************/ 95static UINT8 * avrc_get_data_ptr(BT_HDR *p_pkt) 96{ 97 UINT8 *p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; 98 int i, gap; 99 100 if (p_pkt->offset < AVCT_MSG_OFFSET) 101 { 102 gap = AVCT_MSG_OFFSET - p_pkt->offset; 103 for(i=p_pkt->len; i>0; i--) 104 { 105 *(p_data + i + gap) = *(p_data + i); 106 } 107 p_pkt->offset += gap; 108 p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; 109 } 110 *p_data = AVRC_RSP_IMPL_STBL; 111 return p_data; 112} 113 114 115/****************************************************************************** 116** 117** Function avrc_msg_cback 118** 119** Description This is the callback function used by AVCTP to report 120** received AV control messages. 121** 122** Returns Nothing. 123** 124******************************************************************************/ 125static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr, 126 BT_HDR *p_pkt) 127{ 128 UINT8 opcode; 129 tAVRC_MSG msg; 130 UINT8 *p_data; 131 UINT8 *p_begin; 132 BOOLEAN drop = FALSE; 133 BOOLEAN free = TRUE; 134 BT_HDR *p_rsp = NULL; 135 UINT8 *p_rsp_data; 136 int xx; 137 BOOLEAN reject = FALSE; 138#if (BT_USE_TRACES == TRUE) 139 char *p_drop_msg = "dropped"; 140#endif 141 tAVRC_MSG_VENDOR *p_msg = &msg.vendor; 142 143 if (cr == AVCT_CMD && 144 (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < sizeof(p_pkt->len))) 145 { 146 /* Ignore the invalid AV/C command frame */ 147#if (BT_USE_TRACES == TRUE) 148 p_drop_msg = "dropped - too long AV/C cmd frame size"; 149#endif 150 GKI_freebuf(p_pkt); 151 return; 152 } 153 154 if (cr == AVCT_REJ) 155 { 156 /* The peer thinks that this PID is no longer open - remove this handle */ 157 /* */ 158 GKI_freebuf(p_pkt); 159 AVCT_RemoveConn(handle); 160 return; 161 } 162 163 p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; 164 memset(&msg, 0, sizeof(tAVRC_MSG) ); 165 { 166 msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK; 167 AVRC_TRACE_DEBUG4("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d", 168 handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len); 169 msg.hdr.subunit_type = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT; 170 msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK; 171 opcode = p_data[2]; 172 } 173 174 if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) || 175 ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) ) 176 { 177 178 switch(opcode) 179 { 180 case AVRC_OP_UNIT_INFO: 181 if (cr == AVCT_CMD) 182 { 183 /* send the response to the peer */ 184 p_rsp = p_pkt; /* this also sets free = FALSE, drop = TRUE */ 185 /* check & set the offset. set response code, set subunit_type & subunit_id, 186 set AVRC_OP_UNIT_INFO */ 187 p_rsp_data = avrc_get_data_ptr(p_pkt) + AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */ 188 *p_rsp_data++ = 7; 189 /* Panel subunit & id=0 */ 190 *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); 191 AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id); 192 p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset); 193 cr = AVCT_RSP; 194#if (BT_USE_TRACES == TRUE) 195 p_drop_msg = "auto respond"; 196#endif 197 } 198 else 199 { 200 /* parse response */ 201 p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/ 202 msg.unit.unit_type = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT; 203 msg.unit.unit = *p_data & AVRC_SUBID_MASK; 204 p_data++; 205 AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data); 206 } 207 break; 208 209 case AVRC_OP_SUB_INFO: 210 if (cr == AVCT_CMD) 211 { 212 /* send the response to the peer */ 213 p_rsp = p_pkt; /* this also sets free = FALSE, drop = TRUE */ 214 /* check & set the offset. set response code, set (subunit_type & subunit_id), 215 set AVRC_OP_SUB_INFO, set (page & extention code) */ 216 p_rsp_data = avrc_get_data_ptr(p_pkt) + 4; 217 /* Panel subunit & id=0 */ 218 *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); 219 memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES); 220 p_rsp_data += AVRC_SUBRSP_OPRND_BYTES; 221 p_rsp->len = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset); 222 cr = AVCT_RSP; 223#if (BT_USE_TRACES == TRUE) 224 p_drop_msg = "auto responded"; 225#endif 226 } 227 else 228 { 229 /* parse response */ 230 p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */ 231 msg.sub.page = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK; 232 xx = 0; 233 while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN) 234 { 235 msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT; 236 if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL) 237 msg.sub.panel = TRUE; 238 xx++; 239 } 240 } 241 break; 242 243 case AVRC_OP_VENDOR: 244 p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset; 245 p_begin = p_data; 246 if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */ 247 { 248 if (cr == AVCT_CMD) 249 reject = TRUE; 250 else 251 drop = TRUE; 252 break; 253 } 254 p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */ 255 AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data); 256 p_msg->p_vendor_data = p_data; 257 p_msg->vendor_len = p_pkt->len - (p_data - p_begin); 258 259 break; 260 261 case AVRC_OP_PASS_THRU: 262 if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */ 263 { 264 if (cr == AVCT_CMD) 265 reject = TRUE; 266 else 267 drop = TRUE; 268 break; 269 } 270 p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */ 271 msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data); 272 if (AVRC_PASS_STATE_MASK & *p_data) 273 msg.pass.state = TRUE; 274 else 275 msg.pass.state = FALSE; 276 p_data++; 277 msg.pass.pass_len = *p_data++; 278 if (msg.pass.pass_len != p_pkt->len - 5) 279 msg.pass.pass_len = p_pkt->len - 5; 280 if (msg.pass.pass_len) 281 msg.pass.p_pass_data = p_data; 282 else 283 msg.pass.p_pass_data = NULL; 284 break; 285 286 287 default: 288 if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) 289 { 290 /* reject unsupported opcode */ 291 reject = TRUE; 292 } 293 drop = TRUE; 294 break; 295 } 296 } 297 else /* drop the event */ 298 { 299 drop = TRUE; 300 } 301 302 if (reject) 303 { 304 /* reject unsupported opcode */ 305 p_rsp = p_pkt; /* this also sets free = FALSE, drop = TRUE */ 306 p_rsp_data = avrc_get_data_ptr(p_pkt); 307 *p_rsp_data = AVRC_RSP_REJ; 308#if (BT_USE_TRACES == TRUE) 309 p_drop_msg = "rejected"; 310#endif 311 cr = AVCT_RSP; 312 drop = TRUE; 313 } 314 315 if (p_rsp) 316 { 317 /* set to send response right away */ 318 AVCT_MsgReq( handle, label, cr, p_rsp); 319 free = FALSE; 320 drop = TRUE; 321 } 322 323 if (drop == FALSE) 324 { 325 msg.hdr.opcode = opcode; 326 (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg); 327 } 328#if (BT_USE_TRACES == TRUE) 329 else 330 { 331 AVRC_TRACE_WARNING5("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x", 332 p_drop_msg, 333 handle, avrc_cb.ccb[handle].control, cr, opcode); 334 } 335#endif 336 337 338 if (free) 339 GKI_freebuf(p_pkt); 340} 341 342 343 344 345/****************************************************************************** 346** 347** Function avrc_pass_msg 348** 349** Description Compose a PASS THROUGH command according to p_msg 350** 351** Input Parameters: 352** p_msg: Pointer to PASS THROUGH message structure. 353** 354** Output Parameters: 355** None. 356** 357** Returns pointer to a valid GKI buffer if successful. 358** NULL if p_msg is NULL. 359** 360******************************************************************************/ 361static BT_HDR * avrc_pass_msg(tAVRC_MSG_PASS *p_msg) 362{ 363 BT_HDR *p_cmd = NULL; 364 UINT8 *p_data; 365 366 WC_ASSERT(p_msg != NULL); 367 WC_ASSERT(AVRC_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->pass_len)); 368 369 if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL) 370 { 371 p_cmd->offset = AVCT_MSG_OFFSET; 372 p_cmd->layer_specific = AVCT_DATA_CTRL; 373 p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset; 374 *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK); 375 *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); /* Panel subunit & id=0 */ 376 *p_data++ = AVRC_OP_PASS_THRU; 377 *p_data = (AVRC_PASS_OP_ID_MASK&p_msg->op_id); 378 if (p_msg->state) 379 *p_data |= AVRC_PASS_STATE_MASK; 380 p_data++; 381 382 if (p_msg->op_id == AVRC_ID_VENDOR) 383 { 384 *p_data++ = p_msg->pass_len; 385 if (p_msg->pass_len && p_msg->p_pass_data) 386 { 387 memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len); 388 p_data += p_msg->pass_len; 389 } 390 } 391 else /* set msg len to 0 for other op_id */ 392 { 393 /* set msg len to 0 for other op_id */ 394 *p_data++ = 0; 395 } 396 p_cmd->len = (UINT16) (p_data - (UINT8 *)(p_cmd + 1) - p_cmd->offset); 397 } 398 return p_cmd; 399} 400 401/****************************************************************************** 402** 403** Function AVRC_Open 404** 405** Description This function is called to open a connection to AVCTP. 406** The connection can be either an initiator or acceptor, as 407** determined by the p_ccb->stream parameter. 408** The connection can be a target, a controller or for both role, 409** as determined by the p_ccb->control parameter. 410** By definition, a target connection is an acceptor connection 411** that waits for an incoming AVCTP connection from the peer. 412** The connection remains available to the application until 413** the application closes it by calling AVRC_Close(). The 414** application does not need to reopen the connection after an 415** AVRC_CLOSE_IND_EVT is received. 416** 417** Input Parameters: 418** p_ccb->company_id: Company Identifier. 419** 420** p_ccb->p_ctrl_cback: Pointer to control callback function. 421** 422** p_ccb->p_msg_cback: Pointer to message callback function. 423** 424** p_ccb->conn: AVCTP connection role. This is set to 425** AVCTP_INT for initiator connections and AVCTP_ACP 426** for acceptor connections. 427** 428** p_ccb->control: Control role. This is set to 429** AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL 430** for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL) 431** for connections that support both roles. 432** 433** peer_addr: BD address of peer device. This value is 434** only used for initiator connections; for acceptor 435** connections it can be set to NULL. 436** 437** Output Parameters: 438** p_handle: Pointer to handle. This parameter is only 439** valid if AVRC_SUCCESS is returned. 440** 441** Returns AVRC_SUCCESS if successful. 442** AVRC_NO_RESOURCES if there are not enough resources to open 443** the connection. 444** 445******************************************************************************/ 446UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr) 447{ 448 UINT16 status; 449 tAVCT_CC cc; 450 451 cc.p_ctrl_cback = avrc_ctrl_cback; /* Control callback */ 452 cc.p_msg_cback = avrc_msg_cback; /* Message callback */ 453 cc.pid = UUID_SERVCLASS_AV_REMOTE_CONTROL; /* Profile ID */ 454 cc.role = p_ccb->conn; /* Initiator/acceptor role */ 455 cc.control = p_ccb->control; /* Control role (Control/Target) */ 456 457 status = AVCT_CreateConn(p_handle, &cc, peer_addr); 458 if (status == AVCT_SUCCESS) 459 { 460 memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB)); 461 } 462 AVRC_TRACE_DEBUG4("AVRC_Open role: %d, control:%d status:%d, handle:%d", cc.role, cc.control, status, *p_handle); 463 464 return status; 465} 466 467/****************************************************************************** 468** 469** Function AVRC_Close 470** 471** Description Close a connection opened with AVRC_Open(). 472** This function is called when the 473** application is no longer using a connection. 474** 475** Input Parameters: 476** handle: Handle of this connection. 477** 478** Output Parameters: 479** None. 480** 481** Returns AVRC_SUCCESS if successful. 482** AVRC_BAD_HANDLE if handle is invalid. 483** 484******************************************************************************/ 485UINT16 AVRC_Close(UINT8 handle) 486{ 487 AVRC_TRACE_DEBUG1("AVRC_Close handle:%d", handle); 488 return AVCT_RemoveConn(handle); 489} 490 491 492/****************************************************************************** 493** 494** Function AVRC_MsgReq 495** 496** Description This function is used to send the AVRCP byte stream in p_pkt 497** down to AVCTP. 498** 499** It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET 500** p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE 501** p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE 502** The above BT_HDR settings are set by the AVRC_Bld* functions. 503** 504** Returns AVRC_SUCCESS if successful. 505** AVRC_BAD_HANDLE if handle is invalid. 506** 507******************************************************************************/ 508UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt) 509{ 510 return AVRC_NO_RESOURCES; 511} 512 513 514/****************************************************************************** 515** 516** Function AVRC_PassCmd 517** 518** Description Send a PASS THROUGH command to the peer device. This 519** function can only be called for controller role connections. 520** Any response message from the peer is passed back through 521** the tAVRC_MSG_CBACK callback function. 522** 523** Input Parameters: 524** handle: Handle of this connection. 525** 526** label: Transaction label. 527** 528** p_msg: Pointer to PASS THROUGH message structure. 529** 530** Output Parameters: 531** None. 532** 533** Returns AVRC_SUCCESS if successful. 534** AVRC_BAD_HANDLE if handle is invalid. 535** 536******************************************************************************/ 537UINT16 AVRC_PassCmd(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg) 538{ 539 BT_HDR *p_buf; 540 WC_ASSERT(p_msg != NULL); 541 if (p_msg) 542 { 543 p_msg->hdr.ctype = AVRC_CMD_CTRL; 544 p_buf = avrc_pass_msg(p_msg); 545 if (p_buf) 546 return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf); 547 } 548 return AVRC_NO_RESOURCES; 549} 550 551/****************************************************************************** 552** 553** Function AVRC_PassRsp 554** 555** Description Send a PASS THROUGH response to the peer device. This 556** function can only be called for target role connections. 557** This function must be called when a PASS THROUGH command 558** message is received from the peer through the 559** tAVRC_MSG_CBACK callback function. 560** 561** Input Parameters: 562** handle: Handle of this connection. 563** 564** label: Transaction label. Must be the same value as 565** passed with the command message in the callback function. 566** 567** p_msg: Pointer to PASS THROUGH message structure. 568** 569** Output Parameters: 570** None. 571** 572** Returns AVRC_SUCCESS if successful. 573** AVRC_BAD_HANDLE if handle is invalid. 574** 575******************************************************************************/ 576UINT16 AVRC_PassRsp(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg) 577{ 578 BT_HDR *p_buf; 579 WC_ASSERT(p_msg != NULL); 580 if (p_msg) 581 { 582 p_buf = avrc_pass_msg(p_msg); 583 if (p_buf) 584 return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf); 585 } 586 return AVRC_NO_RESOURCES; 587} 588 589