NFC: nfcmrvl: add support of HCI-based transport
authorVincent Cuissard <cuissard@marvell.com>
Thu, 11 Jun 2015 09:25:43 +0000 (11:25 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Thu, 11 Jun 2015 21:24:09 +0000 (23:24 +0200)
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>
drivers/nfc/nfcmrvl/main.c
drivers/nfc/nfcmrvl/nfcmrvl.h
drivers/nfc/nfcmrvl/usb.c

index acb37c0..48d8b00 100644 (file)
@@ -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;
index 54c4a95..b04cddd 100644 (file)
 #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);
index 6cf15c1..df534b9 100644 (file)
@@ -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);