aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nfc
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2012-04-10 13:43:18 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-12 15:10:44 -0400
commit6ff73fd239ff5d6f1ebfe5b5f7f560d9fad7d749 (patch)
tree8c66777743df9ff8521c22bbe5efa73f26c65d6b /drivers/nfc
parent4849f85ee36db94033a7c8b32689458d6f435e80 (diff)
NFC: pn533 Rx chaining support
When buffers on the receiption path exceed 262 bytes, the pn533 uses a chaining mechanism where the initiator has to send NULL data frames to fetch the remaining frames. We do that from a workqueue context while holding the cmd lock. Once the MI bit is gone, we aggregate the queued received skbs. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/nfc')
-rw-r--r--drivers/nfc/pn533.c144
1 files changed, 128 insertions, 16 deletions
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index f2ee06f059f9..e6ec16d92e65 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -266,8 +266,11 @@ struct pn533 {
266 int in_maxlen; 266 int in_maxlen;
267 struct pn533_frame *in_frame; 267 struct pn533_frame *in_frame;
268 268
269 struct sk_buff_head resp_q;
270
269 struct workqueue_struct *wq; 271 struct workqueue_struct *wq;
270 struct work_struct cmd_work; 272 struct work_struct cmd_work;
273 struct work_struct mi_work;
271 struct pn533_frame *wq_in_frame; 274 struct pn533_frame *wq_in_frame;
272 int wq_in_error; 275 int wq_in_error;
273 276
@@ -1256,6 +1259,8 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx)
1256 1259
1257 dev->tgt_active_prot = 0; 1260 dev->tgt_active_prot = 0;
1258 1261
1262 skb_queue_purge(&dev->resp_q);
1263
1259 pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_RELEASE); 1264 pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_RELEASE);
1260 1265
1261 tg = 1; 1266 tg = 1;
@@ -1454,11 +1459,49 @@ struct pn533_data_exchange_arg {
1454 void *cb_context; 1459 void *cb_context;
1455}; 1460};
1456 1461
1462static struct sk_buff *pn533_build_response(struct pn533 *dev)
1463{
1464 struct sk_buff *skb, *tmp, *t;
1465 unsigned int skb_len = 0, tmp_len = 0;
1466
1467 nfc_dev_dbg(&dev->interface->dev, "%s\n", __func__);
1468
1469 if (skb_queue_empty(&dev->resp_q))
1470 return NULL;
1471
1472 if (skb_queue_len(&dev->resp_q) == 1) {
1473 skb = skb_dequeue(&dev->resp_q);
1474 goto out;
1475 }
1476
1477 skb_queue_walk_safe(&dev->resp_q, tmp, t)
1478 skb_len += tmp->len;
1479
1480 nfc_dev_dbg(&dev->interface->dev, "%s total length %d\n",
1481 __func__, skb_len);
1482
1483 skb = alloc_skb(skb_len, GFP_KERNEL);
1484 if (skb == NULL)
1485 goto out;
1486
1487 skb_put(skb, skb_len);
1488
1489 skb_queue_walk_safe(&dev->resp_q, tmp, t) {
1490 memcpy(skb->data + tmp_len, tmp->data, tmp->len);
1491 tmp_len += tmp->len;
1492 }
1493
1494out:
1495 skb_queue_purge(&dev->resp_q);
1496
1497 return skb;
1498}
1499
1457static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, 1500static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
1458 u8 *params, int params_len) 1501 u8 *params, int params_len)
1459{ 1502{
1460 struct pn533_data_exchange_arg *arg = _arg; 1503 struct pn533_data_exchange_arg *arg = _arg;
1461 struct sk_buff *skb_resp = arg->skb_resp; 1504 struct sk_buff *skb = NULL, *skb_resp = arg->skb_resp;
1462 struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data; 1505 struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
1463 int err = 0; 1506 int err = 0;
1464 u8 status; 1507 u8 status;
@@ -1466,15 +1509,13 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
1466 1509
1467 nfc_dev_dbg(&dev->interface->dev, "%s", __func__); 1510 nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
1468 1511
1469 dev_kfree_skb_irq(arg->skb_out); 1512 dev_kfree_skb(arg->skb_out);
1470 1513
1471 if (params_len < 0) { /* error */ 1514 if (params_len < 0) { /* error */
1472 err = params_len; 1515 err = params_len;
1473 goto error; 1516 goto error;
1474 } 1517 }
1475 1518
1476 skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
1477
1478 status = params[0]; 1519 status = params[0];
1479 1520
1480 cmd_ret = status & PN533_CMD_RET_MASK; 1521 cmd_ret = status & PN533_CMD_RET_MASK;
@@ -1485,25 +1526,27 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
1485 goto error; 1526 goto error;
1486 } 1527 }
1487 1528
1529 skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
1530 skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
1531 skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
1532 skb_queue_tail(&dev->resp_q, skb_resp);
1533
1488 if (status & PN533_CMD_MI_MASK) { 1534 if (status & PN533_CMD_MI_MASK) {
1489 /* TODO: Implement support to multi-part data exchange */ 1535 queue_work(dev->wq, &dev->mi_work);
1490 nfc_dev_err(&dev->interface->dev, "Multi-part message not yet" 1536 return -EINPROGRESS;
1491 " supported");
1492 /* Prevent the other messages from controller */
1493 pn533_send_ack(dev, GFP_ATOMIC);
1494 err = -ENOSYS;
1495 goto error;
1496 } 1537 }
1497 1538
1498 skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN); 1539 skb = pn533_build_response(dev);
1499 skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE); 1540 if (skb == NULL)
1541 goto error;
1500 1542
1501 arg->cb(arg->cb_context, skb_resp, 0); 1543 arg->cb(arg->cb_context, skb, 0);
1502 kfree(arg); 1544 kfree(arg);
1503 return 0; 1545 return 0;
1504 1546
1505error: 1547error:
1506 dev_kfree_skb_irq(skb_resp); 1548 skb_queue_purge(&dev->resp_q);
1549 dev_kfree_skb(skb_resp);
1507 arg->cb(arg->cb_context, NULL, err); 1550 arg->cb(arg->cb_context, NULL, err);
1508 kfree(arg); 1551 kfree(arg);
1509 return 0; 1552 return 0;
@@ -1578,6 +1621,68 @@ error:
1578 return rc; 1621 return rc;
1579} 1622}
1580 1623
1624static void pn533_wq_mi_recv(struct work_struct *work)
1625{
1626 struct pn533 *dev = container_of(work, struct pn533, mi_work);
1627 struct sk_buff *skb_cmd;
1628 struct pn533_data_exchange_arg *arg = dev->cmd_complete_arg;
1629 struct pn533_frame *out_frame, *in_frame;
1630 struct sk_buff *skb_resp;
1631 int skb_resp_len;
1632 int rc;
1633
1634 nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
1635
1636 /* This is a zero payload size skb */
1637 skb_cmd = alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN + PN533_FRAME_TAIL_SIZE,
1638 GFP_KERNEL);
1639 if (skb_cmd == NULL)
1640 goto error_cmd;
1641
1642 skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN);
1643
1644 rc = pn533_data_exchange_tx_frame(dev, skb_cmd);
1645 if (rc)
1646 goto error_frame;
1647
1648 skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
1649 PN533_CMD_DATAEXCH_DATA_MAXLEN +
1650 PN533_FRAME_TAIL_SIZE;
1651 skb_resp = alloc_skb(skb_resp_len, GFP_KERNEL);
1652 if (!skb_resp) {
1653 rc = -ENOMEM;
1654 goto error_frame;
1655 }
1656
1657 in_frame = (struct pn533_frame *) skb_resp->data;
1658 out_frame = (struct pn533_frame *) skb_cmd->data;
1659
1660 arg->skb_resp = skb_resp;
1661 arg->skb_out = skb_cmd;
1662
1663 rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
1664 skb_resp_len,
1665 pn533_data_exchange_complete,
1666 dev->cmd_complete_arg, GFP_KERNEL);
1667 if (!rc)
1668 return;
1669
1670 nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
1671 " perform data_exchange", rc);
1672
1673 kfree_skb(skb_resp);
1674
1675error_frame:
1676 kfree_skb(skb_cmd);
1677
1678error_cmd:
1679 pn533_send_ack(dev, GFP_KERNEL);
1680
1681 kfree(arg);
1682
1683 up(&dev->cmd_lock);
1684}
1685
1581static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, 1686static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
1582 u8 cfgdata_len) 1687 u8 cfgdata_len)
1583{ 1688{
@@ -1676,10 +1781,15 @@ static int pn533_probe(struct usb_interface *interface,
1676 pn533_send_complete, dev); 1781 pn533_send_complete, dev);
1677 1782
1678 INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete); 1783 INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete);
1679 dev->wq = create_singlethread_workqueue("pn533"); 1784 INIT_WORK(&dev->mi_work, pn533_wq_mi_recv);
1785 dev->wq = alloc_workqueue("pn533",
1786 WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
1787 1);
1680 if (dev->wq == NULL) 1788 if (dev->wq == NULL)
1681 goto error; 1789 goto error;
1682 1790
1791 skb_queue_head_init(&dev->resp_q);
1792
1683 usb_set_intfdata(interface, dev); 1793 usb_set_intfdata(interface, dev);
1684 1794
1685 pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION); 1795 pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION);
@@ -1756,6 +1866,8 @@ static void pn533_disconnect(struct usb_interface *interface)
1756 1866
1757 destroy_workqueue(dev->wq); 1867 destroy_workqueue(dev->wq);
1758 1868
1869 skb_queue_purge(&dev->resp_q);
1870
1759 kfree(dev->in_frame); 1871 kfree(dev->in_frame);
1760 usb_free_urb(dev->in_urb); 1872 usb_free_urb(dev->in_urb);
1761 kfree(dev->out_frame); 1873 kfree(dev->out_frame);