#define PN533_LISTEN_TIME 2
/* frame definitions */
-#define PN533_NORMAL_FRAME_MAX_LEN 262 /* 6 (PREAMBLE, SOF, LEN, LCS, TFI)
- 254 (DATA)
- 2 (DCS, postamble) */
#define PN533_FRAME_HEADER_LEN (sizeof(struct pn533_frame) \
+ 2) /* data[0] TFI, data[1] CC */
#define PN533_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
*/
#define PN533_FRAME_MAX_PAYLOAD_LEN 263
-#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
- PN533_FRAME_TAIL_LEN)
#define PN533_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2),
Postamble (1) */
#define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen])
u8 len;
};
-const struct pn533_poll_modulations poll_mod[] = {
+static const struct pn533_poll_modulations poll_mod[] = {
[PN533_POLL_MOD_106KBPS_A] = {
.data = {
.maxtg = 1,
struct work_struct mi_work;
struct work_struct tg_work;
struct timer_list listen_timer;
- struct pn533_frame *wq_in_frame;
int wq_in_error;
int cancel_listen;
struct list_head cmd_queue;
u8 cmd_pending;
+
+ struct pn533_frame_ops *ops;
};
struct pn533_cmd {
u8 cmd_code;
struct sk_buff *req;
struct sk_buff *resp;
+ int resp_len;
void *arg;
};
u8 data[];
} __packed;
+struct pn533_frame_ops {
+ void (*tx_frame_init)(void *frame, u8 cmd_code);
+ void (*tx_frame_finish)(void *frame);
+ void (*tx_update_payload_len)(void *frame, int len);
+ int tx_header_len;
+ int tx_tail_len;
+
+ bool (*rx_is_frame_valid)(void *frame);
+ int (*rx_frame_size)(void *frame);
+ int rx_header_len;
+ int rx_tail_len;
+
+ int max_payload_len;
+ u8 (*get_cmd_code)(void *frame);
+};
+
/* The rule: value + checksum = 0 */
static inline u8 pn533_checksum(u8 value)
{
return pn533_checksum(sum);
}
-static void pn533_tx_frame_init(struct pn533_frame *frame, u8 cmd)
+static void pn533_tx_frame_init(void *_frame, u8 cmd_code)
{
+ struct pn533_frame *frame = _frame;
+
frame->preamble = 0;
frame->start_frame = cpu_to_be16(PN533_SOF);
PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT;
- PN533_FRAME_CMD(frame) = cmd;
+ PN533_FRAME_CMD(frame) = cmd_code;
frame->datalen = 2;
}
-static void pn533_tx_frame_finish(struct pn533_frame *frame)
+static void pn533_tx_frame_finish(void *_frame)
{
+ struct pn533_frame *frame = _frame;
+
frame->datalen_checksum = pn533_checksum(frame->datalen);
PN533_FRAME_CHECKSUM(frame) =
PN533_FRAME_POSTAMBLE(frame) = 0;
}
-static bool pn533_rx_frame_is_valid(struct pn533_frame *frame)
+static void pn533_tx_update_payload_len(void *_frame, int len)
+{
+ struct pn533_frame *frame = _frame;
+
+ frame->datalen += len;
+}
+
+static bool pn533_rx_frame_is_valid(void *_frame)
{
u8 checksum;
+ struct pn533_frame *frame = _frame;
if (frame->start_frame != cpu_to_be16(PN533_SOF))
return false;
return true;
}
-static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd)
+static inline int pn533_rx_frame_size(void *frame)
+{
+ struct pn533_frame *f = frame;
+
+ return sizeof(struct pn533_frame) + f->datalen + PN533_FRAME_TAIL_LEN;
+}
+
+static u8 pn533_get_cmd_code(void *frame)
{
- return (PN533_FRAME_CMD(frame) == PN533_CMD_RESPONSE(cmd));
+ struct pn533_frame *f = frame;
+
+ return PN533_FRAME_CMD(f);
+}
+
+static struct pn533_frame_ops pn533_std_frame_ops = {
+ .tx_frame_init = pn533_tx_frame_init,
+ .tx_frame_finish = pn533_tx_frame_finish,
+ .tx_update_payload_len = pn533_tx_update_payload_len,
+ .tx_header_len = PN533_FRAME_HEADER_LEN,
+ .tx_tail_len = PN533_FRAME_TAIL_LEN,
+
+ .rx_is_frame_valid = pn533_rx_frame_is_valid,
+ .rx_frame_size = pn533_rx_frame_size,
+ .rx_header_len = PN533_FRAME_HEADER_LEN,
+ .rx_tail_len = PN533_FRAME_TAIL_LEN,
+
+ .max_payload_len = PN533_FRAME_MAX_PAYLOAD_LEN,
+ .get_cmd_code = pn533_get_cmd_code,
+};
+
+static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame)
+{
+ return (dev->ops->get_cmd_code(frame) == PN533_CMD_RESPONSE(dev->cmd));
}
static void pn533_recv_response(struct urb *urb)
{
struct pn533 *dev = urb->context;
- struct pn533_frame *in_frame;
-
- dev->wq_in_frame = NULL;
+ u8 *in_frame;
switch (urb->status) {
case 0:
urb->status);
dev->wq_in_error = urb->status;
goto sched_wq;
- break;
case -ESHUTDOWN:
default:
nfc_dev_err(&dev->interface->dev,
nfc_dev_dbg(&dev->interface->dev, "Received a frame.");
print_hex_dump(KERN_DEBUG, "PN533 RX: ", DUMP_PREFIX_NONE, 16, 1,
- in_frame, PN533_FRAME_SIZE(in_frame), false);
+ in_frame, dev->ops->rx_frame_size(in_frame), false);
- if (!pn533_rx_frame_is_valid(in_frame)) {
+ if (!dev->ops->rx_is_frame_valid(in_frame)) {
nfc_dev_err(&dev->interface->dev, "Received an invalid frame");
dev->wq_in_error = -EIO;
goto sched_wq;
}
- if (!pn533_rx_frame_is_cmd_response(in_frame, dev->cmd)) {
+ if (!pn533_rx_frame_is_cmd_response(dev, in_frame)) {
nfc_dev_err(&dev->interface->dev,
"It it not the response to the last command");
dev->wq_in_error = -EIO;
}
dev->wq_in_error = 0;
- dev->wq_in_frame = in_frame;
sched_wq:
queue_work(dev->wq, &dev->cmd_complete_work);
urb->status);
dev->wq_in_error = urb->status;
goto sched_wq;
- break;
case -ESHUTDOWN:
default:
nfc_dev_err(&dev->interface->dev,
return;
sched_wq:
- dev->wq_in_frame = NULL;
queue_work(dev->wq, &dev->cmd_complete_work);
}
{
int rc;
- dev->cmd = PN533_FRAME_CMD(((struct pn533_frame *)out->data));
+ dev->cmd = dev->ops->get_cmd_code(out->data);
dev->cmd_complete = cmd_complete;
dev->cmd_complete_arg = arg;
return rc;
}
-static void pn533_build_cmd_frame(u8 cmd_code, struct sk_buff *skb)
+static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code,
+ struct sk_buff *skb)
{
- struct pn533_frame *frame;
/* payload is already there, just update datalen */
int payload_len = skb->len;
+ struct pn533_frame_ops *ops = dev->ops;
- skb_push(skb, PN533_FRAME_HEADER_LEN);
- skb_put(skb, PN533_FRAME_TAIL_LEN);
- frame = (struct pn533_frame *)skb->data;
+ skb_push(skb, ops->tx_header_len);
+ skb_put(skb, ops->tx_tail_len);
- pn533_tx_frame_init(frame, cmd_code);
- frame->datalen += payload_len;
- pn533_tx_frame_finish(frame);
+ ops->tx_frame_init(skb->data, cmd_code);
+ ops->tx_update_payload_len(skb->data, payload_len);
+ ops->tx_frame_finish(skb->data);
}
struct pn533_send_async_complete_arg {
struct sk_buff *req = arg->req;
struct sk_buff *resp = arg->resp;
- struct pn533_frame *frame = (struct pn533_frame *)resp->data;
int rc;
dev_kfree_skb(req);
return status;
}
- skb_put(resp, PN533_FRAME_SIZE(frame));
- skb_pull(resp, PN533_FRAME_HEADER_LEN);
- skb_trim(resp, resp->len - PN533_FRAME_TAIL_LEN);
+ skb_put(resp, dev->ops->rx_frame_size(resp->data));
+ skb_pull(resp, dev->ops->rx_header_len);
+ skb_trim(resp, resp->len - dev->ops->rx_tail_len);
rc = arg->complete_cb(dev, arg->complete_cb_context, resp);
nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", cmd_code);
- arg = kzalloc(sizeof(arg), GFP_KERNEL);
+ arg = kzalloc(sizeof(*arg), GFP_KERNEL);
if (!arg)
return -ENOMEM;
arg->resp = resp;
arg->req = req;
- pn533_build_cmd_frame(cmd_code, req);
+ pn533_build_cmd_frame(dev, cmd_code, req);
mutex_lock(&dev->cmd_lock);
cmd->cmd_code = cmd_code;
cmd->req = req;
cmd->resp = resp;
+ cmd->resp_len = resp_len;
cmd->arg = arg;
list_add_tail(&cmd->queue, &dev->cmd_queue);
{
struct sk_buff *resp;
int rc;
- int resp_len = PN533_FRAME_HEADER_LEN +
- PN533_FRAME_MAX_PAYLOAD_LEN +
- PN533_FRAME_TAIL_LEN;
+ int resp_len = dev->ops->rx_header_len +
+ dev->ops->max_payload_len +
+ dev->ops->rx_tail_len;
resp = nfc_alloc_recv_skb(resp_len, GFP_KERNEL);
if (!resp)
{
struct sk_buff *resp;
int rc;
+ int resp_len = dev->ops->rx_header_len +
+ dev->ops->max_payload_len +
+ dev->ops->rx_tail_len;
- resp = alloc_skb(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
+ resp = alloc_skb(resp_len, GFP_KERNEL);
if (!resp)
return -ENOMEM;
- rc = __pn533_send_async(dev, cmd_code, req, resp,
- PN533_NORMAL_FRAME_MAX_LEN,
- complete_cb, complete_cb_context);
+ rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb,
+ complete_cb_context);
if (rc)
dev_kfree_skb(resp);
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;
+ int resp_len = dev->ops->rx_header_len +
+ dev->ops->max_payload_len +
+ dev->ops->rx_tail_len;
resp = alloc_skb(resp_len, GFP_KERNEL);
if (!resp)
return -ENOMEM;
- arg = kzalloc(sizeof(arg), GFP_KERNEL);
+ arg = kzalloc(sizeof(*arg), GFP_KERNEL);
if (!arg) {
dev_kfree_skb(resp);
return -ENOMEM;
arg->resp = resp;
arg->req = req;
- pn533_build_cmd_frame(cmd_code, req);
+ pn533_build_cmd_frame(dev, cmd_code, req);
rc = __pn533_send_frame_async(dev, req, resp, resp_len,
pn533_send_async_complete, arg);
mutex_unlock(&dev->cmd_lock);
- __pn533_send_frame_async(dev, cmd->req, cmd->resp,
- PN533_NORMAL_FRAME_MAX_LEN,
- pn533_send_async_complete,
- cmd->arg);
+ __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len,
+ pn533_send_async_complete, cmd->arg);
kfree(cmd);
}
}
}
-static struct sk_buff *pn533_alloc_skb(unsigned int size)
+static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size)
{
struct sk_buff *skb;
- skb = alloc_skb(PN533_FRAME_HEADER_LEN +
+ skb = alloc_skb(dev->ops->tx_header_len +
size +
- PN533_FRAME_TAIL_LEN, GFP_KERNEL);
+ dev->ops->tx_tail_len, GFP_KERNEL);
if (skb)
- skb_reserve(skb, PN533_FRAME_HEADER_LEN);
+ skb_reserve(skb, dev->ops->tx_header_len);
return skb;
}
return -EAGAIN;
}
-static struct sk_buff *pn533_alloc_poll_tg_frame(u8 *gbytes, size_t gbytes_len)
+static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev)
{
struct sk_buff *skb;
u8 *felica, *nfcid3, *gb;
+ u8 *gbytes = dev->gb;
+ size_t gbytes_len = dev->gb_len;
+
u8 felica_params[18] = {0x1, 0xfe, /* DEP */
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
gbytes_len +
1; /* len Tk*/
- skb = pn533_alloc_skb(skb_len);
+ skb = pn533_alloc_skb(dev, skb_len);
if (!skb)
return NULL;
/* DEP support only */
- *skb_put(skb, 1) |= PN533_INIT_TARGET_DEP;
+ *skb_put(skb, 1) = PN533_INIT_TARGET_DEP;
/* MIFARE params */
memcpy(skb_put(skb, 6), mifare_params, 6);
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- skb = pn533_alloc_skb(0);
+ skb = pn533_alloc_skb(dev, 0);
if (!skb)
return;
return rc;
}
-static struct sk_buff *pn533_alloc_poll_in_frame(struct pn533_poll_modulations
- *mod)
+static struct sk_buff *pn533_alloc_poll_in_frame(struct pn533 *dev,
+ struct pn533_poll_modulations *mod)
{
struct sk_buff *skb;
- skb = pn533_alloc_skb(mod->len);
+ skb = pn533_alloc_skb(dev, mod->len);
if (!skb)
return NULL;
if (mod->len == 0) { /* Listen mode */
cmd_code = PN533_CMD_TG_INIT_AS_TARGET;
- skb = pn533_alloc_poll_tg_frame(dev->gb, dev->gb_len);
+ skb = pn533_alloc_poll_tg_frame(dev);
} else { /* Polling mode */
cmd_code = PN533_CMD_IN_LIST_PASSIVE_TARGET;
- skb = pn533_alloc_poll_in_frame(mod);
+ skb = pn533_alloc_poll_in_frame(dev, mod);
}
if (!skb) {
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- skb = pn533_alloc_skb(sizeof(u8) * 2); /*TG + Next*/
+ skb = pn533_alloc_skb(dev, sizeof(u8) * 2); /*TG + Next*/
if (!skb)
return -ENOMEM;
rsp = (struct pn533_cmd_activate_response *)resp->data;
rc = rsp->status & PN533_CMD_RET_MASK;
- if (rc != PN533_CMD_RET_SUCCESS)
+ if (rc != PN533_CMD_RET_SUCCESS) {
dev_kfree_skb(resp);
return -EIO;
+ }
/* ATR_RES general bytes are located at offset 16 */
gt_len = resp->len - 16;
dev->tgt_active_prot = 0;
skb_queue_purge(&dev->resp_q);
- skb = pn533_alloc_skb(sizeof(u8));
+ skb = pn533_alloc_skb(dev, sizeof(u8));
if (!skb)
return;
if (comm_mode == NFC_COMM_PASSIVE)
skb_len += PASSIVE_DATA_LEN;
- skb = pn533_alloc_skb(skb_len);
+ skb = pn533_alloc_skb(dev, skb_len);
if (!skb)
return -ENOMEM;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- skb = pn533_alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN);
+ skb = pn533_alloc_skb(dev, PN533_CMD_DATAEXCH_HEAD_LEN);
if (!skb)
goto error;
skb_len = sizeof(cfgitem) + cfgdata_len; /* cfgitem + cfgdata */
- skb = pn533_alloc_skb(skb_len);
+ skb = pn533_alloc_skb(dev, skb_len);
if (!skb)
return -ENOMEM;
struct sk_buff *skb;
struct sk_buff *resp;
- skb = pn533_alloc_skb(0);
+ skb = pn533_alloc_skb(dev, 0);
if (!skb)
return -ENOMEM;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- skb = pn533_alloc_skb(sizeof(u8));
+ skb = pn533_alloc_skb(dev, sizeof(u8));
if (!skb)
return -ENOMEM;
usb_set_intfdata(interface, dev);
- memset(&fw_ver, 0, sizeof(fw_ver));
- rc = pn533_get_firmware_version(dev, &fw_ver);
- if (rc < 0)
- goto destroy_wq;
-
- nfc_dev_info(&dev->interface->dev,
- "NXP PN533 firmware ver %d.%d now attached",
- fw_ver.ver, fw_ver.rev);
+ dev->ops = &pn533_std_frame_ops;
dev->device_type = id->driver_info;
switch (dev->device_type) {
goto destroy_wq;
}
+ memset(&fw_ver, 0, sizeof(fw_ver));
+ rc = pn533_get_firmware_version(dev, &fw_ver);
+ if (rc < 0)
+ goto destroy_wq;
+
+ nfc_dev_info(&dev->interface->dev,
+ "NXP PN533 firmware ver %d.%d now attached",
+ fw_ver.ver, fw_ver.rev);
+
+
dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols,
- PN533_FRAME_HEADER_LEN +
+ NFC_SE_NONE,
+ dev->ops->tx_header_len +
PN533_CMD_DATAEXCH_HEAD_LEN,
- PN533_FRAME_TAIL_LEN);
+ dev->ops->tx_tail_len);
if (!dev->nfc_dev)
goto destroy_wq;