Home | History | Annotate | Download | only in avrc
      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  *  Interface 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 #if (AVRC_METADATA_INCLUDED == TRUE)
    115 /******************************************************************************
    116 **
    117 ** Function         avrc_prep_end_frag
    118 **
    119 ** Description      This function prepares an end response fragment
    120 **
    121 ** Returns          Nothing.
    122 **
    123 ******************************************************************************/
    124 static void avrc_prep_end_frag(UINT8 handle)
    125 {
    126     tAVRC_FRAG_CB   *p_fcb;
    127     BT_HDR  *p_pkt_new;
    128     UINT8   *p_data, *p_orig_data;
    129     UINT8   rsp_type;
    130 
    131     AVRC_TRACE_DEBUG0 ("avrc_prep_end_frag" );
    132     p_fcb = &avrc_cb.fcb[handle];
    133 
    134     /* The response type of the end fragment should be the same as the the PDU of "End Fragment
    135     ** Respose" Errata: https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383 */
    136     p_orig_data = ((UINT8 *)(p_fcb->p_fmsg + 1) + p_fcb->p_fmsg->offset);
    137     rsp_type = ((*p_orig_data) & AVRC_CTYPE_MASK);
    138 
    139     p_pkt_new           = p_fcb->p_fmsg;
    140     p_pkt_new->len      -= (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
    141     p_pkt_new->offset   += (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
    142     p_data = (UINT8 *)(p_pkt_new+1) + p_pkt_new->offset;
    143     *p_data++       = rsp_type;
    144     *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
    145     *p_data++       = AVRC_OP_VENDOR;
    146     AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
    147     *p_data++       = p_fcb->frag_pdu;
    148     *p_data++       = AVRC_PKT_END;
    149     /* 4=pdu, pkt_type & len */
    150     UINT16_TO_BE_STREAM(p_data, (p_pkt_new->len - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE));
    151 }
    152 
    153 /******************************************************************************
    154 **
    155 ** Function         avrc_send_continue_frag
    156 **
    157 ** Description      This function sends a continue response fragment
    158 **
    159 ** Returns          Nothing.
    160 **
    161 ******************************************************************************/
    162 static void avrc_send_continue_frag(UINT8 handle, UINT8 label)
    163 {
    164     tAVRC_FRAG_CB   *p_fcb;
    165     BT_HDR  *p_pkt_old, *p_pkt;
    166     UINT8   *p_old, *p_data;
    167     UINT8   cr = AVCT_RSP;
    168     tAVRC_RSP   rej_rsp;
    169 
    170     p_fcb = &avrc_cb.fcb[handle];
    171     p_pkt = p_fcb->p_fmsg;
    172 
    173     AVRC_TRACE_DEBUG1 ("avrc_send_continue_frag len(%d) / AVRC_MAX_CTRL_DATA_LEN", p_pkt->len );
    174     if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN)
    175     {
    176         p_pkt_old = p_fcb->p_fmsg;
    177         p_pkt = (BT_HDR *)GKI_getbuf((UINT16)(AVRC_PACKET_LEN + AVCT_MSG_OFFSET + BT_HDR_SIZE));
    178         if (p_pkt)
    179         {
    180             p_pkt->len          = AVRC_MAX_CTRL_DATA_LEN;
    181             p_pkt->offset       = AVCT_MSG_OFFSET;
    182             p_pkt->layer_specific = p_pkt_old->layer_specific;
    183             p_pkt->event = p_pkt_old->event;
    184             p_old = (UINT8 *)(p_pkt_old+1) + p_pkt_old->offset;
    185             p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    186             memcpy (p_data, p_old, AVRC_MAX_CTRL_DATA_LEN);
    187             /* use AVRC continue packet type */
    188             p_data += AVRC_VENDOR_HDR_SIZE;
    189             p_data++; /* pdu */
    190             *p_data++ = AVRC_PKT_CONTINUE;
    191             /* 4=pdu, pkt_type & len */
    192             UINT16_TO_BE_STREAM(p_data, (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - 4));
    193 
    194             /* prepare the left over for as an end fragment */
    195             avrc_prep_end_frag (handle);
    196         }
    197         else
    198         {
    199             /* use the current GKI buffer to send Internal error status */
    200             p_pkt = p_fcb->p_fmsg;
    201             p_fcb->p_fmsg = NULL;
    202             p_fcb->frag_enabled = FALSE;
    203             AVRC_TRACE_ERROR0 ("AVRC_MsgReq no buffers for fragmentation - send internal error" );
    204             p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    205             *p_data++ = AVRC_PDU_REQUEST_CONTINUATION_RSP;
    206             *p_data++ = 0;
    207             UINT16_TO_BE_STREAM(p_data, 0);
    208             p_pkt->len = 4;
    209             rej_rsp.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP;
    210             rej_rsp.status = AVRC_STS_INTERNAL_ERR;
    211             AVRC_BldResponse( handle, (tAVRC_RESPONSE *)&rej_rsp, &p_pkt);
    212             cr = AVCT_RSP;
    213         }
    214     }
    215     else
    216     {
    217         /* end fragment. clean the control block */
    218         p_fcb->frag_enabled = FALSE;
    219         p_fcb->p_fmsg       = NULL;
    220     }
    221     AVCT_MsgReq( handle, label, cr, p_pkt);
    222 }
    223 
    224 /******************************************************************************
    225 **
    226 ** Function         avrc_proc_vendor_command
    227 **
    228 ** Description      This function processes received vendor command.
    229 **
    230 ** Returns          if not NULL, the response to send right away.
    231 **
    232 ******************************************************************************/
    233 static BT_HDR * avrc_proc_vendor_command(UINT8 handle, UINT8 label,
    234                                BT_HDR *p_pkt, tAVRC_MSG_VENDOR *p_msg)
    235 {
    236     BT_HDR      *p_rsp = NULL;
    237     UINT8       *p_data;
    238     UINT8       *p_begin;
    239     UINT8       pkt_type;
    240     BOOLEAN     abort_frag = FALSE;
    241     tAVRC_STS   status = AVRC_STS_NO_ERROR;
    242     tAVRC_FRAG_CB   *p_fcb;
    243 
    244     p_begin  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    245     p_data   = p_begin + AVRC_VENDOR_HDR_SIZE;
    246     pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
    247 
    248     if (pkt_type != AVRC_PKT_SINGLE)
    249     {
    250         /* reject - commands can only be in single packets at AVRCP level */
    251         AVRC_TRACE_ERROR1 ("commands must be in single packet pdu:0x%x", *p_data );
    252         /* use the current GKI buffer to send the reject */
    253         status = AVRC_STS_BAD_CMD;
    254     }
    255     /* check if there are fragments waiting to be sent */
    256     else if (avrc_cb.fcb[handle].frag_enabled)
    257     {
    258         p_fcb = &avrc_cb.fcb[handle];
    259         if (p_msg->company_id == AVRC_CO_METADATA)
    260         {
    261             switch (*p_data)
    262             {
    263             case AVRC_PDU_ABORT_CONTINUATION_RSP:
    264                 /* aborted by CT - send accept response */
    265                 abort_frag = TRUE;
    266                 p_begin = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    267                 *p_begin = (AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK);
    268                 if (*(p_data + 4) != p_fcb->frag_pdu)
    269                 {
    270                     *p_begin = (AVRC_RSP_REJ & AVRC_CTYPE_MASK);
    271                     *(p_data + 4) = AVRC_STS_BAD_PARAM;
    272                 }
    273                 else
    274                 {
    275                     p_data = (p_begin + AVRC_VENDOR_HDR_SIZE + 2);
    276                     UINT16_TO_BE_STREAM(p_data, 0);
    277                     p_pkt->len = (p_data - p_begin);
    278                 }
    279                 AVCT_MsgReq( handle, label, AVCT_RSP, p_pkt);
    280                 p_msg->hdr.opcode = AVRC_OP_DROP; /* used the p_pkt to send response */
    281                 break;
    282 
    283             case AVRC_PDU_REQUEST_CONTINUATION_RSP:
    284                 if (*(p_data + 4) == p_fcb->frag_pdu)
    285                 {
    286                     avrc_send_continue_frag(handle, label);
    287                     p_msg->hdr.opcode = AVRC_OP_DROP_N_FREE;
    288                 }
    289                 else
    290                 {
    291                     /* the pdu id does not match - reject the command using the current GKI buffer */
    292                     AVRC_TRACE_ERROR2("avrc_proc_vendor_command continue pdu: 0x%x does not match \
    293                     current re-assembly pdu: 0x%x",
    294                         *(p_data + 4), p_fcb->frag_pdu);
    295                     status = AVRC_STS_BAD_PARAM;
    296                     abort_frag = TRUE;
    297                 }
    298                 break;
    299 
    300             default:
    301                 /* implicit abort */
    302                 abort_frag = TRUE;
    303             }
    304         }
    305         else
    306         {
    307             abort_frag = TRUE;
    308             /* implicit abort */
    309         }
    310 
    311         if (abort_frag)
    312         {
    313             if (p_fcb->p_fmsg)
    314                 GKI_freebuf(p_fcb->p_fmsg);
    315             p_fcb->p_fmsg = NULL;
    316             p_fcb->frag_enabled = FALSE;
    317         }
    318     }
    319 
    320     if (status != AVRC_STS_NO_ERROR)
    321     {
    322         /* use the current GKI buffer to build/send the reject message */
    323         p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    324         *p_data++ = AVRC_RSP_REJ;
    325         p_data += AVRC_VENDOR_HDR_SIZE; /* pdu */
    326         *p_data++ = 0;                  /* pkt_type */
    327         UINT16_TO_BE_STREAM(p_data, 1); /* len */
    328         *p_data++ = status;             /* error code */
    329         p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
    330         p_rsp = p_pkt;
    331     }
    332 
    333     return p_rsp;
    334 }
    335 
    336 /******************************************************************************
    337 **
    338 ** Function         avrc_proc_far_msg
    339 **
    340 ** Description      This function processes vendor command/response fragmetation
    341 **                  and reassembly
    342 **
    343 ** Returns          0, to report the message with msg_cback .
    344 **
    345 ******************************************************************************/
    346 static UINT8 avrc_proc_far_msg(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR **pp_pkt,
    347     tAVRC_MSG_VENDOR *p_msg)
    348 {
    349     BT_HDR      *p_pkt = *pp_pkt;
    350     UINT8       *p_data;
    351     BOOLEAN     drop = FALSE;
    352     BT_HDR      *p_rsp = NULL;
    353     BT_HDR      *p_cmd = NULL;
    354     BOOLEAN     req_continue = FALSE;
    355     BT_HDR      *p_pkt_new = NULL;
    356     UINT8       pkt_type;
    357     UINT16      buf_len;
    358     tAVRC_RASM_CB   *p_rcb;
    359     tAVRC_NEXT_CMD   avrc_cmd;
    360 
    361     p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    362     pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
    363     AVRC_TRACE_DEBUG1 ("pkt_type %d", pkt_type );
    364     p_rcb = &avrc_cb.rcb[handle];
    365     if (p_msg->company_id == AVRC_CO_METADATA)
    366     {
    367         /* check if the message needs to be re-assembled */
    368         if (pkt_type == AVRC_PKT_SINGLE || pkt_type == AVRC_PKT_START)
    369         {
    370             /* previous fragments need to be dropped, when received another new message */
    371             p_rcb->rasm_offset = 0;
    372             if (p_rcb->p_rmsg)
    373             {
    374                 GKI_freebuf(p_rcb->p_rmsg);
    375                 p_rcb->p_rmsg = NULL;
    376             }
    377         }
    378 
    379         if (pkt_type != AVRC_PKT_SINGLE && cr == AVCT_RSP)
    380         {
    381             /* not a single response packet - need to re-assemble metadata messages */
    382             if (pkt_type == AVRC_PKT_START)
    383             {
    384                 p_rcb->rasm_offset = p_pkt->offset;
    385                 p_rcb->p_rmsg = p_pkt;
    386                 /* set offset to point to where to copy next - use the same re-asm logic as AVCT */
    387                 p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
    388                 p_rcb->rasm_pdu = *p_data;
    389                 req_continue = TRUE;
    390             }
    391             else
    392             {
    393                 /* get size of buffer holding assembled message */
    394                 buf_len = GKI_get_buf_size (p_rcb->p_rmsg) - sizeof(BT_HDR);
    395                 /* adjust offset and len of fragment for header byte */
    396                 p_pkt->offset += (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
    397                 p_pkt->len -= (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
    398                 /* verify length */
    399                 if ((p_rcb->p_rmsg->offset + p_pkt->len) > buf_len)
    400                 {
    401                     AVRC_TRACE_WARNING0("Fragmented message too big! - report the partial message");
    402                     p_pkt->len = buf_len - p_rcb->p_rmsg->offset;
    403                     pkt_type = AVRC_PKT_END;
    404                 }
    405 
    406                 /* copy contents of p_pkt to p_rx_msg */
    407                 memcpy((UINT8 *)(p_rcb->p_rmsg + 1) + p_rcb->p_rmsg->offset,
    408                        (UINT8 *)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
    409 
    410                 if (pkt_type == AVRC_PKT_END)
    411                 {
    412                     p_rcb->p_rmsg->offset = p_rcb->rasm_offset;
    413                     p_rcb->p_rmsg->len += p_pkt->len;
    414                     p_pkt_new = p_rcb->p_rmsg;
    415                     p_rcb->rasm_offset = 0;
    416                     p_rcb->p_rmsg = NULL;
    417                     p_msg->p_vendor_data   = (UINT8 *)(p_pkt_new+1) + p_pkt_new->offset;
    418                     p_msg->hdr.ctype       = p_msg->p_vendor_data[0] & AVRC_CTYPE_MASK;
    419                     /* 6 = ctype, subunit*, opcode & CO_ID */
    420                     p_msg->p_vendor_data  += AVRC_VENDOR_HDR_SIZE;
    421                     p_msg->vendor_len      = p_pkt_new->len - AVRC_VENDOR_HDR_SIZE;
    422                     p_data = p_msg->p_vendor_data + 1; /* skip pdu */
    423                     *p_data++ = AVRC_PKT_SINGLE;
    424                     UINT16_TO_BE_STREAM(p_data, (p_msg->vendor_len - AVRC_MIN_META_HDR_SIZE));
    425                     AVRC_TRACE_DEBUG3("end frag:%d, total len:%d, offset:%d", p_pkt->len,
    426                         p_pkt_new->len, p_pkt_new->offset);
    427                 }
    428                 else
    429                 {
    430                     p_rcb->p_rmsg->offset += p_pkt->len;
    431                     p_rcb->p_rmsg->len += p_pkt->len;
    432                     p_pkt_new = NULL;
    433                     req_continue = TRUE;
    434                 }
    435                 GKI_freebuf(p_pkt);
    436                 *pp_pkt = p_pkt_new;
    437             }
    438         }
    439 
    440         if (cr == AVCT_CMD)
    441         {
    442             p_rsp = avrc_proc_vendor_command(handle, label, *pp_pkt, p_msg);
    443             if (p_rsp)
    444             {
    445                 AVCT_MsgReq( handle, label, AVCT_RSP, p_rsp);
    446                 drop = 3;
    447             }
    448             else if (p_msg->hdr.opcode == AVRC_OP_DROP)
    449             {
    450                 drop = 1;
    451             }
    452             else if (p_msg->hdr.opcode == AVRC_OP_DROP_N_FREE)
    453                 drop = 4;
    454 
    455         }
    456     }
    457     return drop;
    458 }
    459 #endif /* (AVRC_METADATA_INCLUDED == TRUE) */
    460 
    461 /******************************************************************************
    462 **
    463 ** Function         avrc_msg_cback
    464 **
    465 ** Description      This is the callback function used by AVCTP to report
    466 **                  received AV control messages.
    467 **
    468 ** Returns          Nothing.
    469 **
    470 ******************************************************************************/
    471 static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr,
    472                                BT_HDR *p_pkt)
    473 {
    474     UINT8       opcode;
    475     tAVRC_MSG   msg;
    476     UINT8       *p_data;
    477     UINT8       *p_begin;
    478     BOOLEAN     drop = FALSE;
    479     BOOLEAN     free = TRUE;
    480     BT_HDR      *p_rsp = NULL;
    481     UINT8       *p_rsp_data;
    482     int         xx;
    483     BOOLEAN     reject = FALSE;
    484 #if (BT_USE_TRACES == TRUE)
    485     char        *p_drop_msg = "dropped";
    486 #endif
    487     tAVRC_MSG_VENDOR *p_msg = &msg.vendor;
    488 
    489     if (cr == AVCT_CMD &&
    490         (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < sizeof(p_pkt->len)))
    491     {
    492         /* Ignore the invalid AV/C command frame */
    493 #if (BT_USE_TRACES == TRUE)
    494         p_drop_msg = "dropped - too long AV/C cmd frame size";
    495 #endif
    496         GKI_freebuf(p_pkt);
    497         return;
    498     }
    499 
    500     if (cr == AVCT_REJ)
    501     {
    502         /* The peer thinks that this PID is no longer open - remove this handle */
    503         /*  */
    504         GKI_freebuf(p_pkt);
    505         AVCT_RemoveConn(handle);
    506         return;
    507     }
    508 
    509     p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    510     memset(&msg, 0, sizeof(tAVRC_MSG) );
    511     {
    512         msg.hdr.ctype           = p_data[0] & AVRC_CTYPE_MASK;
    513         AVRC_TRACE_DEBUG4("avrc_msg_cback handle:%d, ctype:%d, offset:%d, len: %d",
    514                 handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
    515         msg.hdr.subunit_type    = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
    516         msg.hdr.subunit_id      = p_data[1] & AVRC_SUBID_MASK;
    517         opcode                  = p_data[2];
    518     }
    519 
    520     if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
    521         ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) )
    522     {
    523 
    524         switch(opcode)
    525         {
    526         case AVRC_OP_UNIT_INFO:
    527             if (cr == AVCT_CMD)
    528             {
    529                 /* send the response to the peer */
    530                 p_rsp           = p_pkt; /* this also sets free = FALSE, drop = TRUE */
    531                 /* check & set the offset. set response code, set subunit_type & subunit_id,
    532                    set AVRC_OP_UNIT_INFO */
    533                 /* 3 bytes: ctype, subunit*, opcode */
    534                 p_rsp_data      = avrc_get_data_ptr(p_pkt) + AVRC_AVC_HDR_SIZE;
    535                 *p_rsp_data++   = 7;
    536                 /* Panel subunit & id=0 */
    537                 *p_rsp_data++   = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
    538                 AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
    539                 p_rsp->len      = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
    540                 cr = AVCT_RSP;
    541 #if (BT_USE_TRACES == TRUE)
    542                 p_drop_msg = "auto respond";
    543 #endif
    544             }
    545             else
    546             {
    547                 /* parse response */
    548                 p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
    549                 msg.unit.unit_type  = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
    550                 msg.unit.unit       = *p_data & AVRC_SUBID_MASK;
    551                 p_data++;
    552                 AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
    553             }
    554             break;
    555 
    556         case AVRC_OP_SUB_INFO:
    557             if (cr == AVCT_CMD)
    558             {
    559                 /* send the response to the peer */
    560                 p_rsp           = p_pkt; /* this also sets free = FALSE, drop = TRUE */
    561                 /* check & set the offset. set response code, set (subunit_type & subunit_id),
    562                    set AVRC_OP_SUB_INFO, set (page & extention code) */
    563                 p_rsp_data      = avrc_get_data_ptr(p_pkt) + 4;
    564                 /* Panel subunit & id=0 */
    565                 *p_rsp_data++   = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
    566                 memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
    567                 p_rsp_data      += AVRC_SUBRSP_OPRND_BYTES;
    568                 p_rsp->len      = (UINT16) (p_rsp_data - (UINT8 *)(p_rsp + 1) - p_rsp->offset);
    569                 cr = AVCT_RSP;
    570 #if (BT_USE_TRACES == TRUE)
    571                 p_drop_msg = "auto responded";
    572 #endif
    573             }
    574             else
    575             {
    576                 /* parse response */
    577                 p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
    578                 msg.sub.page    = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
    579                 xx      = 0;
    580                 while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN)
    581                 {
    582                     msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
    583                     if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
    584                         msg.sub.panel   = TRUE;
    585                     xx++;
    586                 }
    587             }
    588             break;
    589 
    590         case AVRC_OP_VENDOR:
    591             p_data  = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    592             p_begin = p_data;
    593             if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
    594             {
    595                 if (cr == AVCT_CMD)
    596                     reject = TRUE;
    597                 else
    598                     drop = TRUE;
    599                 break;
    600             }
    601             p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
    602             AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
    603             p_msg->p_vendor_data   = p_data;
    604             p_msg->vendor_len      = p_pkt->len - (p_data - p_begin);
    605 
    606 #if (AVRC_METADATA_INCLUDED == TRUE)
    607             drop = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);
    608             if (drop)
    609             {
    610                 free = FALSE;
    611                 if (drop == 4)
    612                     free = TRUE;
    613 #if (BT_USE_TRACES == TRUE)
    614                 switch (drop)
    615                 {
    616                 case 1:
    617                     p_drop_msg = "sent_frag";
    618                     break;
    619                 case 2:
    620                     p_drop_msg = "req_cont";
    621                     break;
    622                 case 3:
    623                     p_drop_msg = "sent_frag3";
    624                     break;
    625                 case 4:
    626                     p_drop_msg = "sent_frag_free";
    627                     break;
    628                 default:
    629                     p_drop_msg = "sent_fragd";
    630                 }
    631 #endif
    632             }
    633 #endif /* (AVRC_METADATA_INCLUDED == TRUE) */
    634             break;
    635 
    636         case AVRC_OP_PASS_THRU:
    637             if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
    638             {
    639                 if (cr == AVCT_CMD)
    640                     reject = TRUE;
    641                 else
    642                     drop = TRUE;
    643                 break;
    644             }
    645             p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
    646             msg.pass.op_id  = (AVRC_PASS_OP_ID_MASK & *p_data);
    647             if (AVRC_PASS_STATE_MASK & *p_data)
    648                 msg.pass.state  = TRUE;
    649             else
    650                 msg.pass.state  = FALSE;
    651             p_data++;
    652             msg.pass.pass_len    = *p_data++;
    653             if (msg.pass.pass_len != p_pkt->len - 5)
    654                 msg.pass.pass_len = p_pkt->len - 5;
    655             if (msg.pass.pass_len)
    656                 msg.pass.p_pass_data = p_data;
    657             else
    658                 msg.pass.p_pass_data = NULL;
    659             break;
    660 
    661 
    662         default:
    663             if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
    664             {
    665                 /* reject unsupported opcode */
    666                 reject = TRUE;
    667             }
    668             drop    = TRUE;
    669             break;
    670         }
    671     }
    672     else /* drop the event */
    673     {
    674             drop    = TRUE;
    675     }
    676 
    677     if (reject)
    678     {
    679         /* reject unsupported opcode */
    680         p_rsp           = p_pkt; /* this also sets free = FALSE, drop = TRUE */
    681         p_rsp_data      = avrc_get_data_ptr(p_pkt);
    682         *p_rsp_data     = AVRC_RSP_REJ;
    683 #if (BT_USE_TRACES == TRUE)
    684         p_drop_msg = "rejected";
    685 #endif
    686         cr      = AVCT_RSP;
    687         drop    = TRUE;
    688     }
    689 
    690     if (p_rsp)
    691     {
    692         /* set to send response right away */
    693         AVCT_MsgReq( handle, label, cr, p_rsp);
    694         free = FALSE;
    695         drop = TRUE;
    696     }
    697 
    698     if (drop == FALSE)
    699     {
    700         msg.hdr.opcode = opcode;
    701         (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
    702     }
    703 #if (BT_USE_TRACES == TRUE)
    704     else
    705     {
    706         AVRC_TRACE_WARNING5("avrc_msg_cback %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
    707                 p_drop_msg,
    708                 handle, avrc_cb.ccb[handle].control, cr, opcode);
    709     }
    710 #endif
    711 
    712 
    713     if (free)
    714         GKI_freebuf(p_pkt);
    715 }
    716 
    717 
    718 
    719 
    720 /******************************************************************************
    721 **
    722 ** Function         avrc_pass_msg
    723 **
    724 ** Description      Compose a PASS THROUGH command according to p_msg
    725 **
    726 **                  Input Parameters:
    727 **                      p_msg: Pointer to PASS THROUGH message structure.
    728 **
    729 **                  Output Parameters:
    730 **                      None.
    731 **
    732 ** Returns          pointer to a valid GKI buffer if successful.
    733 **                  NULL if p_msg is NULL.
    734 **
    735 ******************************************************************************/
    736 static BT_HDR  * avrc_pass_msg(tAVRC_MSG_PASS *p_msg)
    737 {
    738     BT_HDR  *p_cmd = NULL;
    739     UINT8   *p_data;
    740 
    741     WC_ASSERT(p_msg != NULL);
    742     WC_ASSERT(AVRC_CMD_POOL_SIZE > (AVRC_MIN_CMD_LEN+p_msg->pass_len));
    743 
    744     if ((p_cmd = (BT_HDR *) GKI_getpoolbuf(AVRC_CMD_POOL_ID)) != NULL)
    745     {
    746         p_cmd->offset   = AVCT_MSG_OFFSET;
    747         p_cmd->layer_specific   = AVCT_DATA_CTRL;
    748         p_data          = (UINT8 *)(p_cmd + 1) + p_cmd->offset;
    749         *p_data++       = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
    750         *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); /* Panel subunit & id=0 */
    751         *p_data++       = AVRC_OP_PASS_THRU;
    752         *p_data         = (AVRC_PASS_OP_ID_MASK&p_msg->op_id);
    753         if (p_msg->state)
    754             *p_data     |= AVRC_PASS_STATE_MASK;
    755         p_data++;
    756 
    757         if (p_msg->op_id == AVRC_ID_VENDOR)
    758         {
    759             *p_data++       = p_msg->pass_len;
    760             if (p_msg->pass_len && p_msg->p_pass_data)
    761             {
    762                 memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len);
    763                 p_data += p_msg->pass_len;
    764             }
    765         }
    766         else /* set msg len to 0 for other op_id */
    767         {
    768             /* set msg len to 0 for other op_id */
    769             *p_data++       = 0;
    770         }
    771         p_cmd->len      = (UINT16) (p_data - (UINT8 *)(p_cmd + 1) - p_cmd->offset);
    772     }
    773     return p_cmd;
    774 }
    775 
    776 /******************************************************************************
    777 **
    778 ** Function         AVRC_Open
    779 **
    780 ** Description      This function is called to open a connection to AVCTP.
    781 **                  The connection can be either an initiator or acceptor, as
    782 **                  determined by the p_ccb->stream parameter.
    783 **                  The connection can be a target, a controller or for both role,
    784 **                  as determined by the p_ccb->control parameter.
    785 **                  By definition, a target connection is an acceptor connection
    786 **                  that waits for an incoming AVCTP connection from the peer.
    787 **                  The connection remains available to the application until
    788 **                  the application closes it by calling AVRC_Close().  The
    789 **                  application does not need to reopen the connection after an
    790 **                  AVRC_CLOSE_IND_EVT is received.
    791 **
    792 **                  Input Parameters:
    793 **                      p_ccb->company_id: Company Identifier.
    794 **
    795 **                      p_ccb->p_ctrl_cback:  Pointer to control callback function.
    796 **
    797 **                      p_ccb->p_msg_cback:  Pointer to message callback function.
    798 **
    799 **                      p_ccb->conn: AVCTP connection role.  This is set to
    800 **                      AVCTP_INT for initiator connections and AVCTP_ACP
    801 **                      for acceptor connections.
    802 **
    803 **                      p_ccb->control: Control role.  This is set to
    804 **                      AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL
    805 **                      for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL)
    806 **                      for connections that support both roles.
    807 **
    808 **                      peer_addr: BD address of peer device.  This value is
    809 **                      only used for initiator connections; for acceptor
    810 **                      connections it can be set to NULL.
    811 **
    812 **                  Output Parameters:
    813 **                      p_handle: Pointer to handle.  This parameter is only
    814 **                                valid if AVRC_SUCCESS is returned.
    815 **
    816 ** Returns          AVRC_SUCCESS if successful.
    817 **                  AVRC_NO_RESOURCES if there are not enough resources to open
    818 **                  the connection.
    819 **
    820 ******************************************************************************/
    821 UINT16 AVRC_Open(UINT8 *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr)
    822 {
    823     UINT16      status;
    824     tAVCT_CC    cc;
    825 
    826     cc.p_ctrl_cback = avrc_ctrl_cback;      /* Control callback */
    827     cc.p_msg_cback  = avrc_msg_cback;       /* Message callback */
    828     cc.pid          = UUID_SERVCLASS_AV_REMOTE_CONTROL;  /* Profile ID */
    829     cc.role         = p_ccb->conn;          /* Initiator/acceptor role */
    830     cc.control      = p_ccb->control;       /* Control role (Control/Target) */
    831 
    832     status = AVCT_CreateConn(p_handle, &cc, peer_addr);
    833     if (status == AVCT_SUCCESS)
    834     {
    835         memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
    836 #if (AVRC_METADATA_INCLUDED == TRUE)
    837         memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB));
    838         memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
    839 #endif
    840     }
    841     AVRC_TRACE_DEBUG4("AVRC_Open role: %d, control:%d status:%d, handle:%d", cc.role, cc.control,
    842         status, *p_handle);
    843 
    844     return status;
    845 }
    846 
    847 /******************************************************************************
    848 **
    849 ** Function         AVRC_Close
    850 **
    851 ** Description      Close a connection opened with AVRC_Open().
    852 **                  This function is called when the
    853 **                  application is no longer using a connection.
    854 **
    855 **                  Input Parameters:
    856 **                      handle: Handle of this connection.
    857 **
    858 **                  Output Parameters:
    859 **                      None.
    860 **
    861 ** Returns          AVRC_SUCCESS if successful.
    862 **                  AVRC_BAD_HANDLE if handle is invalid.
    863 **
    864 ******************************************************************************/
    865 UINT16 AVRC_Close(UINT8 handle)
    866 {
    867     AVRC_TRACE_DEBUG1("AVRC_Close handle:%d", handle);
    868     return AVCT_RemoveConn(handle);
    869 }
    870 
    871 
    872 /******************************************************************************
    873 **
    874 ** Function         AVRC_MsgReq
    875 **
    876 ** Description      This function is used to send the AVRCP byte stream in p_pkt
    877 **                  down to AVCTP.
    878 **
    879 **                  It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET
    880 **                  p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE
    881 **                  p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
    882 **                  The above BT_HDR settings are set by the AVRC_Bld* functions.
    883 **
    884 ** Returns          AVRC_SUCCESS if successful.
    885 **                  AVRC_BAD_HANDLE if handle is invalid.
    886 **
    887 ******************************************************************************/
    888 UINT16 AVRC_MsgReq (UINT8 handle, UINT8 label, UINT8 ctype, BT_HDR *p_pkt)
    889 {
    890 #if (AVRC_METADATA_INCLUDED == TRUE)
    891     UINT8   *p_data;
    892     UINT8   cr = AVCT_CMD;
    893     BOOLEAN chk_frag = TRUE;
    894     UINT8   *p_start = NULL;
    895     tAVRC_FRAG_CB   *p_fcb;
    896     UINT16  len;
    897     BT_HDR  *p_pkt_new;
    898 
    899     if (!p_pkt)
    900         return AVRC_BAD_PARAM;
    901 
    902     if (ctype >= AVRC_RSP_NOT_IMPL)
    903         cr = AVCT_RSP;
    904 
    905     if (p_pkt->event == AVRC_OP_VENDOR)
    906     {
    907         /* add AVRCP Vendor Dependent headers */
    908         p_start = ((UINT8 *)(p_pkt + 1) + p_pkt->offset);
    909         p_pkt->offset -= AVRC_VENDOR_HDR_SIZE;
    910         p_pkt->len += AVRC_VENDOR_HDR_SIZE;
    911         p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    912         *p_data++       = (ctype & AVRC_CTYPE_MASK);
    913         *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
    914         *p_data++       = AVRC_OP_VENDOR;
    915         AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
    916     }
    917     else if (p_pkt->event == AVRC_OP_PASS_THRU)
    918     {
    919         /* add AVRCP Pass Through headers */
    920         p_start = ((UINT8 *)(p_pkt + 1) + p_pkt->offset);
    921         p_pkt->offset -= AVRC_PASS_THRU_SIZE;
    922         p_pkt->len += AVRC_PASS_THRU_SIZE;
    923         p_data = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
    924         *p_data++       = (ctype & AVRC_CTYPE_MASK);
    925         *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
    926         *p_data++       = AVRC_OP_PASS_THRU;/* opcode */
    927         *p_data++       = AVRC_ID_VENDOR;   /* operation id */
    928         *p_data++       = 5;                /* operation data len */
    929         AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
    930     }
    931 
    932     /* abandon previous fragments */
    933     p_fcb = &avrc_cb.fcb[handle];
    934     if (p_fcb->frag_enabled)
    935         p_fcb->frag_enabled = FALSE;
    936 
    937     if (p_fcb->p_fmsg)
    938     {
    939         GKI_freebuf(p_fcb->p_fmsg);
    940         p_fcb->p_fmsg = NULL;
    941     }
    942 
    943     /* AVRCP spec has not defined any control channel commands that needs fragmentation at this level
    944      * check for fragmentation only on the response */
    945     if ((cr == AVCT_RSP) && (chk_frag == TRUE))
    946     {
    947         if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN)
    948         {
    949             AVRC_TRACE_DEBUG1 ("p_pkt->len(%d) > AVRC_MAX_CTRL_DATA_LEN", p_pkt->len );
    950             p_pkt_new = (BT_HDR *)GKI_getbuf((UINT16)(AVRC_PACKET_LEN + AVCT_MSG_OFFSET
    951                 + BT_HDR_SIZE));
    952             if (p_pkt_new)
    953             {
    954                 p_fcb->frag_enabled = TRUE;
    955                 p_fcb->p_fmsg       = p_pkt;
    956                 p_fcb->frag_pdu     = *p_start;
    957                 p_pkt               = p_pkt_new;
    958                 p_pkt_new           = p_fcb->p_fmsg;
    959                 p_pkt->len          = AVRC_MAX_CTRL_DATA_LEN;
    960                 p_pkt->offset       = p_pkt_new->offset;
    961                 p_pkt->layer_specific = p_pkt_new->layer_specific;
    962                 p_pkt->event = p_pkt_new->event;
    963                 p_data = (UINT8 *)(p_pkt+1) + p_pkt->offset;
    964                 p_start -= AVRC_VENDOR_HDR_SIZE;
    965                 memcpy (p_data, p_start, AVRC_MAX_CTRL_DATA_LEN);
    966                 /* use AVRC start packet type */
    967                 p_data += AVRC_VENDOR_HDR_SIZE;
    968                 p_data++; /* pdu */
    969                 *p_data++ = AVRC_PKT_START;
    970                 /* 4 pdu, pkt_type & len */
    971                 len = (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
    972                 UINT16_TO_BE_STREAM(p_data, len);
    973 
    974                 /* prepare the left over for as an end fragment */
    975                 avrc_prep_end_frag (handle);
    976                 AVRC_TRACE_DEBUG3 ("p_pkt len:%d/%d, next len:%d", p_pkt->len, len, p_fcb->p_fmsg->len );
    977             }
    978             else
    979             {
    980                 AVRC_TRACE_ERROR0 ("AVRC_MsgReq no buffers for fragmentation" );
    981                 GKI_freebuf(p_pkt);
    982     return AVRC_NO_RESOURCES;
    983 }
    984         }
    985     }
    986 
    987     return AVCT_MsgReq( handle, label, cr, p_pkt);
    988 #else
    989     return AVRC_NO_RESOURCES;
    990 #endif
    991 }
    992 
    993 
    994 /******************************************************************************
    995 **
    996 ** Function         AVRC_PassCmd
    997 **
    998 ** Description      Send a PASS THROUGH command to the peer device.  This
    999 **                  function can only be called for controller role connections.
   1000 **                  Any response message from the peer is passed back through
   1001 **                  the tAVRC_MSG_CBACK callback function.
   1002 **
   1003 **                  Input Parameters:
   1004 **                      handle: Handle of this connection.
   1005 **
   1006 **                      label: Transaction label.
   1007 **
   1008 **                      p_msg: Pointer to PASS THROUGH message structure.
   1009 **
   1010 **                  Output Parameters:
   1011 **                      None.
   1012 **
   1013 ** Returns          AVRC_SUCCESS if successful.
   1014 **                  AVRC_BAD_HANDLE if handle is invalid.
   1015 **
   1016 ******************************************************************************/
   1017 UINT16 AVRC_PassCmd(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg)
   1018 {
   1019     BT_HDR *p_buf;
   1020     WC_ASSERT(p_msg != NULL);
   1021     if (p_msg)
   1022     {
   1023         p_msg->hdr.ctype    = AVRC_CMD_CTRL;
   1024         p_buf = avrc_pass_msg(p_msg);
   1025         if (p_buf)
   1026             return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
   1027     }
   1028     return AVRC_NO_RESOURCES;
   1029 }
   1030 
   1031 /******************************************************************************
   1032 **
   1033 ** Function         AVRC_PassRsp
   1034 **
   1035 ** Description      Send a PASS THROUGH response to the peer device.  This
   1036 **                  function can only be called for target role connections.
   1037 **                  This function must be called when a PASS THROUGH command
   1038 **                  message is received from the peer through the
   1039 **                  tAVRC_MSG_CBACK callback function.
   1040 **
   1041 **                  Input Parameters:
   1042 **                      handle: Handle of this connection.
   1043 **
   1044 **                      label: Transaction label.  Must be the same value as
   1045 **                      passed with the command message in the callback function.
   1046 **
   1047 **                      p_msg: Pointer to PASS THROUGH message structure.
   1048 **
   1049 **                  Output Parameters:
   1050 **                      None.
   1051 **
   1052 ** Returns          AVRC_SUCCESS if successful.
   1053 **                  AVRC_BAD_HANDLE if handle is invalid.
   1054 **
   1055 ******************************************************************************/
   1056 UINT16 AVRC_PassRsp(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg)
   1057 {
   1058     BT_HDR *p_buf;
   1059     WC_ASSERT(p_msg != NULL);
   1060     if (p_msg)
   1061     {
   1062         p_buf = avrc_pass_msg(p_msg);
   1063         if (p_buf)
   1064             return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
   1065     }
   1066     return AVRC_NO_RESOURCES;
   1067 }
   1068 
   1069