1 /*
2  *    Copyright (C) 2013 SAMSUNG S.LSI
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  */
18 
19 #include <hardware/nfc.h>
20 #include <string.h>
21 
22 #include "device.h"
23 #include "hal.h"
24 #include "hal_msg.h"
25 #include "osi.h"
26 #include "util.h"
27 
hal_nci_send(tNFC_NCI_PKT * pkt)28 int hal_nci_send(tNFC_NCI_PKT* pkt) {
29   size_t len = (size_t)(pkt->len + NCI_HDR_SIZE);
30   int ret;
31 
32   ret = __send_to_device((uint8_t*)pkt, len);
33   if (ret != (int)len
34       /* workaround for retry; F/W I2C issue */
35       && (nfc_hal_info.flag & HAL_FLAG_NTF_TRNS_ERROR)) {
36     OSI_loge("NCI message send failed");
37     OSI_logd("set flag to 0x%06X", nfc_hal_info.flag);
38   } else {
39     util_nci_analyzer(pkt);
40   }
41 
42   return ret;
43 }
44 
hal_nci_send_reset(void)45 void hal_nci_send_reset(void) {
46   tNFC_NCI_PKT nci_pkt;
47 
48   memset(&nci_pkt, 0, sizeof(tNFC_NCI_PKT));
49   nci_pkt.oct0 = NCI_MT_CMD | NCI_PBF_LAST | NCI_GID_CORE;
50   nci_pkt.oid = NCI_CORE_RESET;
51   nci_pkt.len = 0x01;
52   nci_pkt.payload[0] = 0x01;  // Reset config
53 
54   hal_nci_send(&nci_pkt);
55 }
56 
57 /* START [181106] Patch for supporting NCI v2.0 */
58 // [3. CORE_INIT Changes]
hal_nci_send_init(int version)59 void hal_nci_send_init(int version) {
60   /* END [181106] Patch for supporting NCI v2.0 */
61   tNFC_NCI_PKT nci_pkt;
62 
63   /* START [181106] Patch for supporting NCI v2.0 */
64   //[3. CORE_INIT Changes]
65   memset(&nci_pkt, 0, sizeof(tNFC_NCI_PKT));
66   nci_pkt.oct0 = NCI_MT_CMD | NCI_PBF_LAST | NCI_GID_CORE;
67   nci_pkt.oid = NCI_CORE_INIT;
68   nci_pkt.len = 0x00;
69 
70   if (version == NCI_VER_2_0) {
71     nci_pkt.len = 0x02;
72     nci_pkt.payload[0] = 0x00;
73     nci_pkt.payload[1] = 0x00;
74   }
75   /* END [181106] Patch for supporting NCI v2.0 */
76 
77   hal_nci_send(&nci_pkt);
78 }
79 
80 /* Workaround: Initialization flash of LMRT */
hal_nci_send_clearLmrt(void)81 void hal_nci_send_clearLmrt(void) {
82   tNFC_NCI_PKT nci_pkt;
83 
84   memset(&nci_pkt, 0, sizeof(tNFC_NCI_PKT));
85   nci_pkt.oct0 = NCI_MT_CMD | NCI_PBF_LAST | NCI_GID_RF_MANAGE;
86   nci_pkt.oid = 0x01;  // RF_SET_LMRT
87   nci_pkt.len = 0x02;
88   nci_pkt.payload[0] = 0x00;
89   nci_pkt.payload[1] = 0x00;
90 
91   hal_nci_send(&nci_pkt);
92 }
93 /* END WA */
94 
get_clock_info(int rev,int field_name,int * buffer)95 void get_clock_info(int rev, int field_name, int* buffer) {
96   char rev_field[50] = {
97       '\0',
98   };
99   int isRevField = 0;
100 
101   sprintf(rev_field, "%s_REV%d", cfg_name_table[field_name], rev);
102   isRevField = get_config_count(rev_field);
103   if (rev >= 0 && isRevField) {
104     if (!get_config_int(rev_field, buffer)) *buffer = 0;
105   } else if (!get_config_int(cfg_name_table[field_name], buffer))
106     *buffer = 0;
107 }
108 
hal_nci_send_prop_fw_cfg(void)109 void hal_nci_send_prop_fw_cfg(void) {
110   tNFC_NCI_PKT nci_pkt;
111   int rev = get_hw_rev();
112 
113   memset(&nci_pkt, 0, sizeof(tNFC_NCI_PKT));
114   nci_pkt.oct0 = NCI_MT_CMD | NCI_PBF_LAST | NCI_GID_PROP;
115   nci_pkt.oid = NCI_PROP_FW_CFG;
116 
117   nci_pkt.len = 0x01;
118   get_clock_info(rev, CFG_FW_CLK_SPEED, (int*)&nci_pkt.payload[0]);
119   if (nci_pkt.payload[0] == 0xff) {
120     OSI_loge("Set a different value! Current Clock Speed Value : 0x%x",
121              nci_pkt.payload[0]);
122     return;
123   }
124   hal_nci_send(&nci_pkt);
125 }
126 
nci_read_payload(tNFC_HAL_MSG * msg)127 int nci_read_payload(tNFC_HAL_MSG* msg) {
128   tNFC_NCI_PKT* pkt = &msg->nci_packet;
129   int ret;
130 
131   ret = device_read(NCI_PAYLOAD(pkt), NCI_LEN(pkt));
132   if (ret != (int)NCI_LEN(pkt)) {
133     OSI_mem_free((tOSI_MEM_HANDLER)msg);
134     OSI_loge("Failed to read payload");
135     return ret;
136   }
137 
138   data_trace("Recv", NCI_HDR_SIZE + ret, msg->param);
139   return ret;
140 }
141 
fw_force_update(void * param)142 void fw_force_update(__attribute__((unused)) void* param) {
143   OSI_loge("need to F/W update!");
144 }
145 
nci_init_timeout(void * param)146 void nci_init_timeout(__attribute__((unused)) void* param) {
147   OSI_loge("need to retry!");
148 }
149 
nfc_hal_prehandler(tNFC_NCI_PKT * pkt)150 bool nfc_hal_prehandler(tNFC_NCI_PKT* pkt) {
151   if (NCI_MT(pkt) == NCI_MT_NTF) {
152     if (NCI_GID(pkt) == NCI_GID_PROP) {
153       /* Again procedure. only for N3 isN3group */
154       if (NCI_OID(pkt) == NCI_PROP_AGAIN) {
155         if (nfc_hal_info.nci_last_pkt) {
156           OSI_logd("NFC requests sending last message again!");
157           hal_update_sleep_timer();
158           device_write((uint8_t*)nfc_hal_info.nci_last_pkt,
159                        (size_t)(nfc_hal_info.nci_last_pkt->len + NCI_HDR_SIZE));
160           return false;
161         }
162       }
163     }
164   }
165 
166   if (NCI_MT(pkt) == NCI_MT_CMD) {
167     if (NCI_GID(pkt) == NCI_GID_PROP) {
168       if (NCI_OID(pkt) == NCI_PROP_WR_RESET) {
169         hal_nci_send_reset();
170         nfc_hal_info.flag |= HAL_FLAG_PROP_RESET;
171         return false;
172       }
173 
174       if (NCI_OID(pkt) == NCI_PROP_SET_SLEEP_TIME) {
175         tNFC_NCI_PKT dummy_rsp;
176         dummy_rsp.oct0 = NCI_MT_RSP | NCI_PBF_LAST | NCI_GID_PROP;
177         dummy_rsp.oid = NCI_OID(pkt);
178         dummy_rsp.len = 1;
179         dummy_rsp.payload[0] = NCI_STATUS_OK;
180 
181         if (NCI_LEN(pkt) == 0) {
182           setSleepTimeout(SET_SLEEP_TIME_CFG, 5000);
183         } else {
184           uint32_t timeout = NCI_PAYLOAD(pkt)[0] * 1000;  // sec
185           int option = SET_SLEEP_TIME_ONCE;
186 
187           if (NCI_LEN(pkt) > 1)
188             timeout += NCI_PAYLOAD(pkt)[1] * 1000 * 60;  // min
189 
190           if (NCI_LEN(pkt) > 2) option = NCI_PAYLOAD(pkt)[2];
191 
192           setSleepTimeout(option, timeout);
193         }
194 
195         hal_update_sleep_timer();
196         nfc_data_callback(&dummy_rsp);
197         return false;
198       }
199     }
200   }
201 
202   if (NCI_MT(pkt) == NCI_MT_RSP) {
203     if (NCI_GID(pkt) == NCI_GID_CORE) {
204       if (NCI_OID(pkt) == NCI_CORE_RESET) {
205         pkt->oct0 = NCI_MT_RSP | NCI_PBF_LAST | NCI_GID_PROP;
206         pkt->oid = NCI_PROP_WR_RESET;
207       }
208     }
209   }
210   return true;
211 }
212