NFC: pn533: Send ATR_REQ directly for active device detection

In order to improve active devices detection, we send an ATR_REQ between
each passive detection cycle. Without this algorithm, Android 4.3 based
devices running the Broadcom stack are hardly detected.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Samuel Ortiz 2013-08-21 15:06:55 +02:00
parent e29a9e2ae1
commit 673088fb42

View file

@ -387,6 +387,7 @@ struct pn533 {
struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
u8 poll_mod_count;
u8 poll_mod_curr;
u8 poll_dep;
u32 poll_protocols;
u32 listen_protocols;
struct timer_list listen_timer;
@ -1546,6 +1547,9 @@ static int pn533_start_poll_complete(struct pn533 *dev, struct sk_buff *resp)
u8 nbtg, tg, *tgdata;
int rc, tgdata_len;
/* Toggle the DEP polling */
dev->poll_dep = 1;
nbtg = resp->data[0];
tg = resp->data[1];
tgdata = &resp->data[2];
@ -1767,6 +1771,117 @@ static void pn533_wq_rf(struct work_struct *work)
return;
}
static int pn533_poll_dep_complete(struct pn533 *dev, void *arg,
struct sk_buff *resp)
{
struct pn533_cmd_jump_dep_response *rsp;
struct nfc_target nfc_target;
u8 target_gt_len;
int rc;
if (IS_ERR(resp))
return PTR_ERR(resp);
rsp = (struct pn533_cmd_jump_dep_response *)resp->data;
rc = rsp->status & PN533_CMD_RET_MASK;
if (rc != PN533_CMD_RET_SUCCESS) {
/* Not target found, turn radio off */
queue_work(dev->wq, &dev->rf_work);
dev_kfree_skb(resp);
return 0;
}
dev_dbg(&dev->interface->dev, "Creating new target");
nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK;
nfc_target.nfcid1_len = 10;
memcpy(nfc_target.nfcid1, rsp->nfcid3t, nfc_target.nfcid1_len);
rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1);
if (rc)
goto error;
dev->tgt_available_prots = 0;
dev->tgt_active_prot = NFC_PROTO_NFC_DEP;
/* ATR_RES general bytes are located at offset 17 */
target_gt_len = resp->len - 17;
rc = nfc_set_remote_general_bytes(dev->nfc_dev,
rsp->gt, target_gt_len);
if (!rc) {
rc = nfc_dep_link_is_up(dev->nfc_dev,
dev->nfc_dev->targets[0].idx,
0, NFC_RF_INITIATOR);
if (!rc)
pn533_poll_reset_mod_list(dev);
}
error:
dev_kfree_skb(resp);
return rc;
}
#define PASSIVE_DATA_LEN 5
static int pn533_poll_dep(struct nfc_dev *nfc_dev)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct sk_buff *skb;
int rc, skb_len;
u8 *next, nfcid3[NFC_NFCID3_MAXSIZE];
u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
dev_dbg(&dev->interface->dev, "%s", __func__);
if (!dev->gb) {
dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len);
if (!dev->gb || !dev->gb_len) {
dev->poll_dep = 0;
queue_work(dev->wq, &dev->rf_work);
}
}
skb_len = 3 + dev->gb_len; /* ActPass + BR + Next */
skb_len += PASSIVE_DATA_LEN;
/* NFCID3 */
skb_len += NFC_NFCID3_MAXSIZE;
nfcid3[0] = 0x1;
nfcid3[1] = 0xfe;
get_random_bytes(nfcid3 + 2, 6);
skb = pn533_alloc_skb(dev, skb_len);
if (!skb)
return -ENOMEM;
*skb_put(skb, 1) = 0x01; /* Active */
*skb_put(skb, 1) = 0x02; /* 424 kbps */
next = skb_put(skb, 1); /* Next */
*next = 0;
/* Copy passive data */
memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, PASSIVE_DATA_LEN);
*next |= 1;
/* Copy NFCID3 (which is NFCID2 from SENSF_RES) */
memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), nfcid3,
NFC_NFCID3_MAXSIZE);
*next |= 2;
memcpy(skb_put(skb, dev->gb_len), dev->gb, dev->gb_len);
*next |= 4; /* We have some Gi */
rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb,
pn533_poll_dep_complete, NULL);
if (rc < 0)
dev_kfree_skb(skb);
return rc;
}
static int pn533_poll_complete(struct pn533 *dev, void *arg,
struct sk_buff *resp)
{
@ -1853,6 +1968,11 @@ static int pn533_send_poll_frame(struct pn533 *dev)
dev_dbg(&dev->interface->dev, "%s mod len %d\n",
__func__, mod->len);
if (dev->poll_dep) {
dev->poll_dep = 0;
return pn533_poll_dep(dev->nfc_dev);
}
if (mod->len == 0) { /* Listen mode */
cmd_code = PN533_CMD_TG_INIT_AS_TARGET;
skb = pn533_alloc_poll_tg_frame(dev);
@ -2146,7 +2266,6 @@ error:
}
static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf);
#define PASSIVE_DATA_LEN 5
static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
u8 comm_mode, u8 *gb, size_t gb_len)
{