New call-in/-back functions for Controller to do vendor-specific shutdown (2/2)

A pair of asynchronous call-in and call-back API are added into the Host
Controller Vendor Lib interface (bt_vendor_lib.h). The caller calls this new
call-in function to inform the vendor module to perform vendor-specific
shutdown process (e.g. send HCI_RESET to BT Controller) before the caller calls
for interface cleanup() function. The vendor module is responsible for calling
call-back function to notify the caller completion of vendor-specific shutdown
process.

Sample codes of sending a HCI_RESET command in the vendor-specific shutdown
process.
bug 7390787

Change-Id: I817c0a7dd57e750d38884746edeb3436cfc9cfd8
diff --git a/include/bt_vendor_brcm.h b/include/bt_vendor_brcm.h
index 858b71b..8f336bd 100644
--- a/include/bt_vendor_brcm.h
+++ b/include/bt_vendor_brcm.h
@@ -349,6 +349,16 @@
 #define PCM_DATA_FMT_JUSTIFY_MODE       0
 #endif
 
+/* HW_END_WITH_HCI_RESET
+
+    Sample code implementation of sending a HCI_RESET command during the epilog
+    process. It calls back to the callers after command complete of HCI_RESET
+    is received.
+*/
+#ifndef HW_END_WITH_HCI_RESET
+#define HW_END_WITH_HCI_RESET    TRUE
+#endif
+
 /******************************************************************************
 **  Extern variables and functions
 ******************************************************************************/
diff --git a/src/bt_vendor_brcm.c b/src/bt_vendor_brcm.c
index 9bd8922..ef6236f 100644
--- a/src/bt_vendor_brcm.c
+++ b/src/bt_vendor_brcm.c
@@ -53,6 +53,9 @@
 void hw_sco_config(void);
 #endif
 void vnd_load_conf(const char *p_path);
+#if (HW_END_WITH_HCI_RESET == TRUE)
+void hw_epilog_process(void);
+#endif
 
 /******************************************************************************
 **  Variables
@@ -203,6 +206,19 @@
                 hw_lpm_set_wake_state(wake_assert);
             }
             break;
+
+        case BT_VND_OP_EPILOG:
+            {
+#if (HW_END_WITH_HCI_RESET == FALSE)
+                if (bt_vendor_cbacks)
+                {
+                    bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
+                }
+#else
+                hw_epilog_process();
+#endif
+            }
+            break;
     }
 
     return retval;
diff --git a/src/hardware.c b/src/hardware.c
index 45008ef..c8bf746 100644
--- a/src/hardware.c
+++ b/src/hardware.c
@@ -1231,3 +1231,89 @@
 }
 #endif  //VENDOR_LIB_RUNTIME_TUNING_ENABLED
 
+/*****************************************************************************
+**   Sample Codes Section
+*****************************************************************************/
+
+#if (HW_END_WITH_HCI_RESET == TRUE)
+/*******************************************************************************
+**
+** Function         hw_epilog_cback
+**
+** Description      Callback function for Command Complete Events from HCI
+**                  commands sent in epilog process.
+**
+** Returns          None
+**
+*******************************************************************************/
+void hw_epilog_cback(void *p_mem)
+{
+    HC_BT_HDR   *p_evt_buf = (HC_BT_HDR *) p_mem;
+    uint8_t     *p, status;
+    uint16_t    opcode;
+
+    status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE);
+    p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
+    STREAM_TO_UINT16(opcode,p);
+
+    BTHWDBG("%s Opcode:0x%04X Status: %d", __FUNCTION__, opcode, status);
+
+    if (bt_vendor_cbacks)
+    {
+        /* Must free the RX event buffer */
+        bt_vendor_cbacks->dealloc(p_evt_buf);
+
+        /* Once epilog process is done, must call epilog_cb callback
+           to notify caller */
+        bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         hw_epilog_process
+**
+** Description      Sample implementation of epilog process
+**
+** Returns          None
+**
+*******************************************************************************/
+void hw_epilog_process(void)
+{
+    HC_BT_HDR  *p_buf = NULL;
+    uint8_t     *p;
+
+    BTHWDBG("hw_epilog_process");
+
+    /* Sending a HCI_RESET */
+    if (bt_vendor_cbacks)
+    {
+        /* Must allocate command buffer via HC's alloc API */
+        p_buf = (HC_BT_HDR *) bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + \
+                                                       HCI_CMD_PREAMBLE_SIZE);
+    }
+
+    if (p_buf)
+    {
+        p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+        p_buf->offset = 0;
+        p_buf->layer_specific = 0;
+        p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+        p = (uint8_t *) (p_buf + 1);
+        UINT16_TO_STREAM(p, HCI_RESET);
+        *p = 0; /* parameter length */
+
+        /* Send command via HC's xmit_cb API */
+        bt_vendor_cbacks->xmit_cb(HCI_RESET, p_buf, hw_epilog_cback);
+    }
+    else
+    {
+        if (bt_vendor_cbacks)
+        {
+            ALOGE("vendor lib epilog process aborted [no buffer]");
+            bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_FAIL);
+        }
+    }
+}
+#endif // (HW_END_WITH_HCI_RESET == TRUE)