1e0af11faSSamuel Ortiz /* 2e0af11faSSamuel Ortiz * HCI based Driver for Inside Secure microread NFC Chip 3e0af11faSSamuel Ortiz * 4e0af11faSSamuel Ortiz * Copyright (C) 2013 Intel Corporation. All rights reserved. 5e0af11faSSamuel Ortiz * 6e0af11faSSamuel Ortiz * This program is free software; you can redistribute it and/or modify it 7e0af11faSSamuel Ortiz * under the terms and conditions of the GNU General Public License, 8e0af11faSSamuel Ortiz * version 2, as published by the Free Software Foundation. 9e0af11faSSamuel Ortiz * 10e0af11faSSamuel Ortiz * This program is distributed in the hope that it will be useful, 11e0af11faSSamuel Ortiz * but WITHOUT ANY WARRANTY; without even the implied warranty of 12e0af11faSSamuel Ortiz * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13e0af11faSSamuel Ortiz * GNU General Public License for more details. 14e0af11faSSamuel Ortiz * 15e0af11faSSamuel Ortiz * You should have received a copy of the GNU General Public License 16e0af11faSSamuel Ortiz * along with this program; if not, write to the 17e0af11faSSamuel Ortiz * Free Software Foundation, Inc., 18e0af11faSSamuel Ortiz * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19e0af11faSSamuel Ortiz */ 20e0af11faSSamuel Ortiz 21e0af11faSSamuel Ortiz #include <linux/module.h> 22e0af11faSSamuel Ortiz #include <linux/slab.h> 23e0af11faSSamuel Ortiz #include <linux/interrupt.h> 24e0af11faSSamuel Ortiz #include <linux/gpio.h> 25*9593b0b1SSamuel Ortiz #include <linux/mei_cl_bus.h> 26e0af11faSSamuel Ortiz 27e0af11faSSamuel Ortiz #include <linux/nfc.h> 28e0af11faSSamuel Ortiz #include <net/nfc/hci.h> 29e0af11faSSamuel Ortiz #include <net/nfc/llc.h> 30e0af11faSSamuel Ortiz 31e0af11faSSamuel Ortiz #include "microread.h" 32e0af11faSSamuel Ortiz 33e0af11faSSamuel Ortiz #define MICROREAD_DRIVER_NAME "microread" 34e0af11faSSamuel Ortiz 35e0af11faSSamuel Ortiz struct mei_nfc_hdr { 36e0af11faSSamuel Ortiz u8 cmd; 37e0af11faSSamuel Ortiz u8 status; 38e0af11faSSamuel Ortiz u16 req_id; 39e0af11faSSamuel Ortiz u32 reserved; 40e0af11faSSamuel Ortiz u16 data_size; 41e0af11faSSamuel Ortiz } __attribute__((packed)); 42e0af11faSSamuel Ortiz 43e0af11faSSamuel Ortiz #define MEI_NFC_HEADER_SIZE 10 44e0af11faSSamuel Ortiz #define MEI_NFC_MAX_HCI_PAYLOAD 300 45e0af11faSSamuel Ortiz #define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD) 46e0af11faSSamuel Ortiz 47e0af11faSSamuel Ortiz struct microread_mei_phy { 48*9593b0b1SSamuel Ortiz struct mei_cl_device *device; 49e0af11faSSamuel Ortiz struct nfc_hci_dev *hdev; 50e0af11faSSamuel Ortiz 51e0af11faSSamuel Ortiz int powered; 52e0af11faSSamuel Ortiz 53e0af11faSSamuel Ortiz int hard_fault; /* 54e0af11faSSamuel Ortiz * < 0 if hardware error occured (e.g. i2c err) 55e0af11faSSamuel Ortiz * and prevents normal operation. 56e0af11faSSamuel Ortiz */ 57e0af11faSSamuel Ortiz }; 58e0af11faSSamuel Ortiz 59e0af11faSSamuel Ortiz #define MEI_DUMP_SKB_IN(info, skb) \ 60e0af11faSSamuel Ortiz do { \ 61e0af11faSSamuel Ortiz pr_debug("%s:\n", info); \ 62e0af11faSSamuel Ortiz print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET, \ 63e0af11faSSamuel Ortiz 16, 1, (skb)->data, (skb)->len, 0); \ 64e0af11faSSamuel Ortiz } while (0) 65e0af11faSSamuel Ortiz 66e0af11faSSamuel Ortiz #define MEI_DUMP_SKB_OUT(info, skb) \ 67e0af11faSSamuel Ortiz do { \ 68e0af11faSSamuel Ortiz pr_debug("%s:\n", info); \ 69e0af11faSSamuel Ortiz print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET, \ 70e0af11faSSamuel Ortiz 16, 1, (skb)->data, (skb)->len, 0); \ 71e0af11faSSamuel Ortiz } while (0) 72e0af11faSSamuel Ortiz 73e0af11faSSamuel Ortiz static int microread_mei_enable(void *phy_id) 74e0af11faSSamuel Ortiz { 75e0af11faSSamuel Ortiz struct microread_mei_phy *phy = phy_id; 76e0af11faSSamuel Ortiz 77e0af11faSSamuel Ortiz pr_info(DRIVER_DESC ": %s\n", __func__); 78e0af11faSSamuel Ortiz 79e0af11faSSamuel Ortiz phy->powered = 1; 80e0af11faSSamuel Ortiz 81e0af11faSSamuel Ortiz return 0; 82e0af11faSSamuel Ortiz } 83e0af11faSSamuel Ortiz 84e0af11faSSamuel Ortiz static void microread_mei_disable(void *phy_id) 85e0af11faSSamuel Ortiz { 86e0af11faSSamuel Ortiz struct microread_mei_phy *phy = phy_id; 87e0af11faSSamuel Ortiz 88e0af11faSSamuel Ortiz pr_info(DRIVER_DESC ": %s\n", __func__); 89e0af11faSSamuel Ortiz 90e0af11faSSamuel Ortiz phy->powered = 0; 91e0af11faSSamuel Ortiz } 92e0af11faSSamuel Ortiz 93e0af11faSSamuel Ortiz /* 94e0af11faSSamuel Ortiz * Writing a frame must not return the number of written bytes. 95e0af11faSSamuel Ortiz * It must return either zero for success, or <0 for error. 96e0af11faSSamuel Ortiz * In addition, it must not alter the skb 97e0af11faSSamuel Ortiz */ 98e0af11faSSamuel Ortiz static int microread_mei_write(void *phy_id, struct sk_buff *skb) 99e0af11faSSamuel Ortiz { 100e0af11faSSamuel Ortiz struct microread_mei_phy *phy = phy_id; 101e0af11faSSamuel Ortiz int r; 102e0af11faSSamuel Ortiz 103e0af11faSSamuel Ortiz MEI_DUMP_SKB_OUT("mei frame sent", skb); 104e0af11faSSamuel Ortiz 105*9593b0b1SSamuel Ortiz r = mei_cl_send(phy->device, skb->data, skb->len); 106e0af11faSSamuel Ortiz if (r > 0) 107e0af11faSSamuel Ortiz r = 0; 108e0af11faSSamuel Ortiz 109e0af11faSSamuel Ortiz return r; 110e0af11faSSamuel Ortiz } 111e0af11faSSamuel Ortiz 112*9593b0b1SSamuel Ortiz static void microread_event_cb(struct mei_cl_device *device, u32 events, 113e0af11faSSamuel Ortiz void *context) 114e0af11faSSamuel Ortiz { 115e0af11faSSamuel Ortiz struct microread_mei_phy *phy = context; 116e0af11faSSamuel Ortiz 117e0af11faSSamuel Ortiz if (phy->hard_fault != 0) 118e0af11faSSamuel Ortiz return; 119e0af11faSSamuel Ortiz 120*9593b0b1SSamuel Ortiz if (events & BIT(MEI_CL_EVENT_RX)) { 121e0af11faSSamuel Ortiz struct sk_buff *skb; 122e0af11faSSamuel Ortiz int reply_size; 123e0af11faSSamuel Ortiz 124e0af11faSSamuel Ortiz skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL); 125e0af11faSSamuel Ortiz if (!skb) 126e0af11faSSamuel Ortiz return; 127e0af11faSSamuel Ortiz 128*9593b0b1SSamuel Ortiz reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ); 129e0af11faSSamuel Ortiz if (reply_size < MEI_NFC_HEADER_SIZE) { 130e0af11faSSamuel Ortiz kfree(skb); 131e0af11faSSamuel Ortiz return; 132e0af11faSSamuel Ortiz } 133e0af11faSSamuel Ortiz 134e0af11faSSamuel Ortiz skb_put(skb, reply_size); 135e0af11faSSamuel Ortiz skb_pull(skb, MEI_NFC_HEADER_SIZE); 136e0af11faSSamuel Ortiz 137e0af11faSSamuel Ortiz MEI_DUMP_SKB_IN("mei frame read", skb); 138e0af11faSSamuel Ortiz 139e0af11faSSamuel Ortiz nfc_hci_recv_frame(phy->hdev, skb); 140e0af11faSSamuel Ortiz } 141e0af11faSSamuel Ortiz } 142e0af11faSSamuel Ortiz 143e0af11faSSamuel Ortiz static struct nfc_phy_ops mei_phy_ops = { 144e0af11faSSamuel Ortiz .write = microread_mei_write, 145e0af11faSSamuel Ortiz .enable = microread_mei_enable, 146e0af11faSSamuel Ortiz .disable = microread_mei_disable, 147e0af11faSSamuel Ortiz }; 148e0af11faSSamuel Ortiz 149*9593b0b1SSamuel Ortiz static int microread_mei_probe(struct mei_cl_device *device, 150*9593b0b1SSamuel Ortiz const struct mei_cl_device_id *id) 151e0af11faSSamuel Ortiz { 152e0af11faSSamuel Ortiz struct microread_mei_phy *phy; 153e0af11faSSamuel Ortiz int r; 154e0af11faSSamuel Ortiz 155e0af11faSSamuel Ortiz pr_info("Probing NFC microread\n"); 156e0af11faSSamuel Ortiz 157e0af11faSSamuel Ortiz phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL); 158e0af11faSSamuel Ortiz if (!phy) { 159e0af11faSSamuel Ortiz pr_err("Cannot allocate memory for microread mei phy.\n"); 160e0af11faSSamuel Ortiz return -ENOMEM; 161e0af11faSSamuel Ortiz } 162e0af11faSSamuel Ortiz 163cd48d8baSSamuel Ortiz phy->device = device; 164*9593b0b1SSamuel Ortiz mei_cl_set_drvdata(device, phy); 165e0af11faSSamuel Ortiz 166*9593b0b1SSamuel Ortiz r = mei_cl_register_event_cb(device, microread_event_cb, phy); 167e0af11faSSamuel Ortiz if (r) { 168e0af11faSSamuel Ortiz pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n"); 169e0af11faSSamuel Ortiz goto err_out; 170e0af11faSSamuel Ortiz } 171e0af11faSSamuel Ortiz 172e0af11faSSamuel Ortiz r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME, 173e0af11faSSamuel Ortiz MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, 174e0af11faSSamuel Ortiz &phy->hdev); 175e0af11faSSamuel Ortiz if (r < 0) 176e0af11faSSamuel Ortiz goto err_out; 177e0af11faSSamuel Ortiz 178e0af11faSSamuel Ortiz return 0; 179e0af11faSSamuel Ortiz 180e0af11faSSamuel Ortiz err_out: 181e0af11faSSamuel Ortiz kfree(phy); 182e0af11faSSamuel Ortiz 183e0af11faSSamuel Ortiz return r; 184e0af11faSSamuel Ortiz } 185e0af11faSSamuel Ortiz 186*9593b0b1SSamuel Ortiz static int microread_mei_remove(struct mei_cl_device *device) 187e0af11faSSamuel Ortiz { 188*9593b0b1SSamuel Ortiz struct microread_mei_phy *phy = mei_cl_get_drvdata(device); 189e0af11faSSamuel Ortiz 190e0af11faSSamuel Ortiz pr_info("Removing microread\n"); 191e0af11faSSamuel Ortiz 192e0af11faSSamuel Ortiz microread_remove(phy->hdev); 193e0af11faSSamuel Ortiz 194e0af11faSSamuel Ortiz if (phy->powered) 195e0af11faSSamuel Ortiz microread_mei_disable(phy); 196e0af11faSSamuel Ortiz 197e0af11faSSamuel Ortiz kfree(phy); 198e0af11faSSamuel Ortiz 199e0af11faSSamuel Ortiz return 0; 200e0af11faSSamuel Ortiz } 201e0af11faSSamuel Ortiz 202*9593b0b1SSamuel Ortiz static struct mei_cl_device_id microread_mei_tbl[] = { 203*9593b0b1SSamuel Ortiz { MICROREAD_DRIVER_NAME }, 204cd48d8baSSamuel Ortiz 205cd48d8baSSamuel Ortiz /* required last entry */ 206cd48d8baSSamuel Ortiz { } 207cd48d8baSSamuel Ortiz }; 208cd48d8baSSamuel Ortiz MODULE_DEVICE_TABLE(mei, microread_mei_tbl); 209cd48d8baSSamuel Ortiz 210*9593b0b1SSamuel Ortiz static struct mei_cl_driver microread_driver = { 211cd48d8baSSamuel Ortiz .id_table = microread_mei_tbl, 212e0af11faSSamuel Ortiz .name = MICROREAD_DRIVER_NAME, 213e0af11faSSamuel Ortiz 214e0af11faSSamuel Ortiz .probe = microread_mei_probe, 215e0af11faSSamuel Ortiz .remove = microread_mei_remove, 216e0af11faSSamuel Ortiz }; 217e0af11faSSamuel Ortiz 218e0af11faSSamuel Ortiz static int microread_mei_init(void) 219e0af11faSSamuel Ortiz { 220e0af11faSSamuel Ortiz int r; 221e0af11faSSamuel Ortiz 222e0af11faSSamuel Ortiz pr_debug(DRIVER_DESC ": %s\n", __func__); 223e0af11faSSamuel Ortiz 224*9593b0b1SSamuel Ortiz r = mei_cl_driver_register(µread_driver); 225e0af11faSSamuel Ortiz if (r) { 226e0af11faSSamuel Ortiz pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n"); 227e0af11faSSamuel Ortiz return r; 228e0af11faSSamuel Ortiz } 229e0af11faSSamuel Ortiz 230e0af11faSSamuel Ortiz return 0; 231e0af11faSSamuel Ortiz } 232e0af11faSSamuel Ortiz 233e0af11faSSamuel Ortiz static void microread_mei_exit(void) 234e0af11faSSamuel Ortiz { 235*9593b0b1SSamuel Ortiz mei_cl_driver_unregister(µread_driver); 236e0af11faSSamuel Ortiz } 237e0af11faSSamuel Ortiz 238e0af11faSSamuel Ortiz module_init(microread_mei_init); 239e0af11faSSamuel Ortiz module_exit(microread_mei_exit); 240e0af11faSSamuel Ortiz 241e0af11faSSamuel Ortiz MODULE_LICENSE("GPL"); 242e0af11faSSamuel Ortiz MODULE_DESCRIPTION(DRIVER_DESC); 243