NFC: pn533: Del frame logic from Data Exchange cmd
authorWaldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
Mon, 10 Dec 2012 13:42:46 +0000 (14:42 +0100)
committerSamuel Ortiz <sameo@linux.intel.com>
Wed, 9 Jan 2013 23:51:36 +0000 (00:51 +0100)
Remove frame logic from transceive cb using new iface
for async send.

For pn533_wq_mi_recv() use pn533_send_cmd_direct_async which
sends the cmd directly to the hardware, skipping cmd queue.

Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/nfc/pn533.c

index aa7803f16773f91796d95aa13bfa3cfed69fc345..91e1594dfd1394ded59d066661692e268225f48c 100644 (file)
@@ -360,6 +360,7 @@ struct pn533 {
 
        pn533_cmd_complete_t cmd_complete;
        void *cmd_complete_arg;
+       void *cmd_complete_mi_arg;
        struct mutex cmd_lock;
        u8 cmd;
 
@@ -848,6 +849,57 @@ static int pn533_send_cmd_async(struct pn533 *dev, u8 cmd_code,
        return rc;
 }
 
+/*
+ * pn533_send_cmd_direct_async
+ *
+ * The function sends a piority cmd directly to the chip omiting the cmd
+ * queue. It's intended to be used by chaining mechanism of received responses
+ * where the host has to request every single chunk of data before scheduling
+ * next cmd from the queue.
+ */
+static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
+                                      struct sk_buff *req,
+                                      pn533_send_async_complete_t complete_cb,
+                                      void *complete_cb_context)
+{
+       struct pn533_send_async_complete_arg *arg;
+       struct sk_buff *resp;
+       int rc;
+       int resp_len = PN533_FRAME_HEADER_LEN +
+                      PN533_FRAME_MAX_PAYLOAD_LEN +
+                      PN533_FRAME_TAIL_LEN;
+
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+       resp = alloc_skb(resp_len, GFP_KERNEL);
+       if (!resp)
+               return -ENOMEM;
+
+       arg = kzalloc(sizeof(arg), GFP_KERNEL);
+       if (!arg) {
+               dev_kfree_skb(resp);
+               return -ENOMEM;
+       }
+
+       arg->complete_cb = complete_cb;
+       arg->complete_cb_context = complete_cb_context;
+       arg->resp = resp;
+       arg->req = req;
+
+       pn533_build_cmd_frame(cmd_code, req);
+
+       rc = __pn533_send_cmd_frame_async(dev, (struct pn533_frame *)req->data,
+                                         (struct pn533_frame *)resp->data,
+                                         resp_len, pn533_send_async_complete,
+                                         arg);
+       if (rc < 0) {
+               dev_kfree_skb(resp);
+               kfree(arg);
+       }
+
+       return rc;
+}
+
 static void pn533_wq_cmd(struct work_struct *work)
 {
        struct pn533 *dev = container_of(work, struct pn533, cmd_work);
@@ -2024,69 +2076,7 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
        return 0;
 }
 
-static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,
-                               bool target)
-{
-       int payload_len = skb->len;
-       struct pn533_frame *out_frame;
-       u8 tg;
-
-       nfc_dev_dbg(&dev->interface->dev, "%s - Sending %d bytes", __func__,
-                                                               payload_len);
-
-       if (payload_len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
-               /* TODO: Implement support to multi-part data exchange */
-               nfc_dev_err(&dev->interface->dev, "Data length greater than the"
-                                               " max allowed: %d",
-                                               PN533_CMD_DATAEXCH_DATA_MAXLEN);
-               return -ENOSYS;
-       }
-
-       skb_push(skb, PN533_FRAME_HEADER_LEN);
-
-       if (target == true) {
-               switch (dev->device_type) {
-               case PN533_DEVICE_PASORI:
-                       if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
-                               out_frame = (struct pn533_frame *) skb->data;
-                               pn533_tx_frame_init(out_frame,
-                                                   PN533_CMD_IN_COMM_THRU);
-
-                               break;
-                       }
-
-               default:
-                       skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
-                       out_frame = (struct pn533_frame *) skb->data;
-                       pn533_tx_frame_init(out_frame,
-                                           PN533_CMD_IN_DATA_EXCHANGE);
-                       tg = 1;
-                       memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame),
-                              &tg, sizeof(u8));
-                       out_frame->datalen += sizeof(u8);
-
-                       break;
-               }
-
-       } else {
-               skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
-               out_frame = (struct pn533_frame *) skb->data;
-               pn533_tx_frame_init(out_frame, PN533_CMD_TG_SET_DATA);
-       }
-
-
-       /* The data is already in the out_frame, just update the datalen */
-       out_frame->datalen += payload_len;
-
-       pn533_tx_frame_finish(out_frame);
-       skb_put(skb, PN533_FRAME_TAIL_LEN);
-
-       return 0;
-}
-
 struct pn533_data_exchange_arg {
-       struct sk_buff *skb_resp;
-       struct sk_buff *skb_out;
        data_exchange_cb_t cb;
        void *cb_context;
 };
