blob: 3adf8a70f26e7af6bf4c849b5dc7de31205cdc03 [file] [log] [blame]
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +02001/*
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>
Samuel Ortiz36eda942013-04-11 03:03:31 +020018#include <linux/sched.h>
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +020019#include <linux/module.h>
20#include <linux/moduleparam.h>
21#include <linux/device.h>
22#include <linux/pci.h>
23#include <linux/mei_cl_bus.h>
24
25#include "mei_dev.h"
26#include "client.h"
27
28struct mei_nfc_cmd {
29 u8 command;
30 u8 status;
31 u16 req_id;
32 u32 reserved;
33 u16 data_size;
34 u8 sub_command;
35 u8 data[];
36} __packed;
37
38struct mei_nfc_reply {
39 u8 command;
40 u8 status;
41 u16 req_id;
42 u32 reserved;
43 u16 data_size;
44 u8 sub_command;
45 u8 reply_status;
46 u8 data[];
47} __packed;
48
49struct mei_nfc_if_version {
50 u8 radio_version_sw[3];
51 u8 reserved[3];
52 u8 radio_version_hw[3];
53 u8 i2c_addr;
54 u8 fw_ivn;
55 u8 vendor_id;
56 u8 radio_type;
57} __packed;
58
59struct mei_nfc_connect {
60 u8 fw_ivn;
61 u8 vendor_id;
62} __packed;
63
64struct mei_nfc_connect_resp {
65 u8 fw_ivn;
66 u8 vendor_id;
67 u16 me_major;
68 u16 me_minor;
69 u16 me_hotfix;
70 u16 me_build;
71} __packed;
72
73struct mei_nfc_hci_hdr {
74 u8 cmd;
75 u8 status;
76 u16 req_id;
77 u32 reserved;
78 u16 data_size;
79} __packed;
80
81#define MEI_NFC_CMD_MAINTENANCE 0x00
82#define MEI_NFC_CMD_HCI_SEND 0x01
83#define MEI_NFC_CMD_HCI_RECV 0x02
84
85#define MEI_NFC_SUBCMD_CONNECT 0x00
86#define MEI_NFC_SUBCMD_IF_VERSION 0x01
87
88#define MEI_NFC_HEADER_SIZE 10
89
90/** mei_nfc_dev - NFC mei device
91 *
92 * @cl: NFC host client
93 * @cl_info: NFC info host client
94 * @init_work: perform connection to the info client
95 * @fw_ivn: NFC Intervace Version Number
96 * @vendor_id: NFC manufacturer ID
97 * @radio_type: NFC radio type
98 */
99struct mei_nfc_dev {
100 struct mei_cl *cl;
101 struct mei_cl *cl_info;
102 struct work_struct init_work;
Samuel Ortiz36eda942013-04-11 03:03:31 +0200103 wait_queue_head_t send_wq;
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200104 u8 fw_ivn;
105 u8 vendor_id;
106 u8 radio_type;
Samuel Ortiz91a6b952013-04-11 03:03:30 +0200107 char *bus_name;
Samuel Ortiz36eda942013-04-11 03:03:31 +0200108
109 u16 req_id;
110 u16 recv_req_id;
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200111};
112
113static struct mei_nfc_dev nfc_dev;
114
115/* UUIDs for NFC F/W clients */
116const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50,
117 0x94, 0xd4, 0x50, 0x26,
118 0x67, 0x23, 0x77, 0x5c);
119
120static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d,
121 0x48, 0xa4, 0xef, 0xab,
122 0xba, 0x8a, 0x12, 0x06);
123
Samuel Ortiz91a6b952013-04-11 03:03:30 +0200124/* Vendors */
125#define MEI_NFC_VENDOR_INSIDE 0x00
126#define MEI_NFC_VENDOR_NXP 0x01
127
128/* Radio types */
129#define MEI_NFC_VENDOR_INSIDE_UREAD 0x00
130#define MEI_NFC_VENDOR_NXP_PN544 0x01
131
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200132static void mei_nfc_free(struct mei_nfc_dev *ndev)
133{
134 if (ndev->cl) {
135 list_del(&ndev->cl->device_link);
136 mei_cl_unlink(ndev->cl);
137 kfree(ndev->cl);
138 }
139
140 if (ndev->cl_info) {
141 list_del(&ndev->cl_info->device_link);
142 mei_cl_unlink(ndev->cl_info);
143 kfree(ndev->cl_info);
144 }
145}
146
Samuel Ortiz91a6b952013-04-11 03:03:30 +0200147static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
148{
149 struct mei_device *dev;
150
151 if (!ndev->cl)
152 return -ENODEV;
153
154 dev = ndev->cl->dev;
155
156 switch (ndev->vendor_id) {
157 case MEI_NFC_VENDOR_INSIDE:
158 switch (ndev->radio_type) {
159 case MEI_NFC_VENDOR_INSIDE_UREAD:
160 ndev->bus_name = "microread";
161 return 0;
162
163 default:
164 dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n",
165 ndev->radio_type);
166
167 return -EINVAL;
168 }
169
170 case MEI_NFC_VENDOR_NXP:
171 switch (ndev->radio_type) {
172 case MEI_NFC_VENDOR_NXP_PN544:
173 ndev->bus_name = "pn544";
174 return 0;
175 default:
176 dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n",
177 ndev->radio_type);
178
179 return -EINVAL;
180 }
181
182 default:
183 dev_err(&dev->pdev->dev, "Unknow vendor ID 0x%x\n",
184 ndev->vendor_id);
185
186 return -EINVAL;
187 }
188
189 return 0;
190}
191
Samuel Ortiz36eda942013-04-11 03:03:31 +0200192static int mei_nfc_connect(struct mei_nfc_dev *ndev)
193{
194 struct mei_device *dev;
195 struct mei_cl *cl;
196 struct mei_nfc_cmd *cmd, *reply;
197 struct mei_nfc_connect *connect;
198 struct mei_nfc_connect_resp *connect_resp;
199 size_t connect_length, connect_resp_length;
200 int bytes_recv, ret;
201
202 cl = ndev->cl;
203 dev = cl->dev;
204
205 connect_length = sizeof(struct mei_nfc_cmd) +
206 sizeof(struct mei_nfc_connect);
207
208 connect_resp_length = sizeof(struct mei_nfc_cmd) +
209 sizeof(struct mei_nfc_connect_resp);
210
211 cmd = kzalloc(connect_length, GFP_KERNEL);
212 if (!cmd)
213 return -ENOMEM;
214 connect = (struct mei_nfc_connect *)cmd->data;
215
216 reply = kzalloc(connect_resp_length, GFP_KERNEL);
217 if (!reply) {
218 kfree(cmd);
219 return -ENOMEM;
220 }
221
222 connect_resp = (struct mei_nfc_connect_resp *)reply->data;
223
224 cmd->command = MEI_NFC_CMD_MAINTENANCE;
225 cmd->data_size = 3;
226 cmd->sub_command = MEI_NFC_SUBCMD_CONNECT;
227 connect->fw_ivn = ndev->fw_ivn;
228 connect->vendor_id = ndev->vendor_id;
229
230 ret = __mei_cl_send(cl, (u8 *)cmd, connect_length);
231 if (ret < 0) {
232 dev_err(&dev->pdev->dev, "Could not send connect cmd\n");
233 goto err;
234 }
235
236 bytes_recv = __mei_cl_recv(cl, (u8 *)reply, connect_resp_length);
237 if (bytes_recv < 0) {
238 dev_err(&dev->pdev->dev, "Could not read connect response\n");
239 ret = bytes_recv;
240 goto err;
241 }
242
243 dev_info(&dev->pdev->dev, "IVN 0x%x Vendor ID 0x%x\n",
244 connect_resp->fw_ivn, connect_resp->vendor_id);
245
246 dev_info(&dev->pdev->dev, "ME FW %d.%d.%d.%d\n",
247 connect_resp->me_major, connect_resp->me_minor,
248 connect_resp->me_hotfix, connect_resp->me_build);
249
250 ret = 0;
251
252err:
253 kfree(reply);
254 kfree(cmd);
255
256 return ret;
257}
258
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200259static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
260{
261 struct mei_device *dev;
262 struct mei_cl *cl;
263
264 struct mei_nfc_cmd cmd;
265 struct mei_nfc_reply *reply = NULL;
266 struct mei_nfc_if_version *version;
267 size_t if_version_length;
268 int bytes_recv, ret;
269
270 cl = ndev->cl_info;
271 dev = cl->dev;
272
273 memset(&cmd, 0, sizeof(struct mei_nfc_cmd));
274 cmd.command = MEI_NFC_CMD_MAINTENANCE;
275 cmd.data_size = 1;
276 cmd.sub_command = MEI_NFC_SUBCMD_IF_VERSION;
277
278 ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd));
279 if (ret < 0) {
280 dev_err(&dev->pdev->dev, "Could not send IF version cmd\n");
281 return ret;
282 }
283
284 /* to be sure on the stack we alloc memory */
285 if_version_length = sizeof(struct mei_nfc_reply) +
286 sizeof(struct mei_nfc_if_version);
287
288 reply = kzalloc(if_version_length, GFP_KERNEL);
289 if (!reply)
290 return -ENOMEM;
291
292 bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length);
293 if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
294 dev_err(&dev->pdev->dev, "Could not read IF version\n");
295 ret = -EIO;
296 goto err;
297 }
298
299 version = (struct mei_nfc_if_version *)reply->data;
300
301 ndev->fw_ivn = version->fw_ivn;
302 ndev->vendor_id = version->vendor_id;
303 ndev->radio_type = version->radio_type;
304
305err:
306 kfree(reply);
307 return ret;
308}
309
Samuel Ortiz36eda942013-04-11 03:03:31 +0200310static int mei_nfc_enable(struct mei_cl_device *cldev)
311{
312 struct mei_device *dev;
313 struct mei_nfc_dev *ndev = &nfc_dev;
314 int ret;
315
316 dev = ndev->cl->dev;
317
318 ret = mei_nfc_connect(ndev);
319 if (ret < 0) {
320 dev_err(&dev->pdev->dev, "Could not connect to NFC");
321 return ret;
322 }
323
324 return 0;
325}
326
327static int mei_nfc_disable(struct mei_cl_device *cldev)
328{
329 return 0;
330}
331
332static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
333{
334 struct mei_device *dev;
335 struct mei_nfc_dev *ndev;
336 struct mei_nfc_hci_hdr *hdr;
337 u8 *mei_buf;
338 int err;
339
340 ndev = (struct mei_nfc_dev *) cldev->priv_data;
341 dev = ndev->cl->dev;
342
343 mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL);
344 if (!mei_buf)
345 return -ENOMEM;
346
347 hdr = (struct mei_nfc_hci_hdr *) mei_buf;
348 hdr->cmd = MEI_NFC_CMD_HCI_SEND;
349 hdr->status = 0;
350 hdr->req_id = ndev->req_id;
351 hdr->reserved = 0;
352 hdr->data_size = length;
353
354 memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length);
355
356 err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE);
357 if (err < 0)
358 return err;
359
360 kfree(mei_buf);
361
362 if (!wait_event_interruptible_timeout(ndev->send_wq,
363 ndev->recv_req_id == ndev->req_id, HZ)) {
364 dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
365 err = -ETIMEDOUT;
366 } else {
367 ndev->req_id++;
368 }
369
370 return err;
371}
372
373static int mei_nfc_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
374{
375 struct mei_nfc_dev *ndev;
376 struct mei_nfc_hci_hdr *hci_hdr;
377 int received_length;
378
379 ndev = (struct mei_nfc_dev *)cldev->priv_data;
380
381 received_length = __mei_cl_recv(ndev->cl, buf, length);
382 if (received_length < 0)
383 return received_length;
384
385 hci_hdr = (struct mei_nfc_hci_hdr *) buf;
386
387 if (hci_hdr->cmd == MEI_NFC_CMD_HCI_SEND) {
388 ndev->recv_req_id = hci_hdr->req_id;
389 wake_up(&ndev->send_wq);
390
391 return 0;
392 }
393
394 return received_length;
395}
396
397static struct mei_cl_ops nfc_ops = {
398 .enable = mei_nfc_enable,
399 .disable = mei_nfc_disable,
400 .send = mei_nfc_send,
401 .recv = mei_nfc_recv,
402};
403
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200404static void mei_nfc_init(struct work_struct *work)
405{
406 struct mei_device *dev;
Samuel Ortiz91a6b952013-04-11 03:03:30 +0200407 struct mei_cl_device *cldev;
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200408 struct mei_nfc_dev *ndev;
409 struct mei_cl *cl_info;
410
411 ndev = container_of(work, struct mei_nfc_dev, init_work);
412
413 cl_info = ndev->cl_info;
414 dev = cl_info->dev;
415
416 mutex_lock(&dev->device_lock);
417
418 if (mei_cl_connect(cl_info, NULL) < 0) {
419 mutex_unlock(&dev->device_lock);
420 dev_err(&dev->pdev->dev,
421 "Could not connect to the NFC INFO ME client");
422
423 goto err;
424 }
425
426 mutex_unlock(&dev->device_lock);
427
428 if (mei_nfc_if_version(ndev) < 0) {
429 dev_err(&dev->pdev->dev, "Could not get the NFC interfave version");
430
431 goto err;
432 }
433
434 dev_info(&dev->pdev->dev,
435 "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
436 ndev->fw_ivn, ndev->vendor_id, ndev->radio_type);
437
438 mutex_lock(&dev->device_lock);
439
440 if (mei_cl_disconnect(cl_info) < 0) {
441 mutex_unlock(&dev->device_lock);
442 dev_err(&dev->pdev->dev,
443 "Could not disconnect the NFC INFO ME client");
444
445 goto err;
446 }
447
448 mutex_unlock(&dev->device_lock);
449
Samuel Ortiz91a6b952013-04-11 03:03:30 +0200450 if (mei_nfc_build_bus_name(ndev) < 0) {
451 dev_err(&dev->pdev->dev,
452 "Could not build the bus ID name\n");
453 return;
454 }
455
Samuel Ortiz36eda942013-04-11 03:03:31 +0200456 cldev = mei_cl_add_device(dev, mei_nfc_guid, ndev->bus_name, &nfc_ops);
Samuel Ortiz91a6b952013-04-11 03:03:30 +0200457 if (!cldev) {
458 dev_err(&dev->pdev->dev,
459 "Could not add the NFC device to the MEI bus\n");
460
461 goto err;
462 }
463
464 cldev->priv_data = ndev;
465
466
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200467 return;
468
469err:
470 mei_nfc_free(ndev);
471
472 return;
473}
474
475
476int mei_nfc_host_init(struct mei_device *dev)
477{
478 struct mei_nfc_dev *ndev = &nfc_dev;
479 struct mei_cl *cl_info, *cl = NULL;
480 int i, ret;
481
482 /* already initialzed */
483 if (ndev->cl_info)
484 return 0;
485
486 cl_info = mei_cl_allocate(dev);
487 cl = mei_cl_allocate(dev);
488
489 if (!cl || !cl_info) {
490 ret = -ENOMEM;
491 goto err;
492 }
493
494 /* check for valid client id */
495 i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
496 if (i < 0) {
497 dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
498 ret = -ENOENT;
499 goto err;
500 }
501
502 cl_info->me_client_id = dev->me_clients[i].client_id;
503
504 ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY);
505 if (ret)
506 goto err;
507
508 cl_info->device_uuid = mei_nfc_info_guid;
509
510 list_add_tail(&cl_info->device_link, &dev->device_list);
511
512 /* check for valid client id */
513 i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
514 if (i < 0) {
515 dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
516 ret = -ENOENT;
517 goto err;
518 }
519
520 cl->me_client_id = dev->me_clients[i].client_id;
521
522 ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
523 if (ret)
524 goto err;
525
526 cl->device_uuid = mei_nfc_guid;
527
528 list_add_tail(&cl->device_link, &dev->device_list);
529
530 ndev->cl_info = cl_info;
531 ndev->cl = cl;
Samuel Ortiz36eda942013-04-11 03:03:31 +0200532 ndev->req_id = 1;
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200533
534 INIT_WORK(&ndev->init_work, mei_nfc_init);
Samuel Ortiz36eda942013-04-11 03:03:31 +0200535 init_waitqueue_head(&ndev->send_wq);
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200536 schedule_work(&ndev->init_work);
537
538 return 0;
539
540err:
541 mei_nfc_free(ndev);
542
543 return ret;
544}
545
546void mei_nfc_host_exit(void)
547{
548 struct mei_nfc_dev *ndev = &nfc_dev;
549
Samuel Ortiz91a6b952013-04-11 03:03:30 +0200550 if (ndev->cl && ndev->cl->device)
551 mei_cl_remove_device(ndev->cl->device);
552
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200553 mei_nfc_free(ndev);
554}