[PATCH 2/3] nfc: st-nci: add raw NCI path for ST21NFCD
Kristian Brox <[email protected]>
| Newsgroups | dev.linux.lists.oe-linux-nfc,org.kernel.vger.linux-arm-msm |
|---|---|
| Message-ID | <[email protected]> |
ST21NFCD does not use NDLC. When the compatible is st,st21nfcd-i2c, talk raw NCI: - do not add or strip an NDLC PCB - do not run the T1/T2 ACK timers - I2C reads are a 3-byte NCI header plus payload - skip proprietary SET_NFC_MODE and HCI SE discovery st,st21nfcb-i2c and st,st21nfcc-i2c are unchanged. Tested on Fairphone 5: adapter powers up and reads an NTAG 215. Signed-off-by: Kristian Brox <[email protected]> --- diff --git a/drivers/nfc/st-nci/core.c b/drivers/nfc/st-nci/core.c index a367136d4..2356f16b8 100644 --- a/drivers/nfc/st-nci/core.c +++ b/drivers/nfc/st-nci/core.c @@ -18,8 +18,13 @@ static int st_nci_init(struct nci_dev *ndev) { + struct st_nci_info *info = nci_get_drvdata(ndev); struct nci_mode_set_cmd cmd; + /* ST21NFCD has no NDLC proprietary SET_NFC_MODE */ + if (info->ndlc->raw_nci) + return 0; + cmd.cmd_type = ST_NCI_SET_NFC_MODE; cmd.mode = 1; diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index 416770adb..456238b58 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -14,6 +14,7 @@ #include <linux/delay.h> #include <linux/nfc.h> #include <linux/of.h> +#include <linux/property.h> #include "st-nci.h" @@ -22,10 +23,17 @@ /* ndlc header */ #define ST_NCI_FRAME_HEADROOM 1 #define ST_NCI_FRAME_TAILROOM 0 +#define ST_NCI_RAW_FRAME_HEADROOM 0 #define ST_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */ +#define ST_NCI_NCI_HDR_SIZE 3 /* raw NCI: MT/PBF/GID + OID + len */ #define ST_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */ +enum st_nci_i2c_proto { + ST_NCI_I2C_PROTO_NDLC = 0, + ST_NCI_I2C_PROTO_RAW_NCI, +}; + #define ST_NCI_DRIVER_NAME "st_nci" #define ST_NCI_I2C_DRIVER_NAME "st_nci_i2c" @@ -34,6 +42,7 @@ struct st_nci_i2c_phy { struct llt_ndlc *ndlc; bool irq_active; + bool raw_nci; struct gpio_desc *gpiod_reset; @@ -111,6 +120,42 @@ static int st_nci_i2c_read(struct st_nci_i2c_phy *p hy, u8 buf[ST_NCI_I2C_MAX_SIZE]; struct i2c_client *client = phy->i2c_dev; + if (phy->raw_nci) { + r = i2c_master_recv(client, buf, ST_NCI_NCI_HDR_SIZE); + if (r < 0) { + usleep_range(1000, 4000); + r = i2c_master_recv(client, buf, ST_NCI_NCI_HDR_SIZE); + } + if (r != ST_NCI_NCI_HDR_SIZE) + return -EREMOTEIO; + + len = buf[2]; + if (len > ST_NCI_I2C_MAX_SIZE) { + nfc_err(&client->dev, "invalid frame len\n"); + return -EBADMSG; + } + + *skb = alloc_skb(ST_NCI_NCI_HDR_SIZE + len, GFP_KERNEL); + if (!*skb) + return -ENOMEM; + + skb_put(*skb, ST_NCI_NCI_HDR_SIZE); + memcpy((*skb)->data, buf, ST_NCI_NCI_HDR_SIZE); + + if (!len) + return 0; + + r = i2c_master_recv(client, buf, len); + if (r != len) { + kfree_skb(*skb); + return -EREMOTEIO; + } + + skb_put(*skb, len); + memcpy((*skb)->data + ST_NCI_NCI_HDR_SIZE, buf, len); + return 0; + } + r = i2c_master_recv(client, buf, ST_NCI_I2C_MIN_SIZE); if (r < 0) { /* Retry, chip was in standby */ usleep_range(1000, 4000); @@ -211,6 +256,8 @@ static int st_nci_i2c_probe(struct i2c_client *client) return -ENOMEM; phy->i2c_dev = client; + phy->raw_nci = (uintptr_t)device_get_match_data(dev) == + ST_NCI_I2C_PROTO_RAW_NCI; i2c_set_clientdata(client, phy); @@ -231,13 +278,17 @@ static int st_nci_i2c_probe(struct i2c_client *client) device_property_read_bool(dev, "uicc-present"); r = ndlc_probe(phy, &i2c_phy_ops, &client->dev, - ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM, + phy->raw_nci ? ST_NCI_RAW_FRAME_HEADROOM : + ST_NCI_FRAME_HEADROOM, + ST_NCI_FRAME_TAILROOM, &phy->ndlc, &phy->se_status); if (r < 0) { nfc_err(&client->dev, "Unable to register ndlc layer\n"); return r; } + phy->ndlc->raw_nci = phy->raw_nci; + phy->irq_active = true; r = devm_request_threaded_irq(&client->dev, client->irq, NULL, st_nci_irq_thread_fn, @@ -273,6 +324,8 @@ static cons t struct of_device_id of_st_nci_i2c_match[] __maybe_unused = { { .compatible = "st,st21nfcb-i2c", }, { .compatible = "st,st21nfcb_i2c", }, { .compatible = "st,st21nfcc-i2c", }, + { .compatible = "st,st21nfcd-i2c", + .data = (void *)ST_NCI_I2C_PROTO_RAW_NCI }, {} }; MODULE_DEVICE_TABLE(of, of_st_nci_i2c_match); diff --git a/drivers/nfc/st-nci/ndlc.c b/drivers/nfc/st-nci/ndlc.c index be4808859..b3192460c 100644 --- a/drivers/nfc/st-nci/ndlc.c +++ b/drivers/nfc/st-nci/ndlc.c @@ -62,8 +62,9 @@ void ndlc_close(struct llt_ndlc *ndlc) /* toggle reset pin */ ndlc->ops->enable(ndlc->phy_id); - nci_prop_cmd(ndlc->ndev, ST_NCI_CORE_PROP, - sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd); + if (!ndlc->raw_nci) + nci_prop_cmd(ndlc->ndev, ST_NCI_CORE_PROP, + sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd); ndlc->powered = 0; ndlc->ops->disable(ndlc->phy_id); @@ -72,11 +73,13 @@ EXPORT_SYMBOL(ndlc_close); int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb) { - /* add ndlc header */ - u8 pcb = PCB_TYPE_DATAFRAME | PCB_DATAFRAME_RETRANSMIT_NO | - PCB_FRAME_CRC_INFO_NOTPRESENT; + if (!ndlc->raw_nci) { + /* add ndlc header */ + u8 pcb = PCB_TYPE_DATAFRAME | PCB_DATAFRAME_RETRANSMIT_NO | + PCB_FRAME_CRC_INFO_NOTPRESENT; - *(u8 *)skb_push(skb, 1) = pcb; + *(u8 *)skb_push(skb, 1) = pcb; + } skb_queue_tail(&ndlc->send_q, skb); schedule_work(&ndlc->sm_work); @@ -103,6 +106,10 @@ static void llt_ndlc_send_queue(struct llt_ndlc *ndlc) ndlc->hard_fault = r; break; } + if (ndlc->raw_nci) { + kfree_skb(skb); + continue; + } time_sent = jiffies; *(unsigned long *)skb->cb = time_sent; @@ -154,6 +161,10 @@ static void llt_ndlc_rcv_queue(struct llt_ndlc *ndlc) pr_debug("rcvQlen=%d\n", ndlc->rcv_q.qlen); while ((skb = skb_dequeue(&ndlc->rcv_q)) != NULL) { + if (ndlc->raw_nci) { + nci_recv_frame(ndlc->ndev, skb); + continue; + } pcb = skb-> data[0]; skb_pull(skb, 1); if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_SUPERVISOR) { diff --git a/drivers/nfc/st-nci/ndlc.h b/drivers/nfc/st-nci/ndlc.h index c24ce9b0d..5c1f8baf0 100644 --- a/drivers/nfc/st-nci/ndlc.h +++ b/drivers/nfc/st-nci/ndlc.h @@ -39,6 +39,8 @@ struct llt_ndlc { */ int hard_fault; int powered; + /* ST21NFCD: raw NCI on the wire, no NDLC PCB / ACK timers */ + bool raw_nci; }; int ndlc_open(struct llt_ndlc *ndlc); diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c index 607ec768e..44cc102bc 100644 --- a/drivers/nfc/st-nci/se.c +++ b/drivers/nfc/st-nci/se.c @@ -621,6 +621,9 @@ int st_nci_discover_se(struct nci_dev *ndev) int se_count = 0; struct st_nci_info *info = nci_get_drvdata(ndev); + if (info->ndlc->raw_nci) + return 0; + r = st_nci_hci_network_init(ndev); if (r != 0) return r;
publickey - [email protected] - 0x99222460.asc
(application/pgp-keys, 905 B)
-----BEGIN PGP PUBLIC KEY BLOCK----- Comment: https://gopenpgp.org Version: GopenPGP 2.10.0 xjMEajGU4RYJKwYBBAHaRw8BAQdARdhTl87MRrY6Rl8/EyHQvbcUkjYpDrjmrfAG 175yv4vNNWlzeW91cmJyYWluZm9zc0Bwcm90b24ubWUgPGlzeW91cmJyYWluZm9z c0Bwcm90b24ubWU+wsARBBMWCgCDBYJqMZThAwsJBwkQqQe6CH3jwqhFFAAAAAAA HAAgc2FsdEBub3RhdGlvbnMub3BlbnBncGpzLm9yZ6m90fcNgd4qZz5agWNNNj+o rN9+8w6MEQgBx0IjGCOqAxUKCAQWAAIBAhkBApsDAh4BFiEEmSIkYNMj9vElRKBr qQe6CH3jwqgAABpuAQCbRh1ouQ1EaBiGXkXyXRn6dY3ZV53uy+XtQXhm9kiHRAD9 FLQ9kstbrVlwXikRIy9ZH5D4GUWKoverHvZVo7yDZg3OOARqMZThEgorBgEEAZdV AQUBAQdAGGd8U2rrjWq1PZbhlAAOPMJjrDy5dJ7Lnt7dq5CmUQgDAQgHwr4EGBYK AHAFgmoxlOEJEKkHugh948KoRRQAAAAAABwAIHNhbHRAbm90YXRpb25zLm9wZW5w Z3Bqcy5vcmcUo1P4XSdLr4JsFTAi8SqECHDCkkau0mNkaJNZiacSjwKbDBYhBJki JGDTI/bxJUSga6kHugh948KoAAD+fwD+IKq+jmAJg+XneWOOX4p8y1W+GX7qSC1B q8iAXQbikeMBAKtw4i+OgeGMc29LGJsHzYWmRaEOgKBo8G+RIa+FTkoF =knak -----END PGP PUBLIC KEY BLOCK-----
signature.asc
(application/pgp-signature, 322 B)
-----BEGIN PGP SIGNATURE----- Version: ProtonMail wqsEARYIAF0FgmqEx84JEKkHugh948KoNRQAAAAAABwAEHNhbHRAbm90YXRp b25zLm9wZW5wZ3Bqcy5vcmfXhhb/YRGTK6+mXr1fij4RFiEEmSIkYNMj9vEl RKBrqQe6CH3jwqgAAEqRAQDJIKuX1mrbXDOqumz1Z0FFeE6ZgExwwVv1WGn3 b7vrlgD8Cve0RBao0uFHdzzm72atUhj9f31CxErgOydUX8BD1gs= =z2G3 -----END PGP SIGNATURE-----