You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
13 KiB
448 lines
13 KiB
/*
|
|
* Copyright (C) 2013 SAMSUNG S.LSI
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include <hardware/nfc.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
|
|
#include "device.h"
|
|
#include "hal.h"
|
|
#include "hal_msg.h"
|
|
#include "osi.h"
|
|
#include "util.h"
|
|
|
|
#include <cutils/properties.h>
|
|
|
|
uint32_t fw_update_state = 0;
|
|
/* START [181106] Patch for supporting NCI v2.0 */
|
|
// [1. NCI Version Management]
|
|
int gNciVersion = NCI_VER_1_0; // 0x10 : NCI 1.0, 0x20 : NCI2.0
|
|
/* END [181106] Patch for supporting NCI v2.0 */
|
|
|
|
static void nfc_hal_state_switch(tNFC_HAL_MSG* msg, eHAL_STATE state) {
|
|
tNFC_HAL_MSG* new_msg;
|
|
|
|
new_msg = (tNFC_HAL_MSG*)OSI_mem_get(HAL_EVT_SIZE);
|
|
if (!new_msg) {
|
|
OSI_loge("Failed to memory allocate!");
|
|
nfc_stack_cback(HAL_NFC_ERROR_EVT, HAL_NFC_STATUS_OK);
|
|
return;
|
|
}
|
|
|
|
nfc_hal_info.state = state;
|
|
memcpy(new_msg, msg, sizeof(HAL_EVT_SIZE));
|
|
OSI_queue_put(nfc_hal_info.msg_q, (void*)new_msg);
|
|
}
|
|
|
|
void hal_sleep(__attribute__((unused)) void* param) {
|
|
nfc_hal_info.flag &= ~HAL_FLAG_PROP_ONE_TIMER;
|
|
nfc_hal_info.cfg.override_timeout = 0;
|
|
device_sleep();
|
|
}
|
|
|
|
void hal_update_sleep_timer(void) {
|
|
device_wakeup();
|
|
|
|
/* workaround for double timer */
|
|
if (nfc_hal_info.flag & HAL_FLAG_MASK_USING_TIMER) return;
|
|
|
|
if (nfc_hal_info.flag & HAL_FLAG_PROP_ONE_TIMER)
|
|
OSI_timer_start(nfc_hal_info.sleep_timer, nfc_hal_info.cfg.override_timeout,
|
|
(tOSI_TIMER_CALLBACK)hal_sleep, NULL);
|
|
else
|
|
OSI_timer_start(nfc_hal_info.sleep_timer, nfc_hal_info.cfg.sleep_timeout,
|
|
(tOSI_TIMER_CALLBACK)hal_sleep, NULL);
|
|
}
|
|
|
|
int __send_to_device(uint8_t* data, size_t len) {
|
|
hal_update_sleep_timer();
|
|
if (nfc_hal_info.nci_last_pkt)
|
|
memcpy((void*)nfc_hal_info.nci_last_pkt, (void*)data, len);
|
|
|
|
return device_write(data, len);
|
|
}
|
|
|
|
void nfc_hal_open_sm(tNFC_HAL_MSG* msg) {
|
|
tNFC_NCI_PKT* pkt = &msg->nci_packet;
|
|
|
|
switch (msg->event) {
|
|
case HAL_EVT_OPEN:
|
|
device_set_mode(NFC_DEV_MODE_ON);
|
|
hal_nci_send_prop_fw_cfg();
|
|
break;
|
|
case HAL_EVT_READ:
|
|
nci_read_payload(msg);
|
|
util_nci_analyzer(pkt);
|
|
if (NCI_MT(pkt) != NCI_MT_RSP || NCI_GID(pkt) != NCI_GID_PROP ||
|
|
NCI_OID(pkt) != NCI_PROP_FW_CFG) {
|
|
OSI_logd("Not matched rsponse!! we expect NCI_PROP_FW_CFG_RSP");
|
|
} else {
|
|
if (NCI_STATUS(pkt) != NCI_STATUS_OK &&
|
|
NCI_STATUS(pkt) != NCI_STATUS_E_SYNTAX &&
|
|
NCI_STATUS(pkt) != NCI_CLOCK_STATUS_SYNTAX_ERROR &&
|
|
NCI_STATUS(pkt) != NCI_CLOCK_STATUS_MISMATCHED &&
|
|
NCI_STATUS(pkt) != NCI_CLOCK_STATUS_FULL) {
|
|
OSI_loge("Failed to config FW, status: %d", NCI_STATUS(pkt));
|
|
break;
|
|
} else {
|
|
if (NCI_STATUS(pkt) == NCI_STATUS_OK) {
|
|
nfc_hal_info.state = HAL_STATE_POSTINIT;
|
|
nfc_stack_cback(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_OK);
|
|
break;
|
|
}
|
|
OSI_loge("Failed to config FW, status: %d", NCI_STATUS(pkt));
|
|
}
|
|
}
|
|
break;
|
|
case HAL_EVT_COMPLETE_FAILED:
|
|
device_set_mode(NFC_DEV_MODE_OFF);
|
|
nfc_stack_cback(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_FAILED);
|
|
break;
|
|
|
|
case HAL_EVT_TERMINATE:
|
|
// TODO: terminate
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void nfc_hal_postinit_sm(tNFC_HAL_MSG* msg) {
|
|
tNFC_NCI_PKT* pkt = &msg->nci_packet;
|
|
|
|
switch (msg->event) {
|
|
case HAL_EVT_CORE_INIT:
|
|
nfc_hal_info.vs_info.state = VS_INIT;
|
|
nfc_hal_state_switch(msg, HAL_STATE_VS);
|
|
break;
|
|
|
|
case HAL_EVT_WRITE:
|
|
if (NCI_GID(pkt) == NCI_GID_CORE) {
|
|
if (NCI_OID(pkt) == NCI_CORE_RESET && NCI_LEN(pkt) == 1) {
|
|
if (nfc_hal_info.flag & HAL_FLAG_ALREADY_RESET) goto complete;
|
|
|
|
nfc_hal_info.flag |= HAL_FLAG_W4_CORE_RESET_RSP;
|
|
OSI_timer_start(nfc_hal_info.nci_timer, 1000,
|
|
(tOSI_TIMER_CALLBACK)fw_force_update, NULL);
|
|
OSI_logd("set flag to 0x%06X", nfc_hal_info.flag);
|
|
} else if (NCI_OID(pkt) == NCI_CORE_INIT &&
|
|
(NCI_LEN(pkt) == 0 || NCI_LEN(pkt) == 2)) {
|
|
if (nfc_hal_info.flag & HAL_FLAG_ALREADY_INIT) goto complete;
|
|
|
|
nfc_hal_info.flag |= HAL_FLAG_W4_CORE_INIT_RSP;
|
|
OSI_timer_start(nfc_hal_info.nci_timer, 1000,
|
|
(tOSI_TIMER_CALLBACK)nci_init_timeout, NULL);
|
|
OSI_logd("set flag to 0x%06X", nfc_hal_info.flag);
|
|
}
|
|
}
|
|
hal_nci_send(&msg->nci_packet);
|
|
break;
|
|
|
|
case HAL_EVT_READ:
|
|
nci_read_payload(msg);
|
|
if (NCI_GID(pkt) == NCI_GID_CORE) {
|
|
if (NCI_OID(pkt) == NCI_CORE_RESET) {
|
|
OSI_logd("Respond CORE_RESET_RSP");
|
|
nfc_hal_info.flag &= ~HAL_FLAG_W4_CORE_RESET_RSP;
|
|
nfc_hal_info.flag |= HAL_FLAG_ALREADY_RESET;
|
|
/* START [19082300] Patch for supporting NCI v2.0 */
|
|
// [1. NCI Version Management]
|
|
// gNciVersion : 0x10 : NCI1.0, 0x20 : NCI2.0
|
|
if ((NCI_LEN(pkt) == 0x03) && NCI_MT(pkt) == NCI_MT_RSP)
|
|
gNciVersion = NCI_VER_1_0;
|
|
else {
|
|
gNciVersion = NCI_VER_2_0;
|
|
}
|
|
/* END [19082300] Patch for supporting NCI v2.0 */
|
|
} else if (NCI_OID(pkt) == NCI_CORE_INIT) {
|
|
OSI_logd("Respond CORE_INIT_RSP");
|
|
nfc_hal_info.flag &= ~HAL_FLAG_W4_CORE_INIT_RSP;
|
|
nfc_hal_info.flag |= HAL_FLAG_ALREADY_INIT;
|
|
}
|
|
OSI_timer_stop(nfc_hal_info.nci_timer);
|
|
}
|
|
util_nci_analyzer(pkt);
|
|
nfc_data_callback(&msg->nci_packet);
|
|
break;
|
|
|
|
case HAL_EVT_COMPLETE:
|
|
complete:
|
|
nfc_hal_info.flag |= HAL_FLAG_NTF_TRNS_ERROR | HAL_FLAG_RETRY_TRNS;
|
|
nfc_hal_info.state = HAL_STATE_SERVICE;
|
|
|
|
OSI_logd("Complete postinit sm");
|
|
|
|
nfc_stack_cback(HAL_NFC_POST_INIT_CPLT_EVT, HAL_NFC_STATUS_OK);
|
|
break;
|
|
case HAL_EVT_COMPLETE_FAILED:
|
|
nfc_stack_cback(HAL_NFC_POST_INIT_CPLT_EVT, HAL_NFC_STATUS_FAILED);
|
|
break;
|
|
|
|
/* START - VTS */
|
|
case HAL_EVT_POWER_CYCLE:
|
|
OSI_logt("HAL_EVT_POWER_CYCLE");
|
|
device_sleep();
|
|
device_close();
|
|
OSI_logt("HAL state change to POWERCYCLE");
|
|
nfc_hal_state_switch(msg, HAL_STATE_POWERCYCLE);
|
|
break;
|
|
/* END - VTS */
|
|
|
|
case HAL_EVT_TERMINATE:
|
|
// TODO: terminate
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void nfc_hal_vs_sm(tNFC_HAL_MSG* msg) {
|
|
tNFC_HAL_VS_INFO* vs = &nfc_hal_info.vs_info;
|
|
|
|
if (msg->event != HAL_EVT_READ && msg->event != HAL_EVT_CORE_INIT) {
|
|
OSI_loge("Unexpected event [%d]", msg->event);
|
|
return;
|
|
}
|
|
|
|
if (vs->state != VS_INIT) {
|
|
nci_read_payload(msg);
|
|
util_nci_analyzer(pkt);
|
|
}
|
|
|
|
switch (vs->state) {
|
|
case VS_INIT:
|
|
hal_nci_send_clearLmrt();
|
|
vs->state = VS_W4_COMPLETE;
|
|
break;
|
|
case VS_W4_COMPLETE:
|
|
OSI_logd("Vendor Specific is complete.");
|
|
msg->event = HAL_EVT_COMPLETE;
|
|
nfc_hal_state_switch(msg, HAL_STATE_POSTINIT);
|
|
break;
|
|
default:
|
|
OSI_loge("Unexpected event [%d]", msg->event);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void nfc_hal_service_sm(tNFC_HAL_MSG* msg) {
|
|
tNFC_NCI_PKT* pkt = &msg->nci_packet;
|
|
/* START [H16031401] */
|
|
nfc_hal_info.msg_event = msg->event;
|
|
/* END [H16031401] */
|
|
|
|
switch (msg->event) {
|
|
/* START - VTS */
|
|
case HAL_EVT_CORE_INIT:
|
|
nfc_hal_info.vs_info.state = VS_INIT;
|
|
nfc_hal_state_switch(msg, HAL_STATE_VS);
|
|
break;
|
|
/* END - VTS */
|
|
case HAL_EVT_WRITE:
|
|
if (nfc_hal_prehandler(pkt)) hal_nci_send(pkt);
|
|
break;
|
|
case HAL_EVT_READ:
|
|
nci_read_payload(msg);
|
|
util_nci_analyzer(pkt);
|
|
hal_update_sleep_timer();
|
|
if (nfc_hal_prehandler(pkt)) nfc_data_callback(pkt);
|
|
break;
|
|
case HAL_EVT_CONTROL_GRANTED:
|
|
nfc_hal_state_switch(msg, HAL_STATE_GRANTED);
|
|
break;
|
|
case HAL_EVT_TERMINATE:
|
|
// TODO: terminate
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void nfc_hal_grant_finish(void) {
|
|
nfc_stack_cback(HAL_NFC_RELEASE_CONTROL_EVT, HAL_NFC_STATUS_OK);
|
|
nfc_hal_info.state = HAL_STATE_SERVICE;
|
|
nfc_hal_info.grant_cback = NULL;
|
|
}
|
|
|
|
void nfc_hal_grant_sm(tNFC_HAL_MSG* msg) {
|
|
tNFC_NCI_PKT* pkt = &msg->nci_packet;
|
|
uint8_t cback_ret = HAL_GRANT_FINISH;
|
|
|
|
/* Granted mode is not need to SLEEP.
|
|
* hal should pend granted mode just few time */
|
|
switch (msg->event) {
|
|
case HAL_EVT_READ:
|
|
nci_read_payload(msg);
|
|
util_nci_analyzer(pkt);
|
|
cback_ret = nfc_hal_info.grant_cback(pkt);
|
|
if (cback_ret == HAL_GRANT_FINISH) nfc_hal_grant_finish();
|
|
|
|
if (cback_ret != HAL_GRANT_SEND_NEXT) break;
|
|
[[fallthrough]];
|
|
case HAL_EVT_CONTROL_GRANTED:
|
|
pkt = (tNFC_NCI_PKT*)OSI_queue_get(nfc_hal_info.nci_q);
|
|
if (pkt) {
|
|
// TODO: Should CLF respond?
|
|
hal_nci_send(pkt);
|
|
OSI_mem_free((tOSI_MEM_HANDLER)pkt);
|
|
} else
|
|
nfc_hal_grant_finish();
|
|
|
|
break;
|
|
|
|
case HAL_EVT_WRITE:
|
|
OSI_loge("HAL is in granted mode!");
|
|
break;
|
|
}
|
|
}
|
|
/* START - VTS */
|
|
void nfc_hal_power_sm(tNFC_HAL_MSG* msg) {
|
|
switch (msg->event) {
|
|
case HAL_EVT_POWER_CYCLE:
|
|
// have to do is hal open
|
|
OSI_logt("HAL_EVT_POWER_CYCLE");
|
|
// nfc_hal_init();
|
|
|
|
if (device_open()) return;
|
|
|
|
msg->event = HAL_EVT_OPEN;
|
|
nfc_hal_state_switch(msg, HAL_STATE_OPEN);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
/* END - VTS */
|
|
|
|
/* TASK */
|
|
void nfc_hal_task(void) {
|
|
tNFC_HAL_MSG* msg;
|
|
eHAL_STATE old_st;
|
|
|
|
OSI_logt("enter!");
|
|
|
|
if (!nfc_hal_info.msg_task || !nfc_hal_info.nci_timer ||
|
|
!nfc_hal_info.msg_q || !nfc_hal_info.nci_q) {
|
|
OSI_loge("msg_task = %p, nci_timer = %p, msg_q = %p, nci_q = %p",
|
|
nfc_hal_info.msg_task, nfc_hal_info.nci_timer, nfc_hal_info.msg_q,
|
|
nfc_hal_info.nci_q);
|
|
|
|
nfc_hal_deinit();
|
|
OSI_loge("nfc_hal initialization is not succeeded.");
|
|
nfc_stack_cback(HAL_NFC_ERROR_EVT, HAL_NFC_STATUS_FAILED);
|
|
return;
|
|
}
|
|
|
|
while (OSI_task_isRun(nfc_hal_info.msg_task) == OSI_RUN) {
|
|
msg = (tNFC_HAL_MSG*)OSI_queue_get_wait(nfc_hal_info.msg_q);
|
|
if (!msg) continue;
|
|
|
|
OSI_logd("Got a event: %s(%d)", event_to_string(msg->event), msg->event);
|
|
if (msg->event == HAL_EVT_TERMINATE) break;
|
|
|
|
OSI_logd("current state: %s", state_to_string(nfc_hal_info.state));
|
|
old_st = nfc_hal_info.state;
|
|
switch (nfc_hal_info.state) {
|
|
case HAL_STATE_INIT:
|
|
case HAL_STATE_DEINIT:
|
|
case HAL_STATE_OPEN:
|
|
nfc_hal_open_sm(msg);
|
|
break;
|
|
case HAL_STATE_VS:
|
|
nfc_hal_vs_sm(msg);
|
|
break;
|
|
case HAL_STATE_POSTINIT:
|
|
nfc_hal_postinit_sm(msg);
|
|
break;
|
|
case HAL_STATE_SERVICE:
|
|
nfc_hal_service_sm(msg);
|
|
break;
|
|
case HAL_STATE_GRANTED:
|
|
nfc_hal_grant_sm(msg);
|
|
break;
|
|
/* START - VTS */
|
|
case HAL_STATE_POWERCYCLE:
|
|
nfc_hal_power_sm(msg);
|
|
break;
|
|
/* END - VTS */
|
|
default:
|
|
break;
|
|
}
|
|
OSI_mem_free((tOSI_MEM_HANDLER)msg);
|
|
|
|
if (old_st != nfc_hal_info.state) {
|
|
OSI_logd("hal state is changed: %s -> %s", state_to_string(old_st),
|
|
state_to_string(nfc_hal_info.state));
|
|
}
|
|
}
|
|
OSI_logt("exit!");
|
|
}
|
|
|
|
/* Print */
|
|
const char* event_to_string(uint8_t event) {
|
|
switch (event) {
|
|
case HAL_EVT_OPEN:
|
|
return "HAL_EVT_OPEN";
|
|
case HAL_EVT_CORE_INIT:
|
|
return "HAL_EVT_CORE_INIT";
|
|
case HAL_EVT_WRITE:
|
|
return "HAL_EVT_WRITE";
|
|
case HAL_EVT_READ:
|
|
return "HAL_EVT_READ";
|
|
case HAL_EVT_CONTROL_GRANTED:
|
|
return "HAL_EVT_CONTROL_GRANTED";
|
|
/* START - VTS */
|
|
case HAL_EVT_POWER_CYCLE:
|
|
return "HAL_EVT_POWER_CYCLE";
|
|
/* END - VTS */
|
|
case HAL_EVT_TERMINATE:
|
|
return "NFC_HAL_TERMINATE";
|
|
case HAL_EVT_COMPLETE:
|
|
return "NFC_HAL_COMPLETE";
|
|
case HAL_EVT_COMPLETE_FAILED:
|
|
return "NFC_HAL_COMPLETE_FAILED";
|
|
}
|
|
return "Unknown event.";
|
|
}
|
|
|
|
const char* state_to_string(eHAL_STATE state) {
|
|
switch (state) {
|
|
case HAL_STATE_INIT:
|
|
return "INIT";
|
|
case HAL_STATE_DEINIT:
|
|
return "DEINIT";
|
|
case HAL_STATE_OPEN:
|
|
return "OPEN";
|
|
case HAL_STATE_VS:
|
|
return "VENDOR_SPECIFIC";
|
|
case HAL_STATE_POSTINIT:
|
|
return "POST_INIT";
|
|
case HAL_STATE_SERVICE:
|
|
return "SERVICE";
|
|
case HAL_STATE_GRANTED:
|
|
return "GRANT";
|
|
/* START - VTS */
|
|
case HAL_STATE_POWERCYCLE:
|
|
return "POWER_CYCLE";
|
|
/* END - VTS */
|
|
case HAL_STATE_CLOSE:
|
|
return "CLOSE";
|
|
}
|
|
return "Unknown state.";
|
|
}
|