@@ -2130,47 +2120,44 @@ out:
 }
 
 static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
-                                               u8 *params, int params_len)
+                                       struct sk_buff *resp)
 {
        struct pn533_data_exchange_arg *arg = _arg;
-       struct sk_buff *skb = NULL, *skb_resp = arg->skb_resp;
-       struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
-       int err = 0;
-       u8 status;
-       u8 cmd_ret;
+       struct sk_buff *skb;
+       int rc = 0;
+       u8 status, ret, mi;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       dev_kfree_skb(arg->skb_out);
-
-       if (params_len < 0) { /* error */
-               err = params_len;
-               goto error;
+       if (IS_ERR(resp)) {
+               rc = PTR_ERR(resp);
+               goto _error;
        }
 
-       status = params[0];
+       status = resp->data[0];
+       ret = status & PN533_CMD_RET_MASK;
+       mi = status & PN533_CMD_MI_MASK;
+
+       skb_pull(resp, sizeof(status));
 
-       cmd_ret = status & PN533_CMD_RET_MASK;
-       if (cmd_ret != PN533_CMD_RET_SUCCESS) {
-               nfc_dev_err(&dev->interface->dev, "PN533 reported error %d when"
-                                               " exchanging data", cmd_ret);
-               err = -EIO;
+       if (ret != PN533_CMD_RET_SUCCESS) {
+               nfc_dev_err(&dev->interface->dev,
+                           "PN533 reported error %d when exchanging data",
+                           ret);
+               rc = -EIO;
                goto error;
        }
 
-       skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
-       skb_pull(skb_resp, PN533_FRAME_HEADER_LEN);
-       skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
-       skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_LEN);
-       skb_queue_tail(&dev->resp_q, skb_resp);
+       skb_queue_tail(&dev->resp_q, resp);
 
-       if (status & PN533_CMD_MI_MASK) {
+       if (mi) {
+               dev->cmd_complete_mi_arg = arg;
                queue_work(dev->wq, &dev->mi_work);
                return -EINPROGRESS;
        }
 
        skb = pn533_build_response(dev);
-       if (skb == NULL)
+       if (!skb)
                goto error;
 
        arg->cb(arg->cb_context, skb, 0);
@@ -2178,11 +2165,12 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
        return 0;
 
 error:
+       dev_kfree_skb(resp);
+_error:
        skb_queue_purge(&dev->resp_q);
-       dev_kfree_skb(skb_resp);
-       arg->cb(arg->cb_context, NULL, err);
+       arg->cb(arg->cb_context, NULL, rc);
        kfree(arg);
-       return 0;
+       return rc;
 }
 
 static int pn533_transceive(struct nfc_dev *nfc_dev,
@@ -2190,14 +2178,20 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
                            data_exchange_cb_t cb, void *cb_context)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-       struct pn533_frame *out_frame, *in_frame;
-       struct pn533_data_exchange_arg *arg;
-       struct sk_buff *skb_resp;
-       int skb_resp_len;
+       struct pn533_data_exchange_arg *arg = NULL;
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
+       if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
+               /* TODO: Implement support to multi-part data exchange */
+               nfc_dev_err(&dev->interface->dev,
+                           "Data length greater than the max allowed: %d",
+                           PN533_CMD_DATAEXCH_DATA_MAXLEN);
+               rc = -ENOSYS;
+               goto error;
+       }
+
        if (!dev->tgt_active_prot) {
                nfc_dev_err(&dev->interface->dev, "Cannot exchange data if"
                                                " there is no active target");
@@ -2205,51 +2199,43 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
                goto error;
        }
 
-       rc = pn533_build_tx_frame(dev, skb, true);
-       if (rc)
-               goto error;
-
-       skb_resp_len = PN533_FRAME_HEADER_LEN +
-                      PN533_CMD_DATAEXCH_HEAD_LEN +
-                      PN533_CMD_DATAEXCH_DATA_MAXLEN +
-                      PN533_FRAME_TAIL_LEN;
-
-       skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
-       if (!skb_resp) {
-               rc = -ENOMEM;
-               goto error;
-       }
-
-       in_frame = (struct pn533_frame *) skb_resp->data;
-       out_frame = (struct pn533_frame *) skb->data;
-
-       arg = kmalloc(sizeof(struct pn533_data_exchange_arg), GFP_KERNEL);
+       arg = kmalloc(sizeof(*arg), GFP_KERNEL);
        if (!arg) {
                rc = -ENOMEM;
-               goto free_skb_resp;
+               goto error;
        }
 
-       arg->skb_resp = skb_resp;
-       arg->skb_out = skb;
        arg->cb = cb;
        arg->cb_context = cb_context;
 
-       rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, skb_resp_len,
-                                       pn533_data_exchange_complete, arg);
-       if (rc) {
-               nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
-                                               " perform data_exchange", rc);
-               goto free_arg;
+       switch (dev->device_type) {
+       case PN533_DEVICE_PASORI:
+               if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
+                       rc = pn533_send_data_async(dev, PN533_CMD_IN_COMM_THRU,
+                                                  skb,
+                                                  pn533_data_exchange_complete,
+                                                  arg);
+
+                       break;
+               }
+       default:
+               *skb_push(skb, sizeof(u8)) =  1; /*TG*/
+
+               rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE,
+                                          skb, pn533_data_exchange_complete,
+                                          arg);
+
+               break;
        }
 
