1 /* 2 * MEI Library for mei bus nfc device access 3 * 4 * Copyright (C) 2013 Intel Corporation. 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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 20 21 #include <linux/module.h> 22 #include <linux/slab.h> 23 #include <linux/nfc.h> 24 25 #include "mei_phy.h" 26 27 struct mei_nfc_hdr { 28 u8 cmd; 29 u8 status; 30 u16 req_id; 31 u32 reserved; 32 u16 data_size; 33 } __packed; 34 35 struct mei_nfc_cmd { 36 struct mei_nfc_hdr hdr; 37 u8 sub_command; 38 u8 data[]; 39 } __packed; 40 41 struct mei_nfc_reply { 42 struct mei_nfc_hdr hdr; 43 u8 sub_command; 44 u8 reply_status; 45 u8 data[]; 46 } __packed; 47 48 struct mei_nfc_if_version { 49 u8 radio_version_sw[3]; 50 u8 reserved[3]; 51 u8 radio_version_hw[3]; 52 u8 i2c_addr; 53 u8 fw_ivn; 54 u8 vendor_id; 55 u8 radio_type; 56 } __packed; 57 58 struct mei_nfc_connect { 59 u8 fw_ivn; 60 u8 vendor_id; 61 } __packed; 62 63 struct mei_nfc_connect_resp { 64 u8 fw_ivn; 65 u8 vendor_id; 66 u16 me_major; 67 u16 me_minor; 68 u16 me_hotfix; 69 u16 me_build; 70 } __packed; 71 72 73 #define MEI_NFC_CMD_MAINTENANCE 0x00 74 #define MEI_NFC_CMD_HCI_SEND 0x01 75 #define MEI_NFC_CMD_HCI_RECV 0x02 76 77 #define MEI_NFC_SUBCMD_CONNECT 0x00 78 #define MEI_NFC_SUBCMD_IF_VERSION 0x01 79 80 #define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD) 81 82 #define MEI_DUMP_SKB_IN(info, skb) \ 83 do { \ 84 pr_debug("%s:\n", info); \ 85 print_hex_dump_debug("mei in : ", DUMP_PREFIX_OFFSET, \ 86 16, 1, (skb)->data, (skb)->len, false); \ 87 } while (0) 88 89 #define MEI_DUMP_SKB_OUT(info, skb) \ 90 do { \ 91 pr_debug("%s:\n", info); \ 92 print_hex_dump_debug("mei out: ", DUMP_PREFIX_OFFSET, \ 93 16, 1, (skb)->data, (skb)->len, false); \ 94 } while (0) 95 96 #define MEI_DUMP_NFC_HDR(info, _hdr) \ 97 do { \ 98 pr_debug("%s:\n", info); \ 99 pr_debug("cmd=%02d status=%d req_id=%d rsvd=%d size=%d\n", \ 100 (_hdr)->cmd, (_hdr)->status, (_hdr)->req_id, \ 101 (_hdr)->reserved, (_hdr)->data_size); \ 102 } while (0) 103 104 static int mei_nfc_if_version(struct nfc_mei_phy *phy) 105 { 106 107 struct mei_nfc_cmd cmd; 108 struct mei_nfc_reply *reply = NULL; 109 struct mei_nfc_if_version *version; 110 size_t if_version_length; 111 int bytes_recv, r; 112 113 pr_info("%s\n", __func__); 114 115 memset(&cmd, 0, sizeof(struct mei_nfc_cmd)); 116 cmd.hdr.cmd = MEI_NFC_CMD_MAINTENANCE; 117 cmd.hdr.data_size = 1; 118 cmd.sub_command = MEI_NFC_SUBCMD_IF_VERSION; 119 120 MEI_DUMP_NFC_HDR("version", &cmd.hdr); 121 r = mei_cldev_send(phy->cldev, (u8 *)&cmd, sizeof(struct mei_nfc_cmd)); 122 if (r < 0) { 123 pr_err("Could not send IF version cmd\n"); 124 return r; 125 } 126 127 /* to be sure on the stack we alloc memory */ 128 if_version_length = sizeof(struct mei_nfc_reply) + 129 sizeof(struct mei_nfc_if_version); 130 131 reply = kzalloc(if_version_length, GFP_KERNEL); 132 if (!reply) 133 return -ENOMEM; 134 135 bytes_recv = mei_cldev_recv(phy->cldev, (u8 *)reply, if_version_length); 136 if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) { 137 pr_err("Could not read IF version\n"); 138 r = -EIO; 139 goto err; 140 } 141 142 version = (struct mei_nfc_if_version *)reply->data; 143 144 phy->fw_ivn = version->fw_ivn; 145 phy->vendor_id = version->vendor_id; 146 phy->radio_type = version->radio_type; 147 148 err: 149 kfree(reply); 150 return r; 151 } 152 153 static int mei_nfc_connect(struct nfc_mei_phy *phy) 154 { 155 struct mei_nfc_cmd *cmd, *reply; 156 struct mei_nfc_connect *connect; 157 struct mei_nfc_connect_resp *connect_resp; 158 size_t connect_length, connect_resp_length; 159 int bytes_recv, r; 160 161 pr_info("%s\n", __func__); 162 163 connect_length = sizeof(struct mei_nfc_cmd) + 164 sizeof(struct mei_nfc_connect); 165 166 connect_resp_length = sizeof(struct mei_nfc_cmd) + 167 sizeof(struct mei_nfc_connect_resp); 168 169 cmd = kzalloc(connect_length, GFP_KERNEL); 170 if (!cmd) 171 return -ENOMEM; 172 connect = (struct mei_nfc_connect *)cmd->data; 173 174 reply = kzalloc(connect_resp_length, GFP_KERNEL); 175 if (!reply) { 176 kfree(cmd); 177 return -ENOMEM; 178 } 179 180 connect_resp = (struct mei_nfc_connect_resp *)reply->data; 181 182 cmd->hdr.cmd = MEI_NFC_CMD_MAINTENANCE; 183 cmd->hdr.data_size = 3; 184 cmd->sub_command = MEI_NFC_SUBCMD_CONNECT; 185 connect->fw_ivn = phy->fw_ivn; 186 connect->vendor_id = phy->vendor_id; 187 188 MEI_DUMP_NFC_HDR("connect request", &cmd->hdr); 189 r = mei_cldev_send(phy->cldev, (u8 *)cmd, connect_length); 190 if (r < 0) { 191 pr_err("Could not send connect cmd %d\n", r); 192 goto err; 193 } 194 195 bytes_recv = mei_cldev_recv(phy->cldev, (u8 *)reply, 196 connect_resp_length); 197 if (bytes_recv < 0) { 198 r = bytes_recv; 199 pr_err("Could not read connect response %d\n", r); 200 goto err; 201 } 202 203 MEI_DUMP_NFC_HDR("connect reply", &reply->hdr); 204 205 pr_info("IVN 0x%x Vendor ID 0x%x\n", 206 connect_resp->fw_ivn, connect_resp->vendor_id); 207 208 pr_info("ME FW %d.%d.%d.%d\n", 209 connect_resp->me_major, connect_resp->me_minor, 210 connect_resp->me_hotfix, connect_resp->me_build); 211 212 r = 0; 213 214 err: 215 kfree(reply); 216 kfree(cmd); 217 218 return r; 219 } 220 221 static int mei_nfc_send(struct nfc_mei_phy *phy, u8 *buf, size_t length) 222 { 223 struct mei_nfc_hdr *hdr; 224 u8 *mei_buf; 225 int err; 226 227 err = -ENOMEM; 228 mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL); 229 if (!mei_buf) 230 goto out; 231 232 hdr = (struct mei_nfc_hdr *)mei_buf; 233 hdr->cmd = MEI_NFC_CMD_HCI_SEND; 234 hdr->status = 0; 235 hdr->req_id = phy->req_id; 236 hdr->reserved = 0; 237 hdr->data_size = length; 238 239 MEI_DUMP_NFC_HDR("send", hdr); 240 241 memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length); 242 err = mei_cldev_send(phy->cldev, mei_buf, length + MEI_NFC_HEADER_SIZE); 243 if (err < 0) 244 goto out; 245 246 if (!wait_event_interruptible_timeout(phy->send_wq, 247 phy->recv_req_id == phy->req_id, HZ)) { 248 pr_err("NFC MEI command timeout\n"); 249 err = -ETIME; 250 } else { 251 phy->req_id++; 252 } 253 out: 254 kfree(mei_buf); 255 return err; 256 } 257 258 /* 259 * Writing a frame must not return the number of written bytes. 260 * It must return either zero for success, or <0 for error. 261 * In addition, it must not alter the skb 262 */ 263 static int nfc_mei_phy_write(void *phy_id, struct sk_buff *skb) 264 { 265 struct nfc_mei_phy *phy = phy_id; 266 int r; 267 268 MEI_DUMP_SKB_OUT("mei frame sent", skb); 269 270 r = mei_nfc_send(phy, skb->data, skb->len); 271 if (r > 0) 272 r = 0; 273 274 return r; 275 } 276 277 static int mei_nfc_recv(struct nfc_mei_phy *phy, u8 *buf, size_t length) 278 { 279 struct mei_nfc_hdr *hdr; 280 int received_length; 281 282 received_length = mei_cldev_recv(phy->cldev, buf, length); 283 if (received_length < 0) 284 return received_length; 285 286 hdr = (struct mei_nfc_hdr *) buf; 287 288 MEI_DUMP_NFC_HDR("receive", hdr); 289 if (hdr->cmd == MEI_NFC_CMD_HCI_SEND) { 290 phy->recv_req_id = hdr->req_id; 291 wake_up(&phy->send_wq); 292 293 return 0; 294 } 295 296 return received_length; 297 } 298 299 300 static void nfc_mei_event_cb(struct mei_cl_device *cldev, u32 events, 301 void *context) 302 { 303 struct nfc_mei_phy *phy = context; 304 305 if (phy->hard_fault != 0) 306 return; 307 308 if (events & BIT(MEI_CL_EVENT_RX)) { 309 struct sk_buff *skb; 310 int reply_size; 311 312 skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL); 313 if (!skb) 314 return; 315 316 reply_size = mei_nfc_recv(phy, skb->data, MEI_NFC_MAX_READ); 317 if (reply_size < MEI_NFC_HEADER_SIZE) { 318 kfree_skb(skb); 319 return; 320 } 321 322 skb_put(skb, reply_size); 323 skb_pull(skb, MEI_NFC_HEADER_SIZE); 324 325 MEI_DUMP_SKB_IN("mei frame read", skb); 326 327 nfc_hci_recv_frame(phy->hdev, skb); 328 } 329 } 330 331 static int nfc_mei_phy_enable(void *phy_id) 332 { 333 int r; 334 struct nfc_mei_phy *phy = phy_id; 335 336 pr_info("%s\n", __func__); 337 338 if (phy->powered == 1) 339 return 0; 340 341 r = mei_cldev_enable(phy->cldev); 342 if (r < 0) { 343 pr_err("Could not enable device %d\n", r); 344 return r; 345 } 346 347 r = mei_nfc_if_version(phy); 348 if (r < 0) { 349 pr_err("Could not enable device %d\n", r); 350 goto err; 351 } 352 353 r = mei_nfc_connect(phy); 354 if (r < 0) { 355 pr_err("Could not connect to device %d\n", r); 356 goto err; 357 } 358 359 r = mei_cldev_register_event_cb(phy->cldev, BIT(MEI_CL_EVENT_RX), 360 nfc_mei_event_cb, phy); 361 if (r) { 362 pr_err("Event cb registration failed %d\n", r); 363 goto err; 364 } 365 366 phy->powered = 1; 367 368 return 0; 369 370 err: 371 phy->powered = 0; 372 mei_cldev_disable(phy->cldev); 373 return r; 374 } 375 376 static void nfc_mei_phy_disable(void *phy_id) 377 { 378 struct nfc_mei_phy *phy = phy_id; 379 380 pr_info("%s\n", __func__); 381 382 mei_cldev_disable(phy->cldev); 383 384 phy->powered = 0; 385 } 386 387 struct nfc_phy_ops mei_phy_ops = { 388 .write = nfc_mei_phy_write, 389 .enable = nfc_mei_phy_enable, 390 .disable = nfc_mei_phy_disable, 391 }; 392 EXPORT_SYMBOL_GPL(mei_phy_ops); 393 394 struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *cldev) 395 { 396 struct nfc_mei_phy *phy; 397 398 phy = kzalloc(sizeof(struct nfc_mei_phy), GFP_KERNEL); 399 if (!phy) 400 return NULL; 401 402 phy->cldev = cldev; 403 init_waitqueue_head(&phy->send_wq); 404 mei_cldev_set_drvdata(cldev, phy); 405 406 return phy; 407 } 408 EXPORT_SYMBOL_GPL(nfc_mei_phy_alloc); 409 410 void nfc_mei_phy_free(struct nfc_mei_phy *phy) 411 { 412 mei_cldev_disable(phy->cldev); 413 kfree(phy); 414 } 415 EXPORT_SYMBOL_GPL(nfc_mei_phy_free); 416 417 MODULE_LICENSE("GPL"); 418 MODULE_DESCRIPTION("mei bus NFC device interface"); 419