These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / nfc / st21nfca / vendor_cmds.c
1 /*
2  * Proprietary commands extension for STMicroelectronics NFC Chip
3  *
4  * Copyright (C) 2014-2015  STMicroelectronics SAS. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <net/genetlink.h>
20 #include <linux/module.h>
21 #include <linux/nfc.h>
22 #include <net/nfc/hci.h>
23 #include <net/nfc/llc.h>
24
25 #include "st21nfca.h"
26
27 #define ST21NFCA_HCI_DM_GETDATA                 0x10
28 #define ST21NFCA_HCI_DM_PUTDATA                 0x11
29 #define ST21NFCA_HCI_DM_LOAD                    0x12
30 #define ST21NFCA_HCI_DM_GETINFO                 0x13
31 #define ST21NFCA_HCI_DM_UPDATE_AID              0x20
32 #define ST21NFCA_HCI_DM_RESET                   0x3e
33
34 #define ST21NFCA_HCI_DM_FIELD_GENERATOR         0x32
35
36 #define ST21NFCA_FACTORY_MODE_ON                1
37 #define ST21NFCA_FACTORY_MODE_OFF               0
38
39 #define ST21NFCA_EVT_POST_DATA                  0x02
40
41 struct get_param_data {
42         u8 gate;
43         u8 data;
44 } __packed;
45
46 static int st21nfca_factory_mode(struct nfc_dev *dev, void *data,
47                                size_t data_len)
48 {
49         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
50
51         if (data_len != 1)
52                 return -EINVAL;
53
54         pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
55
56         switch (((u8 *)data)[0]) {
57         case ST21NFCA_FACTORY_MODE_ON:
58                 test_and_set_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
59         break;
60         case ST21NFCA_FACTORY_MODE_OFF:
61                 clear_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
62         break;
63         default:
64                 return -EINVAL;
65         }
66
67         return 0;
68 }
69
70 static int st21nfca_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
71                                       size_t data_len)
72 {
73         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
74
75         return nfc_hci_disconnect_all_gates(hdev);
76 }
77
78 static int st21nfca_hci_dm_put_data(struct nfc_dev *dev, void *data,
79                                   size_t data_len)
80 {
81         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
82
83         return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
84                                 ST21NFCA_HCI_DM_PUTDATA, data,
85                                 data_len, NULL);
86 }
87
88 static int st21nfca_hci_dm_update_aid(struct nfc_dev *dev, void *data,
89                                     size_t data_len)
90 {
91         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
92
93         return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
94                         ST21NFCA_HCI_DM_UPDATE_AID, data, data_len, NULL);
95 }
96
97 static int st21nfca_hci_dm_get_info(struct nfc_dev *dev, void *data,
98                                     size_t data_len)
99 {
100         int r;
101         struct sk_buff *msg, *skb;
102         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
103
104         r = nfc_hci_send_cmd(hdev,
105                              ST21NFCA_DEVICE_MGNT_GATE,
106                              ST21NFCA_HCI_DM_GETINFO,
107                              data, data_len, &skb);
108         if (r)
109                 goto exit;
110
111         msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
112                                              HCI_DM_GET_INFO, skb->len);
113         if (!msg) {
114                 r = -ENOMEM;
115                 goto free_skb;
116         }
117
118         if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
119                 kfree_skb(msg);
120                 r = -ENOBUFS;
121                 goto free_skb;
122         }
123
124         r = nfc_vendor_cmd_reply(msg);
125
126 free_skb:
127         kfree_skb(skb);
128 exit:
129         return r;
130 }
131
132 static int st21nfca_hci_dm_get_data(struct nfc_dev *dev, void *data,
133                                     size_t data_len)
134 {
135         int r;
136         struct sk_buff *msg, *skb;
137         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
138
139         r = nfc_hci_send_cmd(hdev,
140                              ST21NFCA_DEVICE_MGNT_GATE,
141                              ST21NFCA_HCI_DM_GETDATA,
142                              data, data_len, &skb);
143         if (r)
144                 goto exit;
145
146         msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
147                                              HCI_DM_GET_DATA, skb->len);
148         if (!msg) {
149                 r = -ENOMEM;
150                 goto free_skb;
151         }
152
153         if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
154                 kfree_skb(msg);
155                 r = -ENOBUFS;
156                 goto free_skb;
157         }
158
159         r = nfc_vendor_cmd_reply(msg);
160
161 free_skb:
162         kfree_skb(skb);
163 exit:
164         return r;
165 }
166
167 static int st21nfca_hci_dm_load(struct nfc_dev *dev, void *data,
168                                 size_t data_len)
169 {
170         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
171
172         return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
173                                 ST21NFCA_HCI_DM_LOAD, data, data_len, NULL);
174 }
175
176 static int st21nfca_hci_dm_reset(struct nfc_dev *dev, void *data,
177                                  size_t data_len)
178 {
179         int r;
180         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
181
182         r = nfc_hci_send_cmd_async(hdev, ST21NFCA_DEVICE_MGNT_GATE,
183                         ST21NFCA_HCI_DM_RESET, data, data_len, NULL, NULL);
184         if (r < 0)
185                 return r;
186
187         r = nfc_llc_stop(hdev->llc);
188         if (r < 0)
189                 return r;
190
191         return nfc_llc_start(hdev->llc);
192 }
193
194 static int st21nfca_hci_get_param(struct nfc_dev *dev, void *data,
195                                   size_t data_len)
196 {
197         int r;
198         struct sk_buff *msg, *skb;
199         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
200         struct get_param_data *param = (struct get_param_data *)data;
201
202         if (data_len < sizeof(struct get_param_data))
203                 return -EPROTO;
204
205         r = nfc_hci_get_param(hdev, param->gate, param->data, &skb);
206         if (r)
207                 goto exit;
208
209         msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
210                                              HCI_GET_PARAM, skb->len);
211         if (!msg) {
212                 r = -ENOMEM;
213                 goto free_skb;
214         }
215
216         if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
217                 kfree_skb(msg);
218                 r = -ENOBUFS;
219                 goto free_skb;
220         }
221
222         r = nfc_vendor_cmd_reply(msg);
223
224 free_skb:
225         kfree_skb(skb);
226 exit:
227         return r;
228 }
229
230 static int st21nfca_hci_dm_field_generator(struct nfc_dev *dev, void *data,
231                                            size_t data_len)
232 {
233         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
234
235         return nfc_hci_send_cmd(hdev,
236                                 ST21NFCA_DEVICE_MGNT_GATE,
237                                 ST21NFCA_HCI_DM_FIELD_GENERATOR,
238                                 data, data_len, NULL);
239 }
240
241 int st21nfca_hci_loopback_event_received(struct nfc_hci_dev *hdev, u8 event,
242                                          struct sk_buff *skb)
243 {
244         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
245
246         switch (event) {
247         case ST21NFCA_EVT_POST_DATA:
248                 info->vendor_info.rx_skb = skb;
249         break;
250         default:
251                 nfc_err(&hdev->ndev->dev, "Unexpected event on loopback gate\n");
252         }
253         complete(&info->vendor_info.req_completion);
254         return 0;
255 }
256 EXPORT_SYMBOL(st21nfca_hci_loopback_event_received);
257
258 static int st21nfca_hci_loopback(struct nfc_dev *dev, void *data,
259                                  size_t data_len)
260 {
261         int r;
262         struct sk_buff *msg;
263         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
264         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
265
266         if (data_len <= 0)
267                 return -EPROTO;
268
269         reinit_completion(&info->vendor_info.req_completion);
270         info->vendor_info.rx_skb = NULL;
271
272         r = nfc_hci_send_event(hdev, NFC_HCI_LOOPBACK_GATE,
273                                ST21NFCA_EVT_POST_DATA, data, data_len);
274         if (r < 0) {
275                 r = -EPROTO;
276                 goto exit;
277         }
278
279         wait_for_completion_interruptible(&info->vendor_info.req_completion);
280         if (!info->vendor_info.rx_skb ||
281             info->vendor_info.rx_skb->len != data_len) {
282                 r = -EPROTO;
283                 goto exit;
284         }
285
286         msg = nfc_vendor_cmd_alloc_reply_skb(hdev->ndev,
287                                         ST21NFCA_VENDOR_OUI,
288                                         HCI_LOOPBACK,
289                                         info->vendor_info.rx_skb->len);
290         if (!msg) {
291                 r = -ENOMEM;
292                 goto free_skb;
293         }
294
295         if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len,
296                     info->vendor_info.rx_skb->data)) {
297                 kfree_skb(msg);
298                 r = -ENOBUFS;
299                 goto free_skb;
300         }
301
302         r = nfc_vendor_cmd_reply(msg);
303 free_skb:
304         kfree_skb(info->vendor_info.rx_skb);
305 exit:
306         return r;
307 }
308
309 static struct nfc_vendor_cmd st21nfca_vendor_cmds[] = {
310         {
311                 .vendor_id = ST21NFCA_VENDOR_OUI,
312                 .subcmd = FACTORY_MODE,
313                 .doit = st21nfca_factory_mode,
314         },
315         {
316                 .vendor_id = ST21NFCA_VENDOR_OUI,
317                 .subcmd = HCI_CLEAR_ALL_PIPES,
318                 .doit = st21nfca_hci_clear_all_pipes,
319         },
320         {
321                 .vendor_id = ST21NFCA_VENDOR_OUI,
322                 .subcmd = HCI_DM_PUT_DATA,
323                 .doit = st21nfca_hci_dm_put_data,
324         },
325         {
326                 .vendor_id = ST21NFCA_VENDOR_OUI,
327                 .subcmd = HCI_DM_UPDATE_AID,
328                 .doit = st21nfca_hci_dm_update_aid,
329         },
330         {
331                 .vendor_id = ST21NFCA_VENDOR_OUI,
332                 .subcmd = HCI_DM_GET_INFO,
333                 .doit = st21nfca_hci_dm_get_info,
334         },
335         {
336                 .vendor_id = ST21NFCA_VENDOR_OUI,
337                 .subcmd = HCI_DM_GET_DATA,
338                 .doit = st21nfca_hci_dm_get_data,
339         },
340         {
341                 .vendor_id = ST21NFCA_VENDOR_OUI,
342                 .subcmd = HCI_DM_LOAD,
343                 .doit = st21nfca_hci_dm_load,
344         },
345         {
346                 .vendor_id = ST21NFCA_VENDOR_OUI,
347                 .subcmd = HCI_DM_RESET,
348                 .doit = st21nfca_hci_dm_reset,
349         },
350         {
351                 .vendor_id = ST21NFCA_VENDOR_OUI,
352                 .subcmd = HCI_GET_PARAM,
353                 .doit = st21nfca_hci_get_param,
354         },
355         {
356                 .vendor_id = ST21NFCA_VENDOR_OUI,
357                 .subcmd = HCI_DM_FIELD_GENERATOR,
358                 .doit = st21nfca_hci_dm_field_generator,
359         },
360         {
361                 .vendor_id = ST21NFCA_VENDOR_OUI,
362                 .subcmd = HCI_LOOPBACK,
363                 .doit = st21nfca_hci_loopback,
364         },
365 };
366
367 int st21nfca_vendor_cmds_init(struct nfc_hci_dev *hdev)
368 {
369         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
370
371         init_completion(&info->vendor_info.req_completion);
372         return nfc_set_vendor_cmds(hdev->ndev, st21nfca_vendor_cmds,
373                                    sizeof(st21nfca_vendor_cmds));
374 }
375 EXPORT_SYMBOL(st21nfca_vendor_cmds_init);