NFC: pn533: Del frame logic from Data Exchange cmd
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>
This commit is contained in:
parent
13003649b1
commit
b1e666f503
|
@ -360,6 +360,7 @@ struct pn533 {
|
||||||
|
|
||||||
pn533_cmd_complete_t cmd_complete;
|
pn533_cmd_complete_t cmd_complete;
|
||||||
void *cmd_complete_arg;
|
void *cmd_complete_arg;
|
||||||
|
void *cmd_complete_mi_arg;
|
||||||
struct mutex cmd_lock;
|
struct mutex cmd_lock;
|
||||||
u8 cmd;
|
u8 cmd;
|
||||||
|
|
||||||
|
@ -848,6 +849,57 @@ static int pn533_send_cmd_async(struct pn533 *dev, u8 cmd_code,
|
||||||
return rc;
|
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)
|
static void pn533_wq_cmd(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct pn533 *dev = container_of(work, struct pn533, cmd_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;
|
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 pn533_data_exchange_arg {
|
||||||
struct sk_buff *skb_resp;
|
|
||||||
struct sk_buff *skb_out;
|
|
||||||
data_exchange_cb_t cb;
|
data_exchange_cb_t cb;
|
||||||
void *cb_context;
|
void *cb_context;
|
||||||
};
|
};
|
||||||
|
@ -2130,47 +2120,44 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
|
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 pn533_data_exchange_arg *arg = _arg;
|
||||||
struct sk_buff *skb = NULL, *skb_resp = arg->skb_resp;
|
struct sk_buff *skb;
|
||||||
struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
|
int rc = 0;
|
||||||
int err = 0;
|
u8 status, ret, mi;
|
||||||
u8 status;
|
|
||||||
u8 cmd_ret;
|
|
||||||
|
|
||||||
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
|
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
|
||||||
|
|
||||||
dev_kfree_skb(arg->skb_out);
|
if (IS_ERR(resp)) {
|
||||||
|
rc = PTR_ERR(resp);
|
||||||
|
goto _error;
|
||||||
|
}
|
||||||
|
|
||||||
if (params_len < 0) { /* error */
|
status = resp->data[0];
|
||||||
err = params_len;
|
ret = status & PN533_CMD_RET_MASK;
|
||||||
|
mi = status & PN533_CMD_MI_MASK;
|
||||||
|
|
||||||
|
skb_pull(resp, sizeof(status));
|
||||||
|
|
||||||
|
if (ret != PN533_CMD_RET_SUCCESS) {
|
||||||
|
nfc_dev_err(&dev->interface->dev,
|
||||||
|
"PN533 reported error %d when exchanging data",
|
||||||
|
ret);
|
||||||
|
rc = -EIO;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = params[0];
|
skb_queue_tail(&dev->resp_q, resp);
|
||||||
|
|
||||||
cmd_ret = status & PN533_CMD_RET_MASK;
|
if (mi) {
|
||||||
if (cmd_ret != PN533_CMD_RET_SUCCESS) {
|
dev->cmd_complete_mi_arg = arg;
|
||||||
nfc_dev_err(&dev->interface->dev, "PN533 reported error %d when"
|
|
||||||
" exchanging data", cmd_ret);
|
|
||||||
err = -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);
|
|
||||||
|
|
||||||
if (status & PN533_CMD_MI_MASK) {
|
|
||||||
queue_work(dev->wq, &dev->mi_work);
|
queue_work(dev->wq, &dev->mi_work);
|
||||||
return -EINPROGRESS;
|
return -EINPROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
skb = pn533_build_response(dev);
|
skb = pn533_build_response(dev);
|
||||||
if (skb == NULL)
|
if (!skb)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
arg->cb(arg->cb_context, skb, 0);
|
arg->cb(arg->cb_context, skb, 0);
|
||||||
|
@ -2178,11 +2165,12 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
dev_kfree_skb(resp);
|
||||||
|
_error:
|
||||||
skb_queue_purge(&dev->resp_q);
|
skb_queue_purge(&dev->resp_q);
|
||||||
dev_kfree_skb(skb_resp);
|
arg->cb(arg->cb_context, NULL, rc);
|
||||||
arg->cb(arg->cb_context, NULL, err);
|
|
||||||
kfree(arg);
|
kfree(arg);
|
||||||
return 0;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pn533_transceive(struct nfc_dev *nfc_dev,
|
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)
|
data_exchange_cb_t cb, void *cb_context)
|
||||||
{
|
{
|
||||||
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
|
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
|
||||||
struct pn533_frame *out_frame, *in_frame;
|
struct pn533_data_exchange_arg *arg = NULL;
|
||||||
struct pn533_data_exchange_arg *arg;
|
|
||||||
struct sk_buff *skb_resp;
|
|
||||||
int skb_resp_len;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
|
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) {
|
if (!dev->tgt_active_prot) {
|
||||||
nfc_dev_err(&dev->interface->dev, "Cannot exchange data if"
|
nfc_dev_err(&dev->interface->dev, "Cannot exchange data if"
|
||||||
" there is no active target");
|
" there is no active target");
|
||||||
|
@ -2205,51 +2199,43 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = pn533_build_tx_frame(dev, skb, true);
|
arg = kmalloc(sizeof(*arg), GFP_KERNEL);
|
||||||
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);
|
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto free_skb_resp;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg->skb_resp = skb_resp;
|
|
||||||
arg->skb_out = skb;
|
|
||||||
arg->cb = cb;
|
arg->cb = cb;
|
||||||
arg->cb_context = cb_context;
|
arg->cb_context = cb_context;
|
||||||
|
|
||||||
rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, skb_resp_len,
|
switch (dev->device_type) {
|
||||||
pn533_data_exchange_complete, arg);
|
case PN533_DEVICE_PASORI:
|
||||||
if (rc) {
|
if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
|
||||||
nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
|
rc = pn533_send_data_async(dev, PN533_CMD_IN_COMM_THRU,
|
||||||
" perform data_exchange", rc);
|
skb,
|
||||||
goto free_arg;
|
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;
|
return 0;
|
||||||
|
|
||||||
free_arg:
|
|
||||||
kfree(arg);
|
|
||||||
free_skb_resp:
|
|
||||||
kfree_skb(skb_resp);
|
|
||||||
error:
|
error:
|
||||||
kfree_skb(skb);
|
kfree(arg);
|
||||||
|
dev_kfree_skb(skb);
|
||||||
return rc;
|
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)
|
static void pn533_wq_mi_recv(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct pn533 *dev = container_of(work, struct pn533, mi_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 sk_buff *skb;
|
||||||
struct pn533_frame *out_frame, *in_frame;
|
|
||||||
struct sk_buff *skb_resp;
|
|
||||||
int skb_resp_len;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
|
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
|
||||||
|
|
||||||
/* This is a zero payload size skb */
|
skb = pn533_alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN);
|
||||||
skb_cmd = pn533_alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN);
|
if (!skb)
|
||||||
if (skb_cmd == NULL)
|
goto error;
|
||||||
goto error_cmd;
|
|
||||||
|
|
||||||
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);
|
break;
|
||||||
if (rc)
|
}
|
||||||
goto error_frame;
|
default:
|
||||||
|
*skb_put(skb, sizeof(u8)) = 1; /*TG*/
|
||||||
|
|
||||||
skb_resp_len = PN533_FRAME_HEADER_LEN +
|
rc = pn533_send_cmd_direct_async(dev,
|
||||||
PN533_CMD_DATAEXCH_HEAD_LEN +
|
PN533_CMD_IN_DATA_EXCHANGE,
|
||||||
PN533_CMD_DATAEXCH_DATA_MAXLEN +
|
skb,
|
||||||
PN533_FRAME_TAIL_LEN;
|
pn533_data_exchange_complete,
|
||||||
|
dev->cmd_complete_mi_arg);
|
||||||
|
|
||||||
skb_resp = alloc_skb(skb_resp_len, GFP_KERNEL);
|
break;
|
||||||
if (!skb_resp) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto error_frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
in_frame = (struct pn533_frame *) skb_resp->data;
|
if (rc == 0) /* success */
|
||||||
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)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
|
nfc_dev_err(&dev->interface->dev,
|
||||||
" perform data_exchange", rc);
|
"Error %d when trying to perform data_exchange", rc);
|
||||||
|
|
||||||
kfree_skb(skb_resp);
|
dev_kfree_skb(skb);
|
||||||
|
kfree(dev->cmd_complete_arg);
|
||||||
|
|
||||||
error_frame:
|
error:
|
||||||
kfree_skb(skb_cmd);
|
|
||||||
|
|
||||||
error_cmd:
|
|
||||||
pn533_send_ack(dev, GFP_KERNEL);
|
pn533_send_ack(dev, GFP_KERNEL);
|
||||||
|
|
||||||
kfree(arg);
|
|
||||||
|
|
||||||
queue_work(dev->wq, &dev->cmd_work);
|
queue_work(dev->wq, &dev->cmd_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue