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>
This commit is contained in:
parent
d18ee5a5b0
commit
f1f1a7da2b
|
@ -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))
|
if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
|
||||||
return -EBUSY;
|
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);
|
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_private *nfcmrvl_nci_register_dev(void *drv_data,
|
||||||
struct nfcmrvl_if_ops *ops,
|
struct nfcmrvl_if_ops *ops,
|
||||||
struct device *dev)
|
struct device *dev,
|
||||||
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct nfcmrvl_private *priv;
|
struct nfcmrvl_private *priv;
|
||||||
int rc;
|
int rc;
|
||||||
|
int headroom = 0;
|
||||||
u32 protocols;
|
u32 protocols;
|
||||||
|
|
||||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
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->drv_data = drv_data;
|
||||||
priv->if_ops = ops;
|
priv->if_ops = ops;
|
||||||
priv->dev = dev;
|
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
|
protocols = NFC_PROTO_JEWEL_MASK
|
||||||
| NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_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_ISO14443_B_MASK
|
||||||
| NFC_PROTO_NFC_DEP_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) {
|
if (!priv->ndev) {
|
||||||
nfc_err(dev, "nci_allocate_device failed\n");
|
nfc_err(dev, "nci_allocate_device failed\n");
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
|
@ -144,6 +162,19 @@ int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
memcpy(skb_put(skb, count), data, count);
|
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);
|
nci_recv_frame(priv->ndev, skb);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
|
|
@ -27,7 +27,23 @@
|
||||||
#define NFCMRVL_GPIO_PIN_NFC_ACTIVE 0xB
|
#define NFCMRVL_GPIO_PIN_NFC_ACTIVE 0xB
|
||||||
#define NFCMRVL_NCI_MAX_EVENT_SIZE 260
|
#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 {
|
struct nfcmrvl_private {
|
||||||
|
|
||||||
|
/* Tell if NCI packets are encapsulated in HCI ones */
|
||||||
|
int hci_muxed;
|
||||||
struct nci_dev *ndev;
|
struct nci_dev *ndev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
void *drv_data;
|
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);
|
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_private *nfcmrvl_nci_register_dev(void *drv_data,
|
||||||
struct nfcmrvl_if_ops *ops,
|
struct nfcmrvl_if_ops *ops,
|
||||||
struct device *dev);
|
struct device *dev,
|
||||||
|
unsigned int flags);
|
||||||
|
|
|
@ -329,7 +329,7 @@ static int nfcmrvl_probe(struct usb_interface *intf,
|
||||||
init_usb_anchor(&drv_data->deferred);
|
init_usb_anchor(&drv_data->deferred);
|
||||||
|
|
||||||
priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops,
|
priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops,
|
||||||
&drv_data->udev->dev);
|
&drv_data->udev->dev, 0);
|
||||||
if (IS_ERR(priv))
|
if (IS_ERR(priv))
|
||||||
return PTR_ERR(priv);
|
return PTR_ERR(priv);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue