1 /* 2 * 3 * Intel Management Engine Interface (Intel MEI) Linux driver 4 * Copyright (c) 2003-2013, Intel Corporation. 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 it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 */ 16 17 #include <linux/kernel.h> 18 #include <linux/sched.h> 19 #include <linux/module.h> 20 #include <linux/moduleparam.h> 21 #include <linux/device.h> 22 #include <linux/slab.h> 23 #include <linux/uuid.h> 24 25 #include <linux/mei_cl_bus.h> 26 27 #include "mei_dev.h" 28 #include "client.h" 29 30 #define MEI_UUID_NFC_INFO UUID_LE(0xd2de1625, 0x382d, 0x417d, \ 31 0x48, 0xa4, 0xef, 0xab, 0xba, 0x8a, 0x12, 0x06) 32 33 static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO; 34 35 #define MEI_UUID_NFC_HCI UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, \ 36 0x94, 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c) 37 38 #define MEI_UUID_ANY NULL_UUID_LE 39 40 /** 41 * number_of_connections - determine whether an client be on the bus 42 * according number of connections 43 * We support only clients: 44 * 1. with single connection 45 * 2. and fixed clients (max_number_of_connections == 0) 46 * 47 * @cldev: me clients device 48 */ 49 static void number_of_connections(struct mei_cl_device *cldev) 50 { 51 dev_dbg(&cldev->dev, "running hook %s on %pUl\n", 52 __func__, mei_me_cl_uuid(cldev->me_cl)); 53 54 if (cldev->me_cl->props.max_number_of_connections > 1) 55 cldev->do_match = 0; 56 } 57 58 /** 59 * blacklist - blacklist a client from the bus 60 * 61 * @cldev: me clients device 62 */ 63 static void blacklist(struct mei_cl_device *cldev) 64 { 65 dev_dbg(&cldev->dev, "running hook %s on %pUl\n", 66 __func__, mei_me_cl_uuid(cldev->me_cl)); 67 cldev->do_match = 0; 68 } 69 70 struct mei_nfc_cmd { 71 u8 command; 72 u8 status; 73 u16 req_id; 74 u32 reserved; 75 u16 data_size; 76 u8 sub_command; 77 u8 data[]; 78 } __packed; 79 80 struct mei_nfc_reply { 81 u8 command; 82 u8 status; 83 u16 req_id; 84 u32 reserved; 85 u16 data_size; 86 u8 sub_command; 87 u8 reply_status; 88 u8 data[]; 89 } __packed; 90 91 struct mei_nfc_if_version { 92 u8 radio_version_sw[3]; 93 u8 reserved[3]; 94 u8 radio_version_hw[3]; 95 u8 i2c_addr; 96 u8 fw_ivn; 97 u8 vendor_id; 98 u8 radio_type; 99 } __packed; 100 101 102 #define MEI_NFC_CMD_MAINTENANCE 0x00 103 #define MEI_NFC_SUBCMD_IF_VERSION 0x01 104 105 /* Vendors */ 106 #define MEI_NFC_VENDOR_INSIDE 0x00 107 #define MEI_NFC_VENDOR_NXP 0x01 108 109 /* Radio types */ 110 #define MEI_NFC_VENDOR_INSIDE_UREAD 0x00 111 #define MEI_NFC_VENDOR_NXP_PN544 0x01 112 113 /** 114 * mei_nfc_if_version - get NFC interface version 115 * 116 * @cl: host client (nfc info) 117 * @ver: NFC interface version to be filled in 118 * 119 * Return: 0 on success; < 0 otherwise 120 */ 121 static int mei_nfc_if_version(struct mei_cl *cl, 122 struct mei_nfc_if_version *ver) 123 { 124 struct mei_device *bus; 125 struct mei_nfc_cmd cmd = { 126 .command = MEI_NFC_CMD_MAINTENANCE, 127 .data_size = 1, 128 .sub_command = MEI_NFC_SUBCMD_IF_VERSION, 129 }; 130 struct mei_nfc_reply *reply = NULL; 131 size_t if_version_length; 132 int bytes_recv, ret; 133 134 bus = cl->dev; 135 136 WARN_ON(mutex_is_locked(&bus->device_lock)); 137 138 ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd), 1); 139 if (ret < 0) { 140 dev_err(bus->dev, "Could not send IF version cmd\n"); 141 return ret; 142 } 143 144 /* to be sure on the stack we alloc memory */ 145 if_version_length = sizeof(struct mei_nfc_reply) + 146 sizeof(struct mei_nfc_if_version); 147 148 reply = kzalloc(if_version_length, GFP_KERNEL); 149 if (!reply) 150 return -ENOMEM; 151 152 ret = 0; 153 bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length); 154 if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) { 155 dev_err(bus->dev, "Could not read IF version\n"); 156 ret = -EIO; 157 goto err; 158 } 159 160 memcpy(ver, reply->data, sizeof(struct mei_nfc_if_version)); 161 162 dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n", 163 ver->fw_ivn, ver->vendor_id, ver->radio_type); 164 165 err: 166 kfree(reply); 167 return ret; 168 } 169 170 /** 171 * mei_nfc_radio_name - derive nfc radio name from the interface version 172 * 173 * @ver: NFC radio version 174 * 175 * Return: radio name string 176 */ 177 static const char *mei_nfc_radio_name(struct mei_nfc_if_version *ver) 178 { 179 180 if (ver->vendor_id == MEI_NFC_VENDOR_INSIDE) { 181 if (ver->radio_type == MEI_NFC_VENDOR_INSIDE_UREAD) 182 return "microread"; 183 } 184 185 if (ver->vendor_id == MEI_NFC_VENDOR_NXP) { 186 if (ver->radio_type == MEI_NFC_VENDOR_NXP_PN544) 187 return "pn544"; 188 } 189 190 return NULL; 191 } 192 193 /** 194 * mei_nfc - The nfc fixup function. The function retrieves nfc radio 195 * name and set is as device attribute so we can load 196 * the proper device driver for it 197 * 198 * @cldev: me client device (nfc) 199 */ 200 static void mei_nfc(struct mei_cl_device *cldev) 201 { 202 struct mei_device *bus; 203 struct mei_cl *cl; 204 struct mei_me_client *me_cl = NULL; 205 struct mei_nfc_if_version ver; 206 const char *radio_name = NULL; 207 int ret; 208 209 bus = cldev->bus; 210 211 dev_dbg(bus->dev, "running hook %s: %pUl match=%d\n", 212 __func__, mei_me_cl_uuid(cldev->me_cl), cldev->do_match); 213 214 mutex_lock(&bus->device_lock); 215 /* we need to connect to INFO GUID */ 216 cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); 217 if (IS_ERR(cl)) { 218 ret = PTR_ERR(cl); 219 cl = NULL; 220 dev_err(bus->dev, "nfc hook alloc failed %d\n", ret); 221 goto out; 222 } 223 224 me_cl = mei_me_cl_by_uuid(bus, &mei_nfc_info_guid); 225 if (!me_cl) { 226 ret = -ENOTTY; 227 dev_err(bus->dev, "Cannot find nfc info %d\n", ret); 228 goto out; 229 } 230 231 ret = mei_cl_connect(cl, me_cl, NULL); 232 if (ret < 0) { 233 dev_err(&cldev->dev, "Can't connect to the NFC INFO ME ret = %d\n", 234 ret); 235 goto out; 236 } 237 238 mutex_unlock(&bus->device_lock); 239 240 ret = mei_nfc_if_version(cl, &ver); 241 if (ret) 242 goto disconnect; 243 244 radio_name = mei_nfc_radio_name(&ver); 245 246 if (!radio_name) { 247 ret = -ENOENT; 248 dev_err(&cldev->dev, "Can't get the NFC interface version ret = %d\n", 249 ret); 250 goto disconnect; 251 } 252 253 dev_dbg(bus->dev, "nfc radio %s\n", radio_name); 254 strlcpy(cldev->name, radio_name, sizeof(cldev->name)); 255 256 disconnect: 257 mutex_lock(&bus->device_lock); 258 if (mei_cl_disconnect(cl) < 0) 259 dev_err(bus->dev, "Can't disconnect the NFC INFO ME\n"); 260 261 mei_cl_flush_queues(cl, NULL); 262 263 out: 264 mei_cl_unlink(cl); 265 mutex_unlock(&bus->device_lock); 266 mei_me_cl_put(me_cl); 267 kfree(cl); 268 269 if (ret) 270 cldev->do_match = 0; 271 272 dev_dbg(bus->dev, "end of fixup match = %d\n", cldev->do_match); 273 } 274 275 #define MEI_FIXUP(_uuid, _hook) { _uuid, _hook } 276 277 static struct mei_fixup { 278 279 const uuid_le uuid; 280 void (*hook)(struct mei_cl_device *cldev); 281 } mei_fixups[] = { 282 MEI_FIXUP(MEI_UUID_ANY, number_of_connections), 283 MEI_FIXUP(MEI_UUID_NFC_INFO, blacklist), 284 MEI_FIXUP(MEI_UUID_NFC_HCI, mei_nfc), 285 }; 286 287 /** 288 * mei_cl_dev_fixup - run fixup handlers 289 * 290 * @cldev: me client device 291 */ 292 void mei_cl_dev_fixup(struct mei_cl_device *cldev) 293 { 294 struct mei_fixup *f; 295 const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); 296 int i; 297 298 for (i = 0; i < ARRAY_SIZE(mei_fixups); i++) { 299 300 f = &mei_fixups[i]; 301 if (uuid_le_cmp(f->uuid, MEI_UUID_ANY) == 0 || 302 uuid_le_cmp(f->uuid, *uuid) == 0) 303 f->hook(cldev); 304 } 305 } 306 307