NFC: NCI: zero struct spi_transfer variables before usage
[deliverable/linux.git] / net / nfc / nci / spi.c
... / ...
CommitLineData
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>
23#include <linux/crc-ccitt.h>
24#include <linux/nfc.h>
25#include <net/nfc/nci_core.h>
26
27#define NCI_SPI_ACK_SHIFT 6
28#define NCI_SPI_MSB_PAYLOAD_MASK 0x3F
29
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
42static int __nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb)
43{
44 struct spi_message m;
45 struct spi_transfer t;
46
47 memset(&t, 0, sizeof(struct spi_transfer));
48 t.tx_buf = skb->data;
49 t.len = skb->len;
50 t.cs_change = 0;
51 t.delay_usecs = nspi->xfer_udelay;
52
53 spi_message_init(&m);
54 spi_message_add_tail(&t, &m);
55
56 return spi_sync(nspi->spi, &m);
57}
58
59int nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb)
60{
61 unsigned int payload_len = skb->len;
62 unsigned char *hdr;
63 int ret;
64 long completion_rc;
65
66 nspi->ops->deassert_int(nspi);
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;
71 hdr[1] = nspi->acknowledge_mode;
72 hdr[2] = payload_len >> 8;
73 hdr[3] = payload_len & 0xFF;
74
75 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
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
83 ret = __nci_spi_send(nspi, skb);
84
85 kfree_skb(skb);
86 nspi->ops->assert_int(nspi);
87
88 if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED)
89 goto done;
90
91 init_completion(&nspi->req_completion);
92 completion_rc = wait_for_completion_interruptible_timeout(
93 &nspi->req_completion,
94 NCI_SPI_SEND_TIMEOUT);
95
96 if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK)
97 ret = -EIO;
98
99done:
100 return ret;
101}
102EXPORT_SYMBOL_GPL(nci_spi_send);
103
104/* ---- Interface to NCI SPI drivers ---- */
105
106/**
107 * nci_spi_allocate_spi - allocate a new nci spi
108 *
109 * @spi: SPI device
110 * @ops: device operations
111 * @acknowledge_mode: Acknowledge mode used by the NFC device
112 * @delay: delay between transactions in us
113 * @ndev: nci dev to send incoming nci frames to
114 */
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)
119{
120 struct nci_spi *nspi;
121
122 if (!ops->assert_int || !ops->deassert_int)
123 return NULL;
124
125 nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL);
126 if (!nspi)
127 return NULL;
128
129 nspi->ops = ops;
130 nspi->acknowledge_mode = acknowledge_mode;
131 nspi->xfer_udelay = delay;
132
133 nspi->spi = spi;
134 nspi->ndev = ndev;
135
136 return nspi;
137}
138EXPORT_SYMBOL_GPL(nci_spi_allocate_spi);
139
140static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
141{
142 struct sk_buff *skb;
143 unsigned char *hdr;
144 u16 crc;
145 int ret;
146
147 skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
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
160 ret = __nci_spi_send(nspi, skb);
161
162 kfree_skb(skb);
163
164 return ret;
165}
166
167static struct sk_buff *__nci_spi_recv_frame(struct nci_spi *nspi)
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);
177
178 memset(&tx, 0, sizeof(struct spi_transfer));
179 req[0] = NCI_SPI_DIRECT_READ;
180 req[1] = nspi->acknowledge_mode;
181 tx.tx_buf = req;
182 tx.len = 2;
183 tx.cs_change = 0;
184 spi_message_add_tail(&tx, &m);
185
186 memset(&rx, 0, sizeof(struct spi_transfer));
187 rx.rx_buf = resp_hdr;
188 rx.len = 2;
189 rx.cs_change = 1;
190 spi_message_add_tail(&rx, &m);
191
192 ret = spi_sync(nspi->spi, &m);
193
194 if (ret)
195 return NULL;
196
197 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
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
203 skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL);
204 if (!skb)
205 return NULL;
206
207 spi_message_init(&m);
208
209 memset(&rx, 0, sizeof(struct spi_transfer));
210 rx.rx_buf = skb_put(skb, rx_len);
211 rx.len = rx_len;
212 rx.cs_change = 0;
213 rx.delay_usecs = nspi->xfer_udelay;
214 spi_message_add_tail(&rx, &m);
215
216 ret = spi_sync(nspi->spi, &m);
217
218 if (ret)
219 goto receive_error;
220
221 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
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 *
263 * @nspi: The nci spi
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 */
271int nci_spi_recv_frame(struct nci_spi *nspi)
272{
273 struct sk_buff *skb;
274 int ret = 0;
275
276 nspi->ops->deassert_int(nspi);
277
278 /* Retrieve frame from SPI */
279 skb = __nci_spi_recv_frame(nspi);
280 if (!skb) {
281 ret = -EIO;
282 goto done;
283 }
284
285 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
286 if (!nci_spi_check_crc(skb)) {
287 send_acknowledge(nspi, ACKNOWLEDGE_NACK);
288 goto done;
289 }
290
291 /* In case of acknowledged mode: if ACK or NACK received,
292 * unblock completion of latest frame sent.
293 */
294 nspi->req_result = nci_spi_get_ack(skb);
295 if (nspi->req_result)
296 complete(&nspi->req_completion);
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
307 if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
308 send_acknowledge(nspi, ACKNOWLEDGE_ACK);
309
310 /* Forward skb to NCI core layer */
311 ret = nci_recv_frame(nspi->ndev, skb);
312
313done:
314 nspi->ops->assert_int(nspi);
315
316 return ret;
317}
318EXPORT_SYMBOL_GPL(nci_spi_recv_frame);
This page took 0.024624 seconds and 5 git commands to generate.