linux/drivers/nfc/mei_phy.c
<<
>>
Prefs
   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
  27struct mei_nfc_hdr {
  28        u8 cmd;
  29        u8 status;
  30        u16 req_id;
  31        u32 reserved;
  32        u16 data_size;
  33} __packed;
  34
  35struct mei_nfc_cmd {
  36        struct mei_nfc_hdr hdr;
  37        u8 sub_command;
  38        u8 data[];
  39} __packed;
  40
  41struct mei_nfc_reply {
  42        struct mei_nfc_hdr hdr;
  43        u8 sub_command;
  44        u8 reply_status;
  45        u8 data[];
  46} __packed;
  47
  48struct 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
  58struct mei_nfc_connect {
  59        u8 fw_ivn;
  60        u8 vendor_id;
  61} __packed;
  62
  63struct 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)                              \
  83do {                                                            \
  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)                             \
  90do {                                                            \
  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)                                \
  97do {                                                                \
  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
 104static 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 < if_version_length) {
 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
 148err:
 149        kfree(reply);
 150        return r;
 151}
 152
 153static 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
 214err:
 215        kfree(reply);
 216        kfree(cmd);
 217
 218        return r;
 219}
 220
 221static 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        }
 253out:
 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 */
 263static 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
 277static 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
 300static void nfc_mei_rx_cb(struct mei_cl_device *cldev)
 301{
 302        struct nfc_mei_phy *phy = mei_cldev_get_drvdata(cldev);
 303        struct sk_buff *skb;
 304        int reply_size;
 305
 306        if (!phy)
 307                return;
 308
 309        if (phy->hard_fault != 0)
 310                return;
 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
 330static int nfc_mei_phy_enable(void *phy_id)
 331{
 332        int r;
 333        struct nfc_mei_phy *phy = phy_id;
 334
 335        pr_info("%s\n", __func__);
 336
 337        if (phy->powered == 1)
 338                return 0;
 339
 340        r = mei_cldev_enable(phy->cldev);
 341        if (r < 0) {
 342                pr_err("Could not enable device %d\n", r);
 343                return r;
 344        }
 345
 346        r = mei_nfc_if_version(phy);
 347        if (r < 0) {
 348                pr_err("Could not enable device %d\n", r);
 349                goto err;
 350        }
 351
 352        r = mei_nfc_connect(phy);
 353        if (r < 0) {
 354                pr_err("Could not connect to device %d\n", r);
 355                goto err;
 356        }
 357
 358        r = mei_cldev_register_rx_cb(phy->cldev, nfc_mei_rx_cb);
 359        if (r) {
 360                pr_err("Event cb registration failed %d\n", r);
 361                goto err;
 362        }
 363
 364        phy->powered = 1;
 365
 366        return 0;
 367
 368err:
 369        phy->powered = 0;
 370        mei_cldev_disable(phy->cldev);
 371        return r;
 372}
 373
 374static void nfc_mei_phy_disable(void *phy_id)
 375{
 376        struct nfc_mei_phy *phy = phy_id;
 377
 378        pr_info("%s\n", __func__);
 379
 380        mei_cldev_disable(phy->cldev);
 381
 382        phy->powered = 0;
 383}
 384
 385struct nfc_phy_ops mei_phy_ops = {
 386        .write = nfc_mei_phy_write,
 387        .enable = nfc_mei_phy_enable,
 388        .disable = nfc_mei_phy_disable,
 389};
 390EXPORT_SYMBOL_GPL(mei_phy_ops);
 391
 392struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *cldev)
 393{
 394        struct nfc_mei_phy *phy;
 395
 396        phy = kzalloc(sizeof(struct nfc_mei_phy), GFP_KERNEL);
 397        if (!phy)
 398                return NULL;
 399
 400        phy->cldev = cldev;
 401        init_waitqueue_head(&phy->send_wq);
 402        mei_cldev_set_drvdata(cldev, phy);
 403
 404        return phy;
 405}
 406EXPORT_SYMBOL_GPL(nfc_mei_phy_alloc);
 407
 408void nfc_mei_phy_free(struct nfc_mei_phy *phy)
 409{
 410        mei_cldev_disable(phy->cldev);
 411        kfree(phy);
 412}
 413EXPORT_SYMBOL_GPL(nfc_mei_phy_free);
 414
 415MODULE_LICENSE("GPL");
 416MODULE_DESCRIPTION("mei bus NFC device interface");
 417