• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/logging.h>
18 #include <android-base/properties.h>
19 #include <android-base/stringprintf.h>
20 #include <dlfcn.h>
21 #include <errno.h>
22 #include <pthread.h>
23 #include <string.h>
24 
25 #include "Cf_hal_api.h"
26 #include "hardware_nfc.h"
27 
28 using android::base::StringPrintf;
29 
30 bool hal_opened = false;
31 bool dbg_logging = false;
32 pthread_mutex_t hmutex = PTHREAD_MUTEX_INITIALIZER;
33 nfc_stack_callback_t* e_cback;
34 nfc_stack_data_callback_t* d_cback;
35 
36 static struct aidl_callback_struct {
37   pthread_mutex_t mutex;
38   pthread_cond_t cond;
39   pthread_t thr;
40   int event_pending;
41   int stop_thread;
42   int thread_running;
43   nfc_event_t event;
44   nfc_status_t event_status;
45 } aidl_callback_data;
46 
aidl_callback_thread_fct(void * arg)47 static void* aidl_callback_thread_fct(void* arg) {
48   int ret;
49   struct aidl_callback_struct* pcb_data = (struct aidl_callback_struct*)arg;
50 
51   ret = pthread_mutex_lock(&pcb_data->mutex);
52   if (ret != 0) {
53     LOG(ERROR) << StringPrintf("%s pthread_mutex_lock failed", __func__);
54     goto error;
55   }
56 
57   do {
58     if (pcb_data->event_pending == 0) {
59       ret = pthread_cond_wait(&pcb_data->cond, &pcb_data->mutex);
60       if (ret != 0) {
61         LOG(ERROR) << StringPrintf("%s pthread_cond_wait failed", __func__);
62         break;
63       }
64     }
65 
66     if (pcb_data->event_pending) {
67       nfc_event_t event = pcb_data->event;
68       nfc_status_t event_status = pcb_data->event_status;
69       int ending = pcb_data->stop_thread;
70       pcb_data->event_pending = 0;
71       ret = pthread_cond_signal(&pcb_data->cond);
72       if (ret != 0) {
73         LOG(ERROR) << StringPrintf("%s pthread_cond_signal failed", __func__);
74         break;
75       }
76       if (ending) {
77         pcb_data->thread_running = 0;
78       }
79       ret = pthread_mutex_unlock(&pcb_data->mutex);
80       if (ret != 0) {
81         LOG(ERROR) << StringPrintf("%s pthread_mutex_unlock failed", __func__);
82       }
83       LOG(INFO) << StringPrintf("%s event %hhx status %hhx", __func__, event,
84                                 event_status);
85       e_cback(event, event_status);
86       usleep(50000);
87       if (ending) {
88         return NULL;
89       }
90       ret = pthread_mutex_lock(&pcb_data->mutex);
91       if (ret != 0) {
92         LOG(ERROR) << StringPrintf("%s pthread_mutex_lock failed", __func__);
93         goto error;
94       }
95     }
96   } while (pcb_data->stop_thread == 0 || pcb_data->event_pending);
97 
98   ret = pthread_mutex_unlock(&pcb_data->mutex);
99   if (ret != 0) {
100     LOG(ERROR) << StringPrintf("%s pthread_mutex_unlock failed", __func__);
101   }
102 
103 error:
104   pcb_data->thread_running = 0;
105   return NULL;
106 }
107 
aidl_callback_thread_start()108 static int aidl_callback_thread_start() {
109   int ret;
110   LOG(INFO) << StringPrintf("%s", __func__);
111 
112   memset(&aidl_callback_data, 0, sizeof(aidl_callback_data));
113 
114   ret = pthread_mutex_init(&aidl_callback_data.mutex, NULL);
115   if (ret != 0) {
116     LOG(ERROR) << StringPrintf("%s pthread_mutex_init failed", __func__);
117     return ret;
118   }
119 
120   ret = pthread_cond_init(&aidl_callback_data.cond, NULL);
121   if (ret != 0) {
122     LOG(ERROR) << StringPrintf("%s pthread_cond_init failed", __func__);
123     return ret;
124   }
125 
126   aidl_callback_data.thread_running = 1;
127 
128   ret = pthread_create(&aidl_callback_data.thr, NULL, aidl_callback_thread_fct,
129                        &aidl_callback_data);
130   if (ret != 0) {
131     LOG(ERROR) << StringPrintf("%s pthread_create failed", __func__);
132     aidl_callback_data.thread_running = 0;
133     return ret;
134   }
135 
136   return 0;
137 }
138 
aidl_callback_thread_end()139 static int aidl_callback_thread_end() {
140   LOG(INFO) << StringPrintf("%s", __func__);
141   if (aidl_callback_data.thread_running != 0) {
142     int ret;
143 
144     ret = pthread_mutex_lock(&aidl_callback_data.mutex);
145     if (ret != 0) {
146       LOG(ERROR) << StringPrintf("%s pthread_mutex_lock failed", __func__);
147       return ret;
148     }
149 
150     aidl_callback_data.stop_thread = 1;
151 
152     // Wait for the thread to have no event pending
153     while (aidl_callback_data.thread_running &&
154            aidl_callback_data.event_pending) {
155       ret = pthread_cond_signal(&aidl_callback_data.cond);
156       if (ret != 0) {
157         LOG(ERROR) << StringPrintf("%s pthread_cond_signal failed", __func__);
158         return ret;
159       }
160       ret = pthread_cond_wait(&aidl_callback_data.cond,
161                               &aidl_callback_data.mutex);
162       if (ret != 0) {
163         LOG(ERROR) << StringPrintf("%s pthread_cond_wait failed", __func__);
164         break;
165       }
166     }
167 
168     ret = pthread_mutex_unlock(&aidl_callback_data.mutex);
169     if (ret != 0) {
170       LOG(ERROR) << StringPrintf("%s pthread_mutex_unlock failed", __func__);
171       return ret;
172     }
173 
174     ret = pthread_cond_signal(&aidl_callback_data.cond);
175     if (ret != 0) {
176       LOG(ERROR) << StringPrintf("%s pthread_cond_signal failed", __func__);
177       return ret;
178     }
179 
180     ret = pthread_detach(aidl_callback_data.thr);
181     if (ret != 0) {
182       LOG(ERROR) << StringPrintf("%s pthread_detach failed", __func__);
183       return ret;
184     }
185   }
186   return 0;
187 }
188 
aidl_callback_post(nfc_event_t event,nfc_status_t event_status)189 static void aidl_callback_post(nfc_event_t event, nfc_status_t event_status) {
190   int ret;
191 
192   if (pthread_equal(pthread_self(), aidl_callback_data.thr)) {
193     e_cback(event, event_status);
194   }
195 
196   ret = pthread_mutex_lock(&aidl_callback_data.mutex);
197   if (ret != 0) {
198     LOG(ERROR) << StringPrintf("%s pthread_mutex_lock failed", __func__);
199     return;
200   }
201 
202   if (aidl_callback_data.thread_running == 0) {
203     (void)pthread_mutex_unlock(&aidl_callback_data.mutex);
204     LOG(ERROR) << StringPrintf("%s thread is not running", __func__);
205     e_cback(event, event_status);
206     return;
207   }
208 
209   while (aidl_callback_data.event_pending) {
210     ret =
211         pthread_cond_wait(&aidl_callback_data.cond, &aidl_callback_data.mutex);
212     if (ret != 0) {
213       LOG(ERROR) << StringPrintf("%s pthread_cond_wait failed", __func__);
214       return;
215     }
216   }
217 
218   aidl_callback_data.event_pending = 1;
219   aidl_callback_data.event = event;
220   aidl_callback_data.event_status = event_status;
221 
222   ret = pthread_mutex_unlock(&aidl_callback_data.mutex);
223   if (ret != 0) {
224     LOG(ERROR) << StringPrintf("%s pthread_mutex_unlock failed", __func__);
225     return;
226   }
227 
228   ret = pthread_cond_signal(&aidl_callback_data.cond);
229   if (ret != 0) {
230     LOG(ERROR) << StringPrintf("%s pthread_cond_signal failed", __func__);
231     return;
232   }
233 }
234 
Cf_hal_open(nfc_stack_callback_t * p_cback,nfc_stack_data_callback_t * p_data_cback)235 int Cf_hal_open(nfc_stack_callback_t* p_cback,
236                 nfc_stack_data_callback_t* p_data_cback) {
237   LOG(INFO) << StringPrintf("%s", __func__);
238   pthread_mutex_lock(&hmutex);
239   if (hal_opened) {
240     // already opened, close then open again
241     LOG(INFO) << StringPrintf("%s close and open again", __func__);
242     if (aidl_callback_data.thread_running && aidl_callback_thread_end() != 0) {
243       pthread_mutex_unlock(&hmutex);
244       return -1;
245     }
246     hal_opened = false;
247   }
248   e_cback = p_cback;
249   d_cback = p_data_cback;
250   if ((hal_opened || !aidl_callback_data.thread_running) &&
251       (aidl_callback_thread_start() != 0)) {
252     // status failed
253     LOG(INFO) << StringPrintf("%s failed", __func__);
254     aidl_callback_post(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_FAILED);
255     pthread_mutex_unlock(&hmutex);
256     return -1;
257   }
258   hal_opened = true;
259   aidl_callback_post(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_OK);
260   pthread_mutex_unlock(&hmutex);
261   return 0;
262 }
263 
Cf_hal_write(uint16_t data_len,const uint8_t * p_data)264 int Cf_hal_write(uint16_t data_len, const uint8_t* p_data) {
265   if (!hal_opened) return -1;
266   // TODO: write NCI state machine
267   (void)data_len;
268   (void)p_data;
269   return 0;
270 }
271 
Cf_hal_core_initialized()272 int Cf_hal_core_initialized() {
273   if (!hal_opened) return -1;
274   pthread_mutex_lock(&hmutex);
275   aidl_callback_post(HAL_NFC_POST_INIT_CPLT_EVT, HAL_NFC_STATUS_OK);
276   pthread_mutex_unlock(&hmutex);
277   return 0;
278 }
279 
Cf_hal_pre_discover()280 int Cf_hal_pre_discover() {
281   if (!hal_opened) return -1;
282   pthread_mutex_lock(&hmutex);
283   aidl_callback_post(HAL_NFC_PRE_DISCOVER_CPLT_EVT, HAL_NFC_STATUS_OK);
284   pthread_mutex_unlock(&hmutex);
285   return 0;
286 }
287 
Cf_hal_close()288 int Cf_hal_close() {
289   LOG(INFO) << StringPrintf("%s", __func__);
290   if (!hal_opened) return -1;
291   pthread_mutex_lock(&hmutex);
292   hal_opened = false;
293   aidl_callback_post(HAL_NFC_CLOSE_CPLT_EVT, HAL_NFC_STATUS_OK);
294   if (aidl_callback_data.thread_running && aidl_callback_thread_end() != 0) {
295     LOG(ERROR) << StringPrintf("%s thread end failed", __func__);
296     pthread_mutex_unlock(&hmutex);
297     return -1;
298   }
299   pthread_mutex_unlock(&hmutex);
300   return 0;
301 }
302 
Cf_hal_close_off()303 int Cf_hal_close_off() {
304   LOG(INFO) << StringPrintf("%s", __func__);
305   if (!hal_opened) return -1;
306   pthread_mutex_lock(&hmutex);
307   hal_opened = false;
308   aidl_callback_post(HAL_NFC_CLOSE_CPLT_EVT, HAL_NFC_STATUS_OK);
309   if (aidl_callback_data.thread_running && aidl_callback_thread_end() != 0) {
310     LOG(ERROR) << StringPrintf("%s thread end failed", __func__);
311     pthread_mutex_unlock(&hmutex);
312     return -1;
313   }
314   pthread_mutex_unlock(&hmutex);
315   return 0;
316 }
317 
Cf_hal_power_cycle()318 int Cf_hal_power_cycle() {
319   if (!hal_opened) return -1;
320   pthread_mutex_lock(&hmutex);
321   aidl_callback_post(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_OK);
322   pthread_mutex_unlock(&hmutex);
323   return 0;
324 }
325 
Cf_hal_factoryReset()326 void Cf_hal_factoryReset() {}
Cf_hal_getConfig(NfcConfig & config)327 void Cf_hal_getConfig(NfcConfig& config) {
328   // TODO: read config from /vendor/etc/libnfc-hal-cf.conf
329   memset(&config, 0x00, sizeof(NfcConfig));
330   config.nfaPollBailOutMode = 1;
331   config.maxIsoDepTransceiveLength = 0xFEFF;
332   config.defaultOffHostRoute = 0x81;
333   config.defaultOffHostRouteFelica = 0x81;
334   config.defaultSystemCodeRoute = 0x00;
335   config.defaultSystemCodePowerState = 0x3B;
336   config.defaultRoute = 0x00;
337   config.offHostRouteUicc.resize(1);
338   config.offHostRouteUicc[0] = 0x81;
339   config.offHostRouteEse.resize(1);
340   config.offHostRouteEse[0] = 0x81;
341   config.defaultIsoDepRoute = 0x81;
342 }
343 
Cf_hal_setVerboseLogging(bool enable)344 void Cf_hal_setVerboseLogging(bool enable) { dbg_logging = enable; }
345 
Cf_hal_getVerboseLogging()346 bool Cf_hal_getVerboseLogging() { return dbg_logging; }
347