gpio: rcar: Fix runtime PM imbalance on error
[linux/fpc-iii.git] / drivers / nfc / st21nfca / vendor_cmds.c
blob62332ca915545d5cfcca137a503a1a5adda2058d
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Proprietary commands extension for STMicroelectronics NFC Chip
5 * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
6 */
8 #include <net/genetlink.h>
9 #include <linux/module.h>
10 #include <linux/nfc.h>
11 #include <net/nfc/hci.h>
12 #include <net/nfc/llc.h>
14 #include "st21nfca.h"
16 #define ST21NFCA_HCI_DM_GETDATA 0x10
17 #define ST21NFCA_HCI_DM_PUTDATA 0x11
18 #define ST21NFCA_HCI_DM_LOAD 0x12
19 #define ST21NFCA_HCI_DM_GETINFO 0x13
20 #define ST21NFCA_HCI_DM_UPDATE_AID 0x20
21 #define ST21NFCA_HCI_DM_RESET 0x3e
23 #define ST21NFCA_HCI_DM_FIELD_GENERATOR 0x32
25 #define ST21NFCA_FACTORY_MODE_ON 1
26 #define ST21NFCA_FACTORY_MODE_OFF 0
28 #define ST21NFCA_EVT_POST_DATA 0x02
30 struct get_param_data {
31 u8 gate;
32 u8 data;
33 } __packed;
35 static int st21nfca_factory_mode(struct nfc_dev *dev, void *data,
36 size_t data_len)
38 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
40 if (data_len != 1)
41 return -EINVAL;
43 pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
45 switch (((u8 *)data)[0]) {
46 case ST21NFCA_FACTORY_MODE_ON:
47 test_and_set_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
48 break;
49 case ST21NFCA_FACTORY_MODE_OFF:
50 clear_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
51 break;
52 default:
53 return -EINVAL;
56 return 0;
59 static int st21nfca_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
60 size_t data_len)
62 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
64 return nfc_hci_disconnect_all_gates(hdev);
67 static int st21nfca_hci_dm_put_data(struct nfc_dev *dev, void *data,
68 size_t data_len)
70 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
72 return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
73 ST21NFCA_HCI_DM_PUTDATA, data,
74 data_len, NULL);
77 static int st21nfca_hci_dm_update_aid(struct nfc_dev *dev, void *data,
78 size_t data_len)
80 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
82 return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
83 ST21NFCA_HCI_DM_UPDATE_AID, data, data_len, NULL);
86 static int st21nfca_hci_dm_get_info(struct nfc_dev *dev, void *data,
87 size_t data_len)
89 int r;
90 struct sk_buff *msg, *skb;
91 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
93 r = nfc_hci_send_cmd(hdev,
94 ST21NFCA_DEVICE_MGNT_GATE,
95 ST21NFCA_HCI_DM_GETINFO,
96 data, data_len, &skb);
97 if (r)
98 goto exit;
100 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
101 HCI_DM_GET_INFO, skb->len);
102 if (!msg) {
103 r = -ENOMEM;
104 goto free_skb;
107 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
108 kfree_skb(msg);
109 r = -ENOBUFS;
110 goto free_skb;
113 r = nfc_vendor_cmd_reply(msg);
115 free_skb:
116 kfree_skb(skb);
117 exit:
118 return r;
121 static int st21nfca_hci_dm_get_data(struct nfc_dev *dev, void *data,
122 size_t data_len)
124 int r;
125 struct sk_buff *msg, *skb;
126 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
128 r = nfc_hci_send_cmd(hdev,
129 ST21NFCA_DEVICE_MGNT_GATE,
130 ST21NFCA_HCI_DM_GETDATA,
131 data, data_len, &skb);
132 if (r)
133 goto exit;
135 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
136 HCI_DM_GET_DATA, skb->len);
137 if (!msg) {
138 r = -ENOMEM;
139 goto free_skb;
142 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
143 kfree_skb(msg);
144 r = -ENOBUFS;
145 goto free_skb;
148 r = nfc_vendor_cmd_reply(msg);
150 free_skb:
151 kfree_skb(skb);
152 exit:
153 return r;
156 static int st21nfca_hci_dm_load(struct nfc_dev *dev, void *data,
157 size_t data_len)
159 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
161 return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
162 ST21NFCA_HCI_DM_LOAD, data, data_len, NULL);
165 static int st21nfca_hci_dm_reset(struct nfc_dev *dev, void *data,
166 size_t data_len)
168 int r;
169 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
171 r = nfc_hci_send_cmd_async(hdev, ST21NFCA_DEVICE_MGNT_GATE,
172 ST21NFCA_HCI_DM_RESET, data, data_len, NULL, NULL);
173 if (r < 0)
174 return r;
176 r = nfc_llc_stop(hdev->llc);
177 if (r < 0)
178 return r;
180 return nfc_llc_start(hdev->llc);
183 static int st21nfca_hci_get_param(struct nfc_dev *dev, void *data,
184 size_t data_len)
186 int r;
187 struct sk_buff *msg, *skb;
188 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
189 struct get_param_data *param = (struct get_param_data *)data;
191 if (data_len < sizeof(struct get_param_data))
192 return -EPROTO;
194 r = nfc_hci_get_param(hdev, param->gate, param->data, &skb);
195 if (r)
196 goto exit;
198 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
199 HCI_GET_PARAM, skb->len);
200 if (!msg) {
201 r = -ENOMEM;
202 goto free_skb;
205 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
206 kfree_skb(msg);
207 r = -ENOBUFS;
208 goto free_skb;
211 r = nfc_vendor_cmd_reply(msg);
213 free_skb:
214 kfree_skb(skb);
215 exit:
216 return r;
219 static int st21nfca_hci_dm_field_generator(struct nfc_dev *dev, void *data,
220 size_t data_len)
222 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
224 return nfc_hci_send_cmd(hdev,
225 ST21NFCA_DEVICE_MGNT_GATE,
226 ST21NFCA_HCI_DM_FIELD_GENERATOR,
227 data, data_len, NULL);
230 int st21nfca_hci_loopback_event_received(struct nfc_hci_dev *hdev, u8 event,
231 struct sk_buff *skb)
233 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
235 switch (event) {
236 case ST21NFCA_EVT_POST_DATA:
237 info->vendor_info.rx_skb = skb;
238 break;
239 default:
240 nfc_err(&hdev->ndev->dev, "Unexpected event on loopback gate\n");
242 complete(&info->vendor_info.req_completion);
243 return 0;
245 EXPORT_SYMBOL(st21nfca_hci_loopback_event_received);
247 static int st21nfca_hci_loopback(struct nfc_dev *dev, void *data,
248 size_t data_len)
250 int r;
251 struct sk_buff *msg;
252 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
253 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
255 if (data_len <= 0)
256 return -EPROTO;
258 reinit_completion(&info->vendor_info.req_completion);
259 info->vendor_info.rx_skb = NULL;
261 r = nfc_hci_send_event(hdev, NFC_HCI_LOOPBACK_GATE,
262 ST21NFCA_EVT_POST_DATA, data, data_len);
263 if (r < 0) {
264 r = -EPROTO;
265 goto exit;
268 wait_for_completion_interruptible(&info->vendor_info.req_completion);
269 if (!info->vendor_info.rx_skb ||
270 info->vendor_info.rx_skb->len != data_len) {
271 r = -EPROTO;
272 goto exit;
275 msg = nfc_vendor_cmd_alloc_reply_skb(hdev->ndev,
276 ST21NFCA_VENDOR_OUI,
277 HCI_LOOPBACK,
278 info->vendor_info.rx_skb->len);
279 if (!msg) {
280 r = -ENOMEM;
281 goto free_skb;
284 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len,
285 info->vendor_info.rx_skb->data)) {
286 kfree_skb(msg);
287 r = -ENOBUFS;
288 goto free_skb;
291 r = nfc_vendor_cmd_reply(msg);
292 free_skb:
293 kfree_skb(info->vendor_info.rx_skb);
294 exit:
295 return r;
298 static struct nfc_vendor_cmd st21nfca_vendor_cmds[] = {
300 .vendor_id = ST21NFCA_VENDOR_OUI,
301 .subcmd = FACTORY_MODE,
302 .doit = st21nfca_factory_mode,
305 .vendor_id = ST21NFCA_VENDOR_OUI,
306 .subcmd = HCI_CLEAR_ALL_PIPES,
307 .doit = st21nfca_hci_clear_all_pipes,
310 .vendor_id = ST21NFCA_VENDOR_OUI,
311 .subcmd = HCI_DM_PUT_DATA,
312 .doit = st21nfca_hci_dm_put_data,
315 .vendor_id = ST21NFCA_VENDOR_OUI,
316 .subcmd = HCI_DM_UPDATE_AID,
317 .doit = st21nfca_hci_dm_update_aid,
320 .vendor_id = ST21NFCA_VENDOR_OUI,
321 .subcmd = HCI_DM_GET_INFO,
322 .doit = st21nfca_hci_dm_get_info,
325 .vendor_id = ST21NFCA_VENDOR_OUI,
326 .subcmd = HCI_DM_GET_DATA,
327 .doit = st21nfca_hci_dm_get_data,
330 .vendor_id = ST21NFCA_VENDOR_OUI,
331 .subcmd = HCI_DM_LOAD,
332 .doit = st21nfca_hci_dm_load,
335 .vendor_id = ST21NFCA_VENDOR_OUI,
336 .subcmd = HCI_DM_RESET,
337 .doit = st21nfca_hci_dm_reset,
340 .vendor_id = ST21NFCA_VENDOR_OUI,
341 .subcmd = HCI_GET_PARAM,
342 .doit = st21nfca_hci_get_param,
345 .vendor_id = ST21NFCA_VENDOR_OUI,
346 .subcmd = HCI_DM_FIELD_GENERATOR,
347 .doit = st21nfca_hci_dm_field_generator,
350 .vendor_id = ST21NFCA_VENDOR_OUI,
351 .subcmd = HCI_LOOPBACK,
352 .doit = st21nfca_hci_loopback,
356 int st21nfca_vendor_cmds_init(struct nfc_hci_dev *hdev)
358 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
360 init_completion(&info->vendor_info.req_completion);
361 return nfc_set_vendor_cmds(hdev->ndev, st21nfca_vendor_cmds,
362 sizeof(st21nfca_vendor_cmds));
364 EXPORT_SYMBOL(st21nfca_vendor_cmds_init);