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 38 static 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 ******************************************************************************/ 67 static 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 ******************************************************************************/ 95 static 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 ******************************************************************************/ 125 static 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 ******************************************************************************/ 361 static 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 ******************************************************************************/ 446 UINT16 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 ******************************************************************************/ 485 UINT16 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 ******************************************************************************/ 508 UINT16 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 ******************************************************************************/ 537 UINT16 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 ******************************************************************************/ 576 UINT16 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