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> 25e0af11faSSamuel Ortiz #include <linux/mei_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 #define MICROREAD_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \ 36e0af11faSSamuel Ortiz 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c) 37e0af11faSSamuel Ortiz 38e0af11faSSamuel Ortiz struct mei_nfc_hdr { 39e0af11faSSamuel Ortiz u8 cmd; 40e0af11faSSamuel Ortiz u8 status; 41e0af11faSSamuel Ortiz u16 req_id; 42e0af11faSSamuel Ortiz u32 reserved; 43e0af11faSSamuel Ortiz u16 data_size; 44e0af11faSSamuel Ortiz } __attribute__((packed)); 45e0af11faSSamuel Ortiz 46e0af11faSSamuel Ortiz #define MEI_NFC_HEADER_SIZE 10 47e0af11faSSamuel Ortiz #define MEI_NFC_MAX_HCI_PAYLOAD 300 48e0af11faSSamuel Ortiz #define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD) 49e0af11faSSamuel Ortiz 50e0af11faSSamuel Ortiz struct microread_mei_phy { 51*cd48d8baSSamuel Ortiz struct mei_device *mei_device; 52e0af11faSSamuel Ortiz struct nfc_hci_dev *hdev; 53e0af11faSSamuel Ortiz 54e0af11faSSamuel Ortiz int powered; 55e0af11faSSamuel Ortiz 56e0af11faSSamuel Ortiz int hard_fault; /* 57e0af11faSSamuel Ortiz * < 0 if hardware error occured (e.g. i2c err) 58e0af11faSSamuel Ortiz * and prevents normal operation. 59e0af11faSSamuel Ortiz */ 60e0af11faSSamuel Ortiz }; 61e0af11faSSamuel Ortiz 62e0af11faSSamuel Ortiz #define MEI_DUMP_SKB_IN(info, skb) \ 63e0af11faSSamuel Ortiz do { \ 64e0af11faSSamuel Ortiz pr_debug("%s:\n", info); \ 65e0af11faSSamuel Ortiz print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET, \ 66e0af11faSSamuel Ortiz 16, 1, (skb)->data, (skb)->len, 0); \ 67e0af11faSSamuel Ortiz } while (0) 68e0af11faSSamuel Ortiz 69e0af11faSSamuel Ortiz #define MEI_DUMP_SKB_OUT(info, skb) \ 70e0af11faSSamuel Ortiz do { \ 71e0af11faSSamuel Ortiz pr_debug("%s:\n", info); \ 72e0af11faSSamuel Ortiz print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET, \ 73e0af11faSSamuel Ortiz 16, 1, (skb)->data, (skb)->len, 0); \ 74e0af11faSSamuel Ortiz } while (0) 75e0af11faSSamuel Ortiz 76e0af11faSSamuel Ortiz static int microread_mei_enable(void *phy_id) 77e0af11faSSamuel Ortiz { 78e0af11faSSamuel Ortiz struct microread_mei_phy *phy = phy_id; 79e0af11faSSamuel Ortiz 80e0af11faSSamuel Ortiz pr_info(DRIVER_DESC ": %s\n", __func__); 81e0af11faSSamuel Ortiz 82e0af11faSSamuel Ortiz phy->powered = 1; 83e0af11faSSamuel Ortiz 84e0af11faSSamuel Ortiz return 0; 85e0af11faSSamuel Ortiz } 86e0af11faSSamuel Ortiz 87e0af11faSSamuel Ortiz static void microread_mei_disable(void *phy_id) 88e0af11faSSamuel Ortiz { 89e0af11faSSamuel Ortiz struct microread_mei_phy *phy = phy_id; 90e0af11faSSamuel Ortiz 91e0af11faSSamuel Ortiz pr_info(DRIVER_DESC ": %s\n", __func__); 92e0af11faSSamuel Ortiz 93e0af11faSSamuel Ortiz phy->powered = 0; 94e0af11faSSamuel Ortiz } 95e0af11faSSamuel Ortiz 96e0af11faSSamuel Ortiz /* 97e0af11faSSamuel Ortiz * Writing a frame must not return the number of written bytes. 98e0af11faSSamuel Ortiz * It must return either zero for success, or <0 for error. 99e0af11faSSamuel Ortiz * In addition, it must not alter the skb 100e0af11faSSamuel Ortiz */ 101e0af11faSSamuel Ortiz static int microread_mei_write(void *phy_id, struct sk_buff *skb) 102e0af11faSSamuel Ortiz { 103e0af11faSSamuel Ortiz struct microread_mei_phy *phy = phy_id; 104e0af11faSSamuel Ortiz int r; 105e0af11faSSamuel Ortiz 106e0af11faSSamuel Ortiz MEI_DUMP_SKB_OUT("mei frame sent", skb); 107e0af11faSSamuel Ortiz 108*cd48d8baSSamuel Ortiz r = mei_send(phy->device, skb->data, skb->len); 109e0af11faSSamuel Ortiz if (r > 0) 110e0af11faSSamuel Ortiz r = 0; 111e0af11faSSamuel Ortiz 112e0af11faSSamuel Ortiz return r; 113e0af11faSSamuel Ortiz } 114e0af11faSSamuel Ortiz 115*cd48d8baSSamuel Ortiz static void microread_event_cb(struct mei_device *device, u32 events, 116e0af11faSSamuel Ortiz void *context) 117e0af11faSSamuel Ortiz { 118e0af11faSSamuel Ortiz struct microread_mei_phy *phy = context; 119e0af11faSSamuel Ortiz 120e0af11faSSamuel Ortiz if (phy->hard_fault != 0) 121e0af11faSSamuel Ortiz return; 122e0af11faSSamuel Ortiz 123*cd48d8baSSamuel Ortiz if (events & BIT(MEI_EVENT_RX)) { 124e0af11faSSamuel Ortiz struct sk_buff *skb; 125e0af11faSSamuel Ortiz int reply_size; 126e0af11faSSamuel Ortiz 127e0af11faSSamuel Ortiz skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL); 128e0af11faSSamuel Ortiz if (!skb) 129e0af11faSSamuel Ortiz return; 130e0af11faSSamuel Ortiz 131*cd48d8baSSamuel Ortiz reply_size = mei_recv(device, skb->data, MEI_NFC_MAX_READ); 132e0af11faSSamuel Ortiz if (reply_size < MEI_NFC_HEADER_SIZE) { 133e0af11faSSamuel Ortiz kfree(skb); 134e0af11faSSamuel Ortiz return; 135e0af11faSSamuel Ortiz } 136e0af11faSSamuel Ortiz 137e0af11faSSamuel Ortiz skb_put(skb, reply_size); 138e0af11faSSamuel Ortiz skb_pull(skb, MEI_NFC_HEADER_SIZE); 139e0af11faSSamuel Ortiz 140e0af11faSSamuel Ortiz MEI_DUMP_SKB_IN("mei frame read", skb); 141e0af11faSSamuel Ortiz 142e0af11faSSamuel Ortiz nfc_hci_recv_frame(phy->hdev, skb); 143e0af11faSSamuel Ortiz } 144e0af11faSSamuel Ortiz } 145e0af11faSSamuel Ortiz 146e0af11faSSamuel Ortiz static struct nfc_phy_ops mei_phy_ops = { 147e0af11faSSamuel Ortiz .write = microread_mei_write, 148e0af11faSSamuel Ortiz .enable = microread_mei_enable, 149e0af11faSSamuel Ortiz .disable = microread_mei_disable, 150e0af11faSSamuel Ortiz }; 151e0af11faSSamuel Ortiz 152*cd48d8baSSamuel Ortiz static int microread_mei_probe(struct mei_device *device, 153*cd48d8baSSamuel Ortiz const struct mei_id *id) 154e0af11faSSamuel Ortiz { 155e0af11faSSamuel Ortiz struct microread_mei_phy *phy; 156e0af11faSSamuel Ortiz int r; 157e0af11faSSamuel Ortiz 158e0af11faSSamuel Ortiz pr_info("Probing NFC microread\n"); 159e0af11faSSamuel Ortiz 160e0af11faSSamuel Ortiz phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL); 161e0af11faSSamuel Ortiz if (!phy) { 162e0af11faSSamuel Ortiz pr_err("Cannot allocate memory for microread mei phy.\n"); 163e0af11faSSamuel Ortiz return -ENOMEM; 164e0af11faSSamuel Ortiz } 165e0af11faSSamuel Ortiz 166*cd48d8baSSamuel Ortiz phy->device = device; 167*cd48d8baSSamuel Ortiz mei_set_clientdata(device, phy); 168e0af11faSSamuel Ortiz 169*cd48d8baSSamuel Ortiz r = mei_register_event_cb(device, microread_event_cb, phy); 170e0af11faSSamuel Ortiz if (r) { 171e0af11faSSamuel Ortiz pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n"); 172e0af11faSSamuel Ortiz goto err_out; 173e0af11faSSamuel Ortiz } 174e0af11faSSamuel Ortiz 175e0af11faSSamuel Ortiz r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME, 176e0af11faSSamuel Ortiz MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, 177e0af11faSSamuel Ortiz &phy->hdev); 178e0af11faSSamuel Ortiz if (r < 0) 179e0af11faSSamuel Ortiz goto err_out; 180e0af11faSSamuel Ortiz 181e0af11faSSamuel Ortiz return 0; 182e0af11faSSamuel Ortiz 183e0af11faSSamuel Ortiz err_out: 184e0af11faSSamuel Ortiz kfree(phy); 185e0af11faSSamuel Ortiz 186e0af11faSSamuel Ortiz return r; 187e0af11faSSamuel Ortiz } 188e0af11faSSamuel Ortiz 189*cd48d8baSSamuel Ortiz static int microread_mei_remove(struct mei_device *device) 190e0af11faSSamuel Ortiz { 191*cd48d8baSSamuel Ortiz struct microread_mei_phy *phy = mei_get_clientdata(device); 192e0af11faSSamuel Ortiz 193e0af11faSSamuel Ortiz pr_info("Removing microread\n"); 194e0af11faSSamuel Ortiz 195e0af11faSSamuel Ortiz microread_remove(phy->hdev); 196e0af11faSSamuel Ortiz 197e0af11faSSamuel Ortiz if (phy->powered) 198e0af11faSSamuel Ortiz microread_mei_disable(phy); 199e0af11faSSamuel Ortiz 200e0af11faSSamuel Ortiz kfree(phy); 201e0af11faSSamuel Ortiz 202e0af11faSSamuel Ortiz return 0; 203e0af11faSSamuel Ortiz } 204e0af11faSSamuel Ortiz 205*cd48d8baSSamuel Ortiz static struct mei_id microread_mei_tbl[] = { 206*cd48d8baSSamuel Ortiz { MICROREAD_DRIVER_NAME, MICROREAD_UUID }, 207*cd48d8baSSamuel Ortiz 208*cd48d8baSSamuel Ortiz /* required last entry */ 209*cd48d8baSSamuel Ortiz { } 210*cd48d8baSSamuel Ortiz }; 211*cd48d8baSSamuel Ortiz 212*cd48d8baSSamuel Ortiz MODULE_DEVICE_TABLE(mei, microread_mei_tbl); 213*cd48d8baSSamuel Ortiz 214*cd48d8baSSamuel Ortiz static struct mei_driver microread_driver = { 215*cd48d8baSSamuel Ortiz .id_table = microread_mei_tbl, 216e0af11faSSamuel Ortiz .name = MICROREAD_DRIVER_NAME, 217e0af11faSSamuel Ortiz 218e0af11faSSamuel Ortiz .probe = microread_mei_probe, 219e0af11faSSamuel Ortiz .remove = microread_mei_remove, 220e0af11faSSamuel Ortiz }; 221e0af11faSSamuel Ortiz 222e0af11faSSamuel Ortiz static int microread_mei_init(void) 223e0af11faSSamuel Ortiz { 224e0af11faSSamuel Ortiz int r; 225e0af11faSSamuel Ortiz 226e0af11faSSamuel Ortiz pr_debug(DRIVER_DESC ": %s\n", __func__); 227e0af11faSSamuel Ortiz 228e0af11faSSamuel Ortiz r = mei_driver_register(µread_driver); 229e0af11faSSamuel Ortiz if (r) { 230e0af11faSSamuel Ortiz pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n"); 231e0af11faSSamuel Ortiz return r; 232e0af11faSSamuel Ortiz } 233e0af11faSSamuel Ortiz 234e0af11faSSamuel Ortiz return 0; 235e0af11faSSamuel Ortiz } 236e0af11faSSamuel Ortiz 237e0af11faSSamuel Ortiz static void microread_mei_exit(void) 238e0af11faSSamuel Ortiz { 239e0af11faSSamuel Ortiz mei_driver_unregister(µread_driver); 240e0af11faSSamuel Ortiz } 241e0af11faSSamuel Ortiz 242e0af11faSSamuel Ortiz module_init(microread_mei_init); 243e0af11faSSamuel Ortiz module_exit(microread_mei_exit); 244e0af11faSSamuel Ortiz 245e0af11faSSamuel Ortiz MODULE_LICENSE("GPL"); 246e0af11faSSamuel Ortiz MODULE_DESCRIPTION(DRIVER_DESC); 247