• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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  * Platform implementation for a nq-nci extension driver.
17  *
18  * The driver presents the following interface on a miscdev:
19  * - ioctl():
20  *   - for setting and getting power.
21  *     This handles SVDD_PWR_REQ and NFC_VEN muxing.
22  *     (ESE_RST is not connected in this case.)
23  * - read():
24  *   - For reading arbitrary amounts of data.
25  *     CS is asserted and deasserted on each call, but the clock
26  *     also appears to do the same which keeps the ese data available
27  *     as far as I can tell.
28  * - write():
29  *   - For writing arbitrary amounts of data.
30  *     CS is asserted as with read() calls, so the less fragmented
31  *     the better.
32  *
33  * All GPIO toggling and chip select requirements are handled behind this
34  * interface.
35  *
36  */
37 
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <limits.h>
41 #include <stdint.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/ioctl.h>
45 #include <unistd.h>
46 
47 #include "../include/ese/hw/nxp/pn80t/common.h"
48 
49 #ifndef UNUSED
50 #define UNUSED(x) x __attribute__((unused))
51 #endif
52 
53 /* From kernel/drivers/nfc/nq-nci.h */
54 #define ESE_SET_PWR _IOW(0xE9, 0x02, unsigned int)
55 #define ESE_GET_PWR _IOR(0xE9, 0x03, unsigned int)
56 #define ESE_CLEAR_GPIO _IOW(0xE9, 0x11, unsigned int)
57 
58 static const char kDevicePath[] = "/dev/pn81a";
59 
60 struct PlatformHandle {
61   int fd;
62 };
63 
platform_toggle_bootloader(void * blob,int val)64 int platform_toggle_bootloader(void *blob, int val) {
65   const struct PlatformHandle *handle = blob;
66   if (!handle) {
67     return -1;
68   }
69   return ioctl(handle->fd, ESE_CLEAR_GPIO, val);
70 }
71 
platform_toggle_reset(void * blob,int val)72 int platform_toggle_reset(void *blob, int val) {
73   const struct PlatformHandle *handle = blob;
74   if (!handle) {
75     return -1;
76   }
77   /* 0=power and 1=no power in the kernel. */
78   return ioctl(handle->fd, ESE_SET_PWR, !val);
79 }
80 
platform_init(void * hwopts)81 void *platform_init(void *hwopts) {
82   /* TODO(wad): It may make sense to pass in the dev path here. */
83   if (hwopts != NULL) {
84     return NULL;
85   }
86 
87   struct PlatformHandle *handle = calloc(1, sizeof(*handle));
88   if (!handle) {
89     ALOGE("%s: unable to allocate memory for handle", __func__);
90     return NULL;
91   }
92   handle->fd = open(kDevicePath, O_RDWR);
93   if (handle->fd < 0) {
94     ALOGE("%s: opening '%s' failed: %s", __func__, kDevicePath,
95           strerror(errno));
96     free(handle);
97     return NULL;
98   }
99   return handle;
100 }
101 
platform_release(void * blob)102 int platform_release(void *blob) {
103   struct PlatformHandle *handle = blob;
104   if (!handle) {
105     return -1;
106   }
107   /* Power off and cooldown should've happened via common code. */
108   close(handle->fd);
109   free(handle);
110   return 0;
111 }
112 
platform_wait(void * UNUSED (blob),long usec)113 int platform_wait(void *UNUSED(blob), long usec) {
114   return usleep((useconds_t)usec);
115 }
116 
nq_transmit(struct EseInterface * ese,const uint8_t * buf,uint32_t len,int UNUSED (complete))117 uint32_t nq_transmit(struct EseInterface *ese, const uint8_t *buf, uint32_t len,
118                      int UNUSED(complete)) {
119   struct NxpState *ns = NXP_PN80T_STATE(ese);
120   const struct Pn80tPlatform *platform = ese->ops->opts;
121   uint32_t bytes = 0;
122   ALOGV("nq_nci:%s: called [%d]", __func__, len);
123   if (len > INT_MAX) {
124     ese_set_error(ese, kNxpPn80tErrorTransmitSize);
125     ALOGE("Unexpectedly large transfer attempted: %u", len);
126     return 0;
127   }
128   if (len == 0)
129     return len;
130   const struct PlatformHandle *handle = ns->handle;
131   while (bytes < len) {
132     ssize_t ret = write(handle->fd, (void *)(buf + bytes), len - bytes);
133     if (ret < 0) {
134       if (errno == EAGAIN || errno == EINTR) {
135         continue;
136       }
137       ese_set_error(ese, kNxpPn80tErrorTransmit);
138       ALOGE("%s: failed to write to hw (ret=%zd, errno=%d)", __func__, ret,
139             errno);
140       return 0;
141     }
142     bytes += ret;
143   }
144   return len;
145 }
146 
nq_receive(struct EseInterface * ese,uint8_t * buf,uint32_t len,int UNUSED (complete))147 uint32_t nq_receive(struct EseInterface *ese, uint8_t *buf, uint32_t len,
148                     int UNUSED(complete)) {
149   const struct Pn80tPlatform *platform = ese->ops->opts;
150   struct NxpState *ns = NXP_PN80T_STATE(ese);
151   ALOGV("nq_nci:%s: called [%d]", __func__, len);
152   if (!ns) {
153     ALOGE("NxpState was NULL");
154     return 0;
155   }
156   if (len > INT_MAX) {
157     ese_set_error(ese, kNxpPn80tErrorReceiveSize);
158     ALOGE("Unexpectedly large receive attempted: %u", len);
159     return 0;
160   }
161   const struct PlatformHandle *handle = ns->handle;
162   if (len == 0) {
163     return 0;
164   }
165   uint32_t bytes = 0;
166   while (bytes < len) {
167     ssize_t ret = read(handle->fd, (void *)(buf + bytes), len - bytes);
168     if (ret < 0) {
169       if (errno == EAGAIN || errno == EINTR) {
170         continue;
171       }
172       ALOGE("%s: failed to read from hw (ret=%zd, errno=%d)", __func__, ret,
173             errno);
174       ese_set_error(ese, kNxpPn80tErrorReceive);
175       return 0;
176     }
177     bytes += ret;
178   }
179   ALOGV("%s: read bytes: %u", __func__, bytes);
180   return len;
181 }
182 
183 static const struct Pn80tPlatform kPn80tNqNciPlatform = {
184     .initialize = &platform_init,
185     .release = &platform_release,
186     .toggle_reset = &platform_toggle_reset,
187     .toggle_ven = NULL,
188     .toggle_power_req = NULL,
189     .toggle_bootloader = &platform_toggle_bootloader,
190     .wait = &platform_wait,
191 };
192 
193 static const struct EseOperations ops = {
194     .name = "NXP PN80T/PN81A (NQ-NCI:PN553)",
195     .open = &nxp_pn80t_open,
196     .hw_receive = &nq_receive,
197     .hw_transmit = &nq_transmit,
198     .hw_reset = &nxp_pn80t_reset,
199     .transceive = &nxp_pn80t_transceive,
200     .poll = &nxp_pn80t_poll,
201     .close = &nxp_pn80t_close,
202     .opts = &kPn80tNqNciPlatform,
203     .errors = kNxpPn80tErrorMessages,
204     .errors_count = kNxpPn80tErrorMax,
205 };
206 __attribute__((visibility("default")))
207 ESE_DEFINE_HW_OPS(ESE_HW_NXP_PN80T_NQ_NCI, ops);
208