summaryrefslogtreecommitdiffstats
path: root/drivers/nfc/nfcmrvl
diff options
context:
space:
mode:
authorVincent Cuissard <cuissard@marvell.com>2015-06-11 11:25:43 +0200
committerSamuel Ortiz <sameo@linux.intel.com>2015-06-11 23:24:09 +0200
commitf1f1a7da2b3853bf55ee5aab47c8916454b65fa8 (patch)
treedc506c43af42e2ce525ebbe26f8cda7fb8659acd /drivers/nfc/nfcmrvl
parentd18ee5a5b0926f1a5f6969e9207d9c4f99533f9b (diff)
downloadop-kernel-dev-f1f1a7da2b3853bf55ee5aab47c8916454b65fa8.zip
op-kernel-dev-f1f1a7da2b3853bf55ee5aab47c8916454b65fa8.tar.gz
NFC: nfcmrvl: add support of HCI-based transport
In some configuration NCI packet can be encapsulated in HCI packets. This patch had the support of this. Signed-off-by: Vincent Cuissard <cuissard@marvell.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/nfc/nfcmrvl')
-rw-r--r--drivers/nfc/nfcmrvl/main.c35
-rw-r--r--drivers/nfc/nfcmrvl/nfcmrvl.h19
-rw-r--r--drivers/nfc/nfcmrvl/usb.c2
3 files changed, 52 insertions, 4 deletions
diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c
index acb37c0..48d8b00 100644
--- a/drivers/nfc/nfcmrvl/main.c
+++ b/drivers/nfc/nfcmrvl/main.c
@@ -63,6 +63,17 @@ static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
return -EBUSY;
+ if (priv->hci_muxed) {
+ unsigned char *hdr;
+ unsigned char len = skb->len;
+
+ hdr = (char *) skb_push(skb, NFCMRVL_HCI_EVENT_HEADER_SIZE);
+ hdr[0] = NFCMRVL_HCI_COMMAND_CODE;
+ hdr[1] = NFCMRVL_HCI_OGF;
+ hdr[2] = NFCMRVL_HCI_OCF;
+ hdr[3] = len;
+ }
+
return priv->if_ops->nci_send(priv, skb);
}
@@ -80,10 +91,12 @@ static struct nci_ops nfcmrvl_nci_ops = {
struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
struct nfcmrvl_if_ops *ops,
- struct device *dev)
+ struct device *dev,
+ unsigned int flags)
{
struct nfcmrvl_private *priv;
int rc;
+ int headroom = 0;
u32 protocols;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -93,6 +106,10 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
priv->drv_data = drv_data;
priv->if_ops = ops;
priv->dev = dev;
+ priv->hci_muxed = (flags & NFCMRVL_DEV_FLAG_HCI_MUXED) ? 1 : 0;
+
+ if (priv->hci_muxed)
+ headroom = NFCMRVL_HCI_EVENT_HEADER_SIZE;
protocols = NFC_PROTO_JEWEL_MASK
| NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
@@ -100,7 +117,8 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
| NFC_PROTO_ISO14443_B_MASK
| NFC_PROTO_NFC_DEP_MASK;
- priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols, 0, 0);
+ priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols,
+ headroom, 0);
if (!priv->ndev) {
nfc_err(dev, "nci_allocate_device failed\n");
rc = -ENOMEM;
@@ -144,6 +162,19 @@ int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count)
return -ENOMEM;
memcpy(skb_put(skb, count), data, count);
+
+ if (priv->hci_muxed) {
+ if (skb->data[0] == NFCMRVL_HCI_EVENT_CODE &&
+ skb->data[1] == NFCMRVL_HCI_NFC_EVENT_CODE) {
+ /* Data packet, let's extract NCI payload */
+ skb_pull(skb, NFCMRVL_HCI_EVENT_HEADER_SIZE);
+ } else {
+ /* Skip this packet */
+ kfree_skb(skb);
+ return 0;
+ }
+ }
+
nci_recv_frame(priv->ndev, skb);
return count;
diff --git a/drivers/nfc/nfcmrvl/nfcmrvl.h b/drivers/nfc/nfcmrvl/nfcmrvl.h
index 54c4a95..b04cddd 100644
--- a/drivers/nfc/nfcmrvl/nfcmrvl.h
+++ b/drivers/nfc/nfcmrvl/nfcmrvl.h
@@ -27,7 +27,23 @@
#define NFCMRVL_GPIO_PIN_NFC_ACTIVE 0xB
#define NFCMRVL_NCI_MAX_EVENT_SIZE 260
+/*
+** HCI defines
+*/
+
+#define NFCMRVL_HCI_EVENT_HEADER_SIZE 0x04
+#define NFCMRVL_HCI_EVENT_CODE 0x04
+#define NFCMRVL_HCI_NFC_EVENT_CODE 0xFF
+#define NFCMRVL_HCI_COMMAND_CODE 0x01
+#define NFCMRVL_HCI_OGF 0x81
+#define NFCMRVL_HCI_OCF 0xFE
+
+#define NFCMRVL_DEV_FLAG_HCI_MUXED (1 << 0)
+
struct nfcmrvl_private {
+
+ /* Tell if NCI packets are encapsulated in HCI ones */
+ int hci_muxed;
struct nci_dev *ndev;
unsigned long flags;
void *drv_data;
@@ -45,4 +61,5 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv);
int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count);
struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
struct nfcmrvl_if_ops *ops,
- struct device *dev);
+ struct device *dev,
+ unsigned int flags);
diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c
index 6cf15c1..df534b9 100644
--- a/drivers/nfc/nfcmrvl/usb.c
+++ b/drivers/nfc/nfcmrvl/usb.c
@@ -329,7 +329,7 @@ static int nfcmrvl_probe(struct usb_interface *intf,
init_usb_anchor(&drv_data->deferred);
priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops,
- &drv_data->udev->dev);
+ &drv_data->udev->dev, 0);
if (IS_ERR(priv))
return PTR_ERR(priv);
OpenPOWER on IntegriCloud