root/drivers/nfc/mei_phy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mei_nfc_if_version
  2. mei_nfc_connect
  3. mei_nfc_send
  4. nfc_mei_phy_write
  5. mei_nfc_recv
  6. nfc_mei_rx_cb
  7. nfc_mei_phy_enable
  8. nfc_mei_phy_disable
  9. nfc_mei_phy_alloc
  10. nfc_mei_phy_free

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

/* [<][>][^][v][top][bottom][index][help] */