NFC: NCI: zero struct spi_transfer variables before usage
[deliverable/linux.git] / net / nfc / nci / spi.c
CommitLineData
8a00a61b
FD
1/*
2 * Copyright (C) 2013 Intel Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 */
18
19#define pr_fmt(fmt) "nci_spi: %s: " fmt, __func__
20
21#include <linux/export.h>
22#include <linux/spi/spi.h>
ee9596d4 23#include <linux/crc-ccitt.h>
8a00a61b
FD
24#include <linux/nfc.h>
25#include <net/nfc/nci_core.h>
26
391d8a2d
FD
27#define NCI_SPI_ACK_SHIFT 6
28#define NCI_SPI_MSB_PAYLOAD_MASK 0x3F
8a00a61b 29
ee9596d4
FD
30#define NCI_SPI_SEND_TIMEOUT (NCI_CMD_TIMEOUT > NCI_DATA_TIMEOUT ? \
31 NCI_CMD_TIMEOUT : NCI_DATA_TIMEOUT)
32
33#define NCI_SPI_DIRECT_WRITE 0x01
34#define NCI_SPI_DIRECT_READ 0x02
35
36#define ACKNOWLEDGE_NONE 0
37#define ACKNOWLEDGE_ACK 1
38#define ACKNOWLEDGE_NACK 2
39
40#define CRC_INIT 0xFFFF
41
fa544fff 42static int __nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb)
ee9596d4
FD
43{
44 struct spi_message m;
45 struct spi_transfer t;
46
a4ada6ca 47 memset(&t, 0, sizeof(struct spi_transfer));
ee9596d4
FD
48 t.tx_buf = skb->data;
49 t.len = skb->len;
50 t.cs_change = 0;
fa544fff 51 t.delay_usecs = nspi->xfer_udelay;
ee9596d4
FD
52
53 spi_message_init(&m);
54 spi_message_add_tail(&t, &m);
55
fa544fff 56 return spi_sync(nspi->spi, &m);
ee9596d4
FD
57}
58
fa544fff 59int nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb)
8a00a61b 60{
ee9596d4
FD
61 unsigned int payload_len = skb->len;
62 unsigned char *hdr;
63 int ret;
64 long completion_rc;
65
fa544fff 66 nspi->ops->deassert_int(nspi);
ee9596d4
FD
67
68 /* add the NCI SPI header to the start of the buffer */
69 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
70 hdr[0] = NCI_SPI_DIRECT_WRITE;
fa544fff 71 hdr[1] = nspi->acknowledge_mode;
ee9596d4
FD
72 hdr[2] = payload_len >> 8;
73 hdr[3] = payload_len & 0xFF;
74
fa544fff 75 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
ee9596d4
FD
76 u16 crc;
77
78 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
79 *skb_put(skb, 1) = crc >> 8;
80 *skb_put(skb, 1) = crc & 0xFF;
81 }
82
fa544fff 83 ret = __nci_spi_send(nspi, skb);
ee9596d4
FD
84
85 kfree_skb(skb);
fa544fff 86 nspi->ops->assert_int(nspi);
ee9596d4 87
fa544fff 88 if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED)
ee9596d4
FD
89 goto done;
90
fa544fff 91 init_completion(&nspi->req_completion);
d5937511 92 completion_rc = wait_for_completion_interruptible_timeout(
fa544fff 93 &nspi->req_completion,
d5937511 94 NCI_SPI_SEND_TIMEOUT);
ee9596d4 95
fa544fff 96 if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK)
ee9596d4
FD
97 ret = -EIO;
98
99done:
100 return ret;
8a00a61b 101}
fa544fff 102EXPORT_SYMBOL_GPL(nci_spi_send);
8a00a61b
FD
103
104/* ---- Interface to NCI SPI drivers ---- */
105
106/**
fa544fff 107 * nci_spi_allocate_spi - allocate a new nci spi
8a00a61b
FD
108 *
109 * @spi: SPI device
110 * @ops: device operations
fa544fff 111 * @acknowledge_mode: Acknowledge mode used by the NFC device
8a00a61b 112 * @delay: delay between transactions in us
fa544fff 113 * @ndev: nci dev to send incoming nci frames to
8a00a61b 114 */
fa544fff
EL
115struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi,
116 struct nci_spi_ops *ops,
117 u8 acknowledge_mode, unsigned int delay,
118 struct nci_dev *ndev)
8a00a61b 119{
fa544fff 120 struct nci_spi *nspi;
8a00a61b 121
fa544fff 122 if (!ops->assert_int || !ops->deassert_int)
8a00a61b
FD
123 return NULL;
124
fa544fff
EL
125 nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL);
126 if (!nspi)
8a00a61b
FD
127 return NULL;
128
fa544fff
EL
129 nspi->ops = ops;
130 nspi->acknowledge_mode = acknowledge_mode;
131 nspi->xfer_udelay = delay;
8a00a61b 132
645d5087 133 nspi->spi = spi;
fa544fff 134 nspi->ndev = ndev;
8a00a61b 135
fa544fff 136 return nspi;
8a00a61b 137}
fa544fff 138EXPORT_SYMBOL_GPL(nci_spi_allocate_spi);
391d8a2d 139
fa544fff 140static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
391d8a2d
FD
141{
142 struct sk_buff *skb;
143 unsigned char *hdr;
144 u16 crc;
145 int ret;
146
fa544fff 147 skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
391d8a2d
FD
148
149 /* add the NCI SPI header to the start of the buffer */
150 hdr = skb_push(skb, NCI_SPI_HDR_LEN);
151 hdr[0] = NCI_SPI_DIRECT_WRITE;
152 hdr[1] = NCI_SPI_CRC_ENABLED;
153 hdr[2] = acknowledge << NCI_SPI_ACK_SHIFT;
154 hdr[3] = 0;
155
156 crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
157 *skb_put(skb, 1) = crc >> 8;
158 *skb_put(skb, 1) = crc & 0xFF;
159
fa544fff 160 ret = __nci_spi_send(nspi, skb);
391d8a2d
FD
161
162 kfree_skb(skb);
163
164 return ret;
165}
166
fa544fff 167static struct sk_buff *__nci_spi_recv_frame(struct nci_spi *nspi)
391d8a2d
FD
168{
169 struct sk_buff *skb;
170 struct spi_message m;
171 unsigned char req[2], resp_hdr[2];
172 struct spi_transfer tx, rx;
173 unsigned short rx_len = 0;
174 int ret;
175
176 spi_message_init(&m);
a4ada6ca
EL
177
178 memset(&tx, 0, sizeof(struct spi_transfer));
391d8a2d 179 req[0] = NCI_SPI_DIRECT_READ;
fa544fff 180 req[1] = nspi->acknowledge_mode;
391d8a2d
FD
181 tx.tx_buf = req;
182 tx.len = 2;
183 tx.cs_change = 0;
184 spi_message_add_tail(&tx, &m);
a4ada6ca
EL
185
186 memset(&rx, 0, sizeof(struct spi_transfer));
391d8a2d
FD
187 rx.rx_buf = resp_hdr;
188 rx.len = 2;
189 rx.cs_change = 1;
190 spi_message_add_tail(&rx, &m);
a4ada6ca 191
fa544fff 192 ret = spi_sync(nspi->spi, &m);
391d8a2d
FD
193
194 if (ret)
195 return NULL;
196
fa544fff 197 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
391d8a2d
FD
198 rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) +
199 resp_hdr[1] + NCI_SPI_CRC_LEN;
200 else
201 rx_len = (resp_hdr[0] << 8) | resp_hdr[1];
202
fa544fff 203 skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL);
391d8a2d
FD
204 if (!skb)
205 return NULL;
206
207 spi_message_init(&m);
a4ada6ca
EL
208
209 memset(&rx, 0, sizeof(struct spi_transfer));
391d8a2d
FD
210 rx.rx_buf = skb_put(skb, rx_len);
211 rx.len = rx_len;
212 rx.cs_change = 0;
fa544fff 213 rx.delay_usecs = nspi->xfer_udelay;
391d8a2d 214 spi_message_add_tail(&rx, &m);
a4ada6ca 215
fa544fff 216 ret = spi_sync(nspi->spi, &m);
391d8a2d
FD
217
218 if (ret)
219 goto receive_error;
220
fa544fff 221 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
391d8a2d
FD
222 *skb_push(skb, 1) = resp_hdr[1];
223 *skb_push(skb, 1) = resp_hdr[0];
224 }
225
226 return skb;
227
228receive_error:
229 kfree_skb(skb);
230
231 return NULL;
232}
233
234static int nci_spi_check_crc(struct sk_buff *skb)
235{
236 u16 crc_data = (skb->data[skb->len - 2] << 8) |
237 skb->data[skb->len - 1];
238 int ret;
239
240 ret = (crc_ccitt(CRC_INIT, skb->data, skb->len - NCI_SPI_CRC_LEN)
241 == crc_data);
242
243 skb_trim(skb, skb->len - NCI_SPI_CRC_LEN);
244
245 return ret;
246}
247
248static u8 nci_spi_get_ack(struct sk_buff *skb)
249{
250 u8 ret;
251
252 ret = skb->data[0] >> NCI_SPI_ACK_SHIFT;
253
254 /* Remove NFCC part of the header: ACK, NACK and MSB payload len */
255 skb_pull(skb, 2);
256
257 return ret;
258}
259
260/**
261 * nci_spi_recv_frame - receive frame from NCI SPI drivers
262 *
fa544fff 263 * @nspi: The nci spi
391d8a2d
FD
264 * Context: can sleep
265 *
266 * This call may only be used from a context that may sleep. The sleep
267 * is non-interruptible, and has no timeout.
268 *
269 * It returns zero on success, else a negative error code.
270 */
fa544fff 271int nci_spi_recv_frame(struct nci_spi *nspi)
391d8a2d
FD
272{
273 struct sk_buff *skb;
274 int ret = 0;
275
fa544fff 276 nspi->ops->deassert_int(nspi);
391d8a2d
FD
277
278 /* Retrieve frame from SPI */
fa544fff 279 skb = __nci_spi_recv_frame(nspi);
391d8a2d
FD
280 if (!skb) {
281 ret = -EIO;
282 goto done;
283 }
284
fa544fff 285 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
391d8a2d 286 if (!nci_spi_check_crc(skb)) {
fa544fff 287 send_acknowledge(nspi, ACKNOWLEDGE_NACK);
391d8a2d
FD
288 goto done;
289 }
290
291 /* In case of acknowledged mode: if ACK or NACK received,
292 * unblock completion of latest frame sent.
293 */
fa544fff
EL
294 nspi->req_result = nci_spi_get_ack(skb);
295 if (nspi->req_result)
296 complete(&nspi->req_completion);
391d8a2d
FD
297 }
298
299 /* If there is no payload (ACK/NACK only frame),
300 * free the socket buffer
301 */
302 if (skb->len == 0) {
303 kfree_skb(skb);
304 goto done;
305 }
306
fa544fff
EL
307 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
308 send_acknowledge(nspi, ACKNOWLEDGE_ACK);
391d8a2d
FD
309
310 /* Forward skb to NCI core layer */
fa544fff 311 ret = nci_recv_frame(nspi->ndev, skb);
391d8a2d
FD
312
313done:
fa544fff 314 nspi->ops->assert_int(nspi);
391d8a2d
FD
315
316 return ret;
317}
318EXPORT_SYMBOL_GPL(nci_spi_recv_frame);
This page took 0.061797 seconds and 5 git commands to generate.