aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/mei/nfc.c170
1 files changed, 169 insertions, 1 deletions
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 33354d94c0c2..3adf8a70f26e 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -15,6 +15,7 @@
15 */ 15 */
16 16
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/sched.h>
18#include <linux/module.h> 19#include <linux/module.h>
19#include <linux/moduleparam.h> 20#include <linux/moduleparam.h>
20#include <linux/device.h> 21#include <linux/device.h>
@@ -99,10 +100,14 @@ struct mei_nfc_dev {
99 struct mei_cl *cl; 100 struct mei_cl *cl;
100 struct mei_cl *cl_info; 101 struct mei_cl *cl_info;
101 struct work_struct init_work; 102 struct work_struct init_work;
103 wait_queue_head_t send_wq;
102 u8 fw_ivn; 104 u8 fw_ivn;
103 u8 vendor_id; 105 u8 vendor_id;
104 u8 radio_type; 106 u8 radio_type;
105 char *bus_name; 107 char *bus_name;
108
109 u16 req_id;
110 u16 recv_req_id;
106}; 111};
107 112
108static struct mei_nfc_dev nfc_dev; 113static struct mei_nfc_dev nfc_dev;
@@ -184,6 +189,73 @@ static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
184 return 0; 189 return 0;
185} 190}
186 191
192static 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
187static int mei_nfc_if_version(struct mei_nfc_dev *ndev) 259static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
188{ 260{
189 struct mei_device *dev; 261 struct mei_device *dev;
@@ -235,6 +307,100 @@ err:
235 return ret; 307 return ret;
236} 308}
237 309
310static 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
238static void mei_nfc_init(struct work_struct *work) 404static void mei_nfc_init(struct work_struct *work)
239{ 405{
240 struct mei_device *dev; 406 struct mei_device *dev;
@@ -287,7 +453,7 @@ static void mei_nfc_init(struct work_struct *work)
287 return; 453 return;
288 } 454 }
289 455
290 cldev = mei_cl_add_device(dev, mei_nfc_guid, ndev->bus_name, NULL); 456 cldev = mei_cl_add_device(dev, mei_nfc_guid, ndev->bus_name, &nfc_ops);
291 if (!cldev) { 457 if (!cldev) {
292 dev_err(&dev->pdev->dev, 458 dev_err(&dev->pdev->dev,
293 "Could not add the NFC device to the MEI bus\n"); 459 "Could not add the NFC device to the MEI bus\n");
@@ -363,8 +529,10 @@ int mei_nfc_host_init(struct mei_device *dev)
363 529
364 ndev->cl_info = cl_info; 530 ndev->cl_info = cl_info;
365 ndev->cl = cl; 531 ndev->cl = cl;
532 ndev->req_id = 1;
366 533
367 INIT_WORK(&ndev->init_work, mei_nfc_init); 534 INIT_WORK(&ndev->init_work, mei_nfc_init);
535 init_waitqueue_head(&ndev->send_wq);
368 schedule_work(&ndev->init_work); 536 schedule_work(&ndev->init_work);
369 537
370 return 0; 538 return 0;