+       if (rc < 0) /* rc from send_async */
+               goto error;
+
        return 0;
 
-free_arg:
-       kfree(arg);
-free_skb_resp:
-       kfree_skb(skb_resp);
 error:
-       kfree_skb(skb);
+       kfree(arg);
+       dev_kfree_skb(skb);
        return rc;
 }
 
@@ -2305,63 +2291,50 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
 static void pn533_wq_mi_recv(struct work_struct *work)
 {
        struct pn533 *dev = container_of(work, struct pn533, mi_work);
-       struct sk_buff *skb_cmd;
-       struct pn533_data_exchange_arg *arg = dev->cmd_complete_arg;
-       struct pn533_frame *out_frame, *in_frame;
-       struct sk_buff *skb_resp;
-       int skb_resp_len;
+
+       struct sk_buff *skb;
        int rc;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       /* This is a zero payload size skb */
-       skb_cmd = pn533_alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN);
-       if (skb_cmd == NULL)
-               goto error_cmd;
+       skb = pn533_alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN);
+       if (!skb)
+               goto error;
 
-       skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN);
+       switch (dev->device_type) {
+       case PN533_DEVICE_PASORI:
+               if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
+                       rc = pn533_send_cmd_direct_async(dev,
+                                               PN533_CMD_IN_COMM_THRU,
+                                               skb,
+                                               pn533_data_exchange_complete,
+                                                dev->cmd_complete_mi_arg);
 
-       rc = pn533_build_tx_frame(dev, skb_cmd, true);
-       if (rc)
-               goto error_frame;
+                       break;
+               }
+       default:
+               *skb_put(skb, sizeof(u8)) =  1; /*TG*/
 
-       skb_resp_len = PN533_FRAME_HEADER_LEN +
-                      PN533_CMD_DATAEXCH_HEAD_LEN +
-                      PN533_CMD_DATAEXCH_DATA_MAXLEN +
-                      PN533_FRAME_TAIL_LEN;
+               rc = pn533_send_cmd_direct_async(dev,
+                                                PN533_CMD_IN_DATA_EXCHANGE,
+                                                skb,
+                                                pn533_data_exchange_complete,
+                                                dev->cmd_complete_mi_arg);
 
-       skb_resp = alloc_skb(skb_resp_len, GFP_KERNEL);
-       if (!skb_resp) {
-               rc = -ENOMEM;
-               goto error_frame;
+               break;
        }
 
-       in_frame = (struct pn533_frame *) skb_resp->data;
-       out_frame = (struct pn533_frame *) skb_cmd->data;
-
-       arg->skb_resp = skb_resp;
-       arg->skb_out = skb_cmd;
-
-       rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
-                                         skb_resp_len,
-                                         pn533_data_exchange_complete,
-                                         dev->cmd_complete_arg);
-       if (!rc)
+       if (rc == 0) /* success */
                return;
 
-       nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
-                                               " perform data_exchange", rc);
-
-       kfree_skb(skb_resp);
+       nfc_dev_err(&dev->interface->dev,
+                   "Error %d when trying to perform data_exchange", rc);
 
-error_frame:
-       kfree_skb(skb_cmd);
+       dev_kfree_skb(skb);
+       kfree(dev->cmd_complete_arg);
 
-error_cmd:
+error:
        pn533_send_ack(dev, GFP_KERNEL);
-
-       kfree(arg);
-
        queue_work(dev->wq, &dev->cmd_work);
 }