1 /*
2  * Copyright (C) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "allocator.h"
16 #include "cmd/hci_cmd.h"
17 #include "log.h"
18 #include "platform/include/list.h"
19 #include "platform/include/mutex.h"
20 #include "hci_vendor_if.h"
21 
22 typedef struct {
23     const HCIVendorEventCallback *callback;
24     void *context;
25 } HCIVendorEventCallbackBlock;
26 
27 static List *g_hciVendorCallbackList = NULL;
28 static Mutex *g_hciVendorCallbackListLock = NULL;
29 
HCIVendorAllocCallbackBlock(const HCIVendorEventCallback * callback,void * context)30 static HCIVendorEventCallbackBlock *HCIVendorAllocCallbackBlock(const HCIVendorEventCallback *callback, void *context)
31 {
32     HCIVendorEventCallbackBlock *block = MEM_MALLOC.alloc(sizeof(HCIVendorEventCallbackBlock));
33     if (block != NULL) {
34         block->callback = (HCIVendorEventCallback *)callback;
35         block->context = context;
36     }
37     return block;
38 }
39 
HCIVendorFreeCallbacksBlock(void * block)40 static void HCIVendorFreeCallbacksBlock(void *block)
41 {
42     MEM_MALLOC.free(block);
43 }
44 
HciVendorClosed(void)45 NO_SANITIZE("cfi") void HciVendorClosed(void)
46 {
47     if (g_hciVendorCallbackListLock == NULL) {
48         LOG_ERROR("g_hciVendorCallbackListLock is null");
49         return;
50     }
51     HCIVendorEventCallbackBlock *block = NULL;
52     MutexLock(g_hciVendorCallbackListLock);
53     ListNode *node = ListGetFirstNode(g_hciVendorCallbackList);
54     while (node != NULL) {
55         block = ListGetNodeData(node);
56         if (block->callback != NULL && block->callback->hciVendorClosed != NULL) {
57             block->callback->hciVendorClosed(block->context);
58         }
59         node = ListGetNextNode(node);
60     }
61     MutexUnlock(g_hciVendorCallbackListLock);
62 }
63 
HciVendorInit(void)64 void HciVendorInit(void)
65 {
66     g_hciVendorCallbackList = ListCreate(HCIVendorFreeCallbacksBlock);
67     if (g_hciVendorCallbackList == NULL) {
68         LOG_ERROR("%{public}s:malloc error.", __FUNCTION__);
69     }
70 
71     g_hciVendorCallbackListLock = MutexCreate();
72     if (g_hciVendorCallbackListLock == NULL) {
73         LOG_ERROR("%{public}s:create mutex error.", __FUNCTION__);
74     }
75 }
76 
HciVendorClose(void)77 void HciVendorClose(void)
78 {
79     HciVendorClosed();
80     if (g_hciVendorCallbackListLock != NULL) {
81         MutexDelete(g_hciVendorCallbackListLock);
82         g_hciVendorCallbackListLock = NULL;
83     }
84 
85     if (g_hciVendorCallbackList != NULL) {
86         ListDelete(g_hciVendorCallbackList);
87         g_hciVendorCallbackList = NULL;
88     }
89 }
90 
HCIVIF_RegisterVendorEventCallback(const HCIVendorEventCallback * callback,void * context)91 int HCIVIF_RegisterVendorEventCallback(
92     const HCIVendorEventCallback *callback, void *context)
93 {
94     if (callback == NULL) {
95         LOG_ERROR("%{public}s: callback is null", __FUNCTION__);
96         return BT_BAD_PARAM;
97     }
98 
99     if ((g_hciVendorCallbackList == NULL) || ((g_hciVendorCallbackListLock == NULL))) {
100         LOG_ERROR("%{public}s: hci vendor not ready", __FUNCTION__);
101         return BT_BAD_STATUS;
102     }
103 
104     HCIVendorEventCallbackBlock *block = HCIVendorAllocCallbackBlock(callback, context);
105     if (block == NULL) {
106         return BT_NO_MEMORY;
107     }
108 
109     MutexLock(g_hciVendorCallbackListLock);
110     ListAddLast(g_hciVendorCallbackList, block);
111     MutexUnlock(g_hciVendorCallbackListLock);
112 
113     return BT_SUCCESS;
114 }
115 
HCIVIF_DeregisterVendorEventCallback(const HCIVendorEventCallback * callback)116 int HCIVIF_DeregisterVendorEventCallback(const HCIVendorEventCallback *callback)
117 {
118     if (callback == NULL) {
119         return BT_BAD_PARAM;
120     }
121 
122     if ((g_hciVendorCallbackList == NULL) || ((g_hciVendorCallbackListLock == NULL))) {
123         LOG_ERROR("%{public}s: hci vendor not ready", __FUNCTION__);
124         return BT_BAD_STATUS;
125     }
126 
127     MutexLock(g_hciVendorCallbackListLock);
128 
129     HCIVendorEventCallbackBlock *block = NULL;
130     ListNode *node = ListGetFirstNode(g_hciVendorCallbackList);
131     while (node != NULL) {
132         block = ListGetNodeData(node);
133         if (block != NULL) {
134             if (block->callback == callback) {
135                 ListRemoveNode(g_hciVendorCallbackList, block);
136                 break;
137             }
138         }
139         node = ListGetNextNode(node);
140     }
141 
142     MutexUnlock(g_hciVendorCallbackListLock);
143 
144     return BT_SUCCESS;
145 }
146 
HCIVIF_SendCmd(uint16_t opCode,const void * param,size_t paramLength)147 int HCIVIF_SendCmd(uint16_t opCode, const void *param, size_t paramLength)
148 {
149     HciCmd *cmd = HciAllocCmd(opCode, param, paramLength);
150     return HciSendCmd(cmd);
151 }
152 
HciEventOnVendorCommandComplete(uint16_t opCode,const void * param,uint8_t paramLength)153 NO_SANITIZE("cfi") void HciEventOnVendorCommandComplete(uint16_t opCode, const void *param, uint8_t paramLength)
154 {
155     if (g_hciVendorCallbackListLock == NULL) {
156         LOG_ERROR("g_hciVendorCallbackListLock is null");
157         return;
158     }
159     HCIVendorEventCallbackBlock *block = NULL;
160     MutexLock(g_hciVendorCallbackListLock);
161     ListNode *node = ListGetFirstNode(g_hciVendorCallbackList);
162     while (node != NULL) {
163         block = ListGetNodeData(node);
164         if (block->callback != NULL && block->callback->hciCommandCompleteEvent != NULL) {
165             block->callback->hciCommandCompleteEvent(opCode, param, paramLength, block->context);
166         }
167         node = ListGetNextNode(node);
168     }
169     MutexUnlock(g_hciVendorCallbackListLock);
170 }
171