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 < 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
 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_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
 331static 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
 370err:
 371        phy->powered = 0;
 372        mei_cldev_disable(phy->cldev);
 373        return r;
 374}
 375
 376static 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
 387struct 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};
 392EXPORT_SYMBOL_GPL(mei_phy_ops);
 393
 394struct 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}
 408EXPORT_SYMBOL_GPL(nfc_mei_phy_alloc);
 409
 410void nfc_mei_phy_free(struct nfc_mei_phy *phy)
 411{
 412        mei_cldev_disable(phy->cldev);
 413        kfree(phy);
 414}
 415EXPORT_SYMBOL_GPL(nfc_mei_phy_free);
 416
 417MODULE_LICENSE("GPL");
 418MODULE_DESCRIPTION("mei bus NFC device interface");
 419