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); 376