#define PN533_CMD_TG_INIT_AS_TARGET 0x8c
#define PN533_CMD_TG_GET_DATA 0x86
#define PN533_CMD_TG_SET_DATA 0x8e
+#define PN533_CMD_TG_SET_META_DATA 0x94
#define PN533_CMD_UNDEF 0xff
#define PN533_CMD_RESPONSE(cmd) (cmd + 1)
struct delayed_work poll_work;
struct work_struct mi_rx_work;
struct work_struct mi_tx_work;
+ struct work_struct mi_tm_rx_work;
+ struct work_struct mi_tm_tx_work;
struct work_struct tg_work;
struct work_struct rf_work;
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;
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];
#define PN533_CMD_DATAEXCH_HEAD_LEN 1
#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
+static void pn533_wq_tm_mi_recv(struct work_struct *work);
+static struct sk_buff *pn533_build_response(struct pn533 *dev);
+
static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg,
struct sk_buff *resp)
{
- u8 status;
+ struct sk_buff *skb;
+ u8 status, ret, mi;
+ int rc;
dev_dbg(&dev->interface->dev, "%s\n", __func__);
- if (IS_ERR(resp))
+ if (IS_ERR(resp)) {
+ skb_queue_purge(&dev->resp_q);
return PTR_ERR(resp);
+ }
status = resp->data[0];
+
+ ret = status & PN533_CMD_RET_MASK;
+ mi = status & PN533_CMD_MI_MASK;
+
skb_pull(resp, sizeof(status));
- if (status != 0) {
- nfc_tm_deactivated(dev->nfc_dev);
- dev->tgt_mode = 0;
- dev_kfree_skb(resp);
- return 0;
+ if (ret != PN533_CMD_RET_SUCCESS) {
+ rc = -EIO;
+ goto error;
+ }
+
+ skb_queue_tail(&dev->resp_q, resp);
+
+ if (mi) {
+ queue_work(dev->wq, &dev->mi_tm_rx_work);
+ return -EINPROGRESS;
}
- return nfc_tm_data_received(dev->nfc_dev, resp);
+ skb = pn533_build_response(dev);
+ if (!skb) {
+ rc = -EIO;
+ goto error;
+ }
+
+ return nfc_tm_data_received(dev->nfc_dev, skb);
+
+error:
+ nfc_tm_deactivated(dev->nfc_dev);
+ dev->tgt_mode = 0;
+ skb_queue_purge(&dev->resp_q);
+ dev_kfree_skb(resp);
+
+ return rc;
+}
+
+static void pn533_wq_tm_mi_recv(struct work_struct *work)
+{
+ struct pn533 *dev = container_of(work, struct pn533, mi_tm_rx_work);
+ struct sk_buff *skb;
+ int rc;
+
+ dev_dbg(&dev->interface->dev, "%s\n", __func__);
+
+ skb = pn533_alloc_skb(dev, 0);
+ if (!skb)
+ return;
+
+ rc = pn533_send_cmd_direct_async(dev,
+ PN533_CMD_TG_GET_DATA,
+ skb,
+ pn533_tm_get_data_complete,
+ NULL);
+
+ if (rc < 0)
+ dev_kfree_skb(skb);
+
+ return;
+}
+
+static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
+ struct sk_buff *resp);
+static void pn533_wq_tm_mi_send(struct work_struct *work)
+{
+ struct pn533 *dev = container_of(work, struct pn533, mi_tm_tx_work);
+ struct sk_buff *skb;
+ int rc;
+
+ dev_dbg(&dev->interface->dev, "%s\n", __func__);
+
+ /* Grab the first skb in the queue */
+ skb = skb_dequeue(&dev->fragment_skb);
+ if (skb == NULL) { /* No more data */
+ /* Reset the queue for future use */
+ skb_queue_head_init(&dev->fragment_skb);
+ goto error;
+ }
+
+ /* last entry - remove MI bit */
+ if (skb_queue_len(&dev->fragment_skb) == 0) {
+ rc = pn533_send_cmd_direct_async(dev, PN533_CMD_TG_SET_DATA,
+ skb, pn533_tm_send_complete, NULL);
+ } else
+ rc = pn533_send_cmd_direct_async(dev,
+ PN533_CMD_TG_SET_META_DATA,
+ skb, pn533_tm_send_complete, NULL);
+
+ if (rc == 0) /* success */
+ return;
+
+ dev_err(&dev->interface->dev,
+ "Error %d when trying to perform set meta data_exchange", rc);
+
+ dev_kfree_skb(skb);
+
+error:
+ pn533_send_ack(dev, GFP_KERNEL);
+ queue_work(dev->wq, &dev->cmd_work);
}
static void pn533_wq_tg_get_data(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)
{
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);
u32 im_protocols, u32 tm_protocols)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+ struct pn533_poll_modulations *cur_mod;
u8 rand_mod;
+ int rc;
dev_dbg(&dev->interface->dev,
"%s: im protocols 0x%x tm protocols 0x%x\n",
rand_mod %= dev->poll_mod_count;
dev->poll_mod_curr = rand_mod;
- return pn533_send_poll_frame(dev);
+ cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+ rc = pn533_send_poll_frame(dev);
+
+ /* Start listen timer */
+ if (!rc && cur_mod->len == 0 && dev->poll_mod_count > 1)
+ mod_timer(&dev->listen_timer, jiffies + PN533_LISTEN_TIME * HZ);
+
+ return rc;
}
static void pn533_stop_poll(struct nfc_dev *nfc_dev)
}
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)
{
break;
}
- /* Reserve the TG/MI byte */
- skb_reserve(frag, 1);
+ if (!dev->tgt_mode) {
+ /* Reserve the TG/MI byte */
+ skb_reserve(frag, 1);
- /* MI + TG */
- if (frag_size == PN533_CMD_DATAFRAME_MAXLEN)
- *skb_push(frag, sizeof(u8)) = (PN533_CMD_MI_MASK | 1);
- else
- *skb_push(frag, sizeof(u8)) = 1; /* TG */
+ /* MI + TG */
+ if (frag_size == PN533_CMD_DATAFRAME_MAXLEN)
+ *skb_push(frag, sizeof(u8)) =
+ (PN533_CMD_MI_MASK | 1);
+ else
+ *skb_push(frag, sizeof(u8)) = 1; /* TG */
+ }
memcpy(skb_put(frag, frag_size), skb->data, frag_size);
status = resp->data[0];
+ /* Prepare for the next round */
+ if (skb_queue_len(&dev->fragment_skb) > 0) {
+ queue_work(dev->wq, &dev->mi_tm_tx_work);
+ return -EINPROGRESS;
+ }
dev_kfree_skb(resp);
if (status != 0) {
dev_dbg(&dev->interface->dev, "%s\n", __func__);
+ /* let's split in multiple chunks if size's too big */
if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
- nfc_err(&dev->interface->dev,
- "Data length greater than the max allowed: %d\n",
- PN533_CMD_DATAEXCH_DATA_MAXLEN);
- return -ENOSYS;
+ rc = pn533_fill_fragment_skbs(dev, skb);
+ if (rc <= 0)
+ goto error;
+
+ /* get the first skb */
+ skb = skb_dequeue(&dev->fragment_skb);
+ if (!skb) {
+ rc = -EIO;
+ goto error;
+ }
+
+ rc = pn533_send_data_async(dev, PN533_CMD_TG_SET_META_DATA, skb,
+ pn533_tm_send_complete, NULL);
+ } else {
+ /* Send th skb */
+ rc = pn533_send_data_async(dev, PN533_CMD_TG_SET_DATA, skb,
+ pn533_tm_send_complete, NULL);
}
- rc = pn533_send_data_async(dev, PN533_CMD_TG_SET_DATA, skb,
- pn533_tm_send_complete, NULL);
- if (rc < 0)
+error:
+ if (rc < 0) {
dev_kfree_skb(skb);
+ skb_queue_purge(&dev->fragment_skb);
+ }
return rc;
}
return rc;
}
-int pn533_dev_up(struct nfc_dev *nfc_dev)
+static int pn533_dev_up(struct nfc_dev *nfc_dev)
{
return pn533_rf_field(nfc_dev, 1);
}
-int pn533_dev_down(struct nfc_dev *nfc_dev)
+static int pn533_dev_down(struct nfc_dev *nfc_dev)
{
return pn533_rf_field(nfc_dev, 0);
}
INIT_WORK(&dev->mi_rx_work, pn533_wq_mi_recv);
INIT_WORK(&dev->mi_tx_work, pn533_wq_mi_send);
INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data);
+ INIT_WORK(&dev->mi_tm_rx_work, pn533_wq_tm_mi_recv);
+ INIT_WORK(&dev->mi_tm_tx_work, pn533_wq_tm_mi_send);
INIT_DELAYED_WORK(&dev->poll_work, pn533_wq_poll);
INIT_WORK(&dev->rf_work, pn533_wq_rf);
dev->wq = alloc_ordered_workqueue("pn533", 0);