From e279f84f304d5486291a2d6465105dc6f96cc8ca Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 20 Mar 2013 11:27:57 +0100 Subject: NFC: pn533: Use dynamic debug for pn533 hex dumps Those can be very verbose and we only want them when debugging pn533. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index f0f6763d67a..73d39f3fbdf 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -543,8 +543,8 @@ static void pn533_recv_response(struct urb *urb) in_frame = dev->in_urb->transfer_buffer; nfc_dev_dbg(&dev->interface->dev, "Received a frame."); - print_hex_dump(KERN_DEBUG, "PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, - in_frame, dev->ops->rx_frame_size(in_frame), false); + print_hex_dump_debug("PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, in_frame, + dev->ops->rx_frame_size(in_frame), false); if (!dev->ops->rx_is_frame_valid(in_frame)) { nfc_dev_err(&dev->interface->dev, "Received an invalid frame"); @@ -659,8 +659,8 @@ static int __pn533_send_frame_async(struct pn533 *dev, dev->in_urb->transfer_buffer = in->data; dev->in_urb->transfer_buffer_length = in_len; - print_hex_dump(KERN_DEBUG, "PN533 TX: ", DUMP_PREFIX_NONE, 16, 1, - out->data, out->len, false); + print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1, + out->data, out->len, false); rc = usb_submit_urb(dev->out_urb, GFP_KERNEL); if (rc) -- cgit v1.2.3-70-g09d2 From 63123108f45663a93cfbb7480050043c04d202bf Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:01:58 +0200 Subject: NFC: pn533: Reword all std frame logic funct Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 121 ++++++++++++++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 73d39f3fbdf..8e809e083c3 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -78,32 +78,32 @@ MODULE_DEVICE_TABLE(usb, pn533_table); /* How much time we spend listening for initiators */ #define PN533_LISTEN_TIME 2 -/* frame definitions */ -#define PN533_FRAME_HEADER_LEN (sizeof(struct pn533_frame) \ +/* Standard pn533 frame definitions */ +#define PN533_STD_FRAME_HEADER_LEN (sizeof(struct pn533_std_frame) \ + 2) /* data[0] TFI, data[1] CC */ -#define PN533_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/ +#define PN533_STD_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/ /* * Max extended frame payload len, excluding TFI and CC * which are already in PN533_FRAME_HEADER_LEN. */ -#define PN533_FRAME_MAX_PAYLOAD_LEN 263 +#define PN533_STD_FRAME_MAX_PAYLOAD_LEN 263 -#define PN533_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2), +#define PN533_STD_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2), Postamble (1) */ -#define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen]) -#define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1]) +#define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen]) +#define PN533_STD_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1]) /* start of frame */ -#define PN533_SOF 0x00FF +#define PN533_STD_FRAME_SOF 0x00FF -/* frame identifier: in/out/error */ -#define PN533_FRAME_IDENTIFIER(f) (f->data[0]) -#define PN533_DIR_OUT 0xD4 -#define PN533_DIR_IN 0xD5 +/* standard frame identifier: in/out/error */ +#define PN533_STD_FRAME_IDENTIFIER(f) (f->data[0]) /* TFI */ +#define PN533_STD_FRAME_DIR_OUT 0xD4 +#define PN533_STD_FRAME_DIR_IN 0xD5 /* PN533 Commands */ -#define PN533_FRAME_CMD(f) (f->data[1]) +#define PN533_STD_FRAME_CMD(f) (f->data[1]) #define PN533_CMD_GET_FIRMWARE_VERSION 0x02 #define PN533_CMD_RF_CONFIGURATION 0x32 @@ -369,7 +369,7 @@ struct pn533_cmd { void *arg; }; -struct pn533_frame { +struct pn533_std_frame { u8 preamble; __be16 start_frame; u8 datalen; @@ -394,13 +394,13 @@ struct pn533_frame_ops { }; /* The rule: value + checksum = 0 */ -static inline u8 pn533_checksum(u8 value) +static inline u8 pn533_std_checksum(u8 value) { return ~value + 1; } /* The rule: sum(data elements) + checksum = 0 */ -static u8 pn533_data_checksum(u8 *data, int datalen) +static u8 pn533_std_data_checksum(u8 *data, int datalen) { u8 sum = 0; int i; @@ -408,61 +408,61 @@ static u8 pn533_data_checksum(u8 *data, int datalen) for (i = 0; i < datalen; i++) sum += data[i]; - return pn533_checksum(sum); + return pn533_std_checksum(sum); } -static void pn533_tx_frame_init(void *_frame, u8 cmd_code) +static void pn533_std_tx_frame_init(void *_frame, u8 cmd_code) { - struct pn533_frame *frame = _frame; + struct pn533_std_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_code; + frame->start_frame = cpu_to_be16(PN533_STD_FRAME_SOF); + PN533_STD_FRAME_IDENTIFIER(frame) = PN533_STD_FRAME_DIR_OUT; + PN533_STD_FRAME_CMD(frame) = cmd_code; frame->datalen = 2; } -static void pn533_tx_frame_finish(void *_frame) +static void pn533_std_tx_frame_finish(void *_frame) { - struct pn533_frame *frame = _frame; + struct pn533_std_frame *frame = _frame; - frame->datalen_checksum = pn533_checksum(frame->datalen); + frame->datalen_checksum = pn533_std_checksum(frame->datalen); - PN533_FRAME_CHECKSUM(frame) = - pn533_data_checksum(frame->data, frame->datalen); + PN533_STD_FRAME_CHECKSUM(frame) = + pn533_std_data_checksum(frame->data, frame->datalen); - PN533_FRAME_POSTAMBLE(frame) = 0; + PN533_STD_FRAME_POSTAMBLE(frame) = 0; } -static void pn533_tx_update_payload_len(void *_frame, int len) +static void pn533_std_tx_update_payload_len(void *_frame, int len) { - struct pn533_frame *frame = _frame; + struct pn533_std_frame *frame = _frame; frame->datalen += len; } -static bool pn533_rx_frame_is_valid(void *_frame) +static bool pn533_std_rx_frame_is_valid(void *_frame) { u8 checksum; - struct pn533_frame *frame = _frame; + struct pn533_std_frame *frame = _frame; - if (frame->start_frame != cpu_to_be16(PN533_SOF)) + if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF)) return false; - checksum = pn533_checksum(frame->datalen); + checksum = pn533_std_checksum(frame->datalen); if (checksum != frame->datalen_checksum) return false; - checksum = pn533_data_checksum(frame->data, frame->datalen); - if (checksum != PN533_FRAME_CHECKSUM(frame)) + checksum = pn533_std_data_checksum(frame->data, frame->datalen); + if (checksum != PN533_STD_FRAME_CHECKSUM(frame)) return false; return true; } -static bool pn533_rx_frame_is_ack(struct pn533_frame *frame) +static bool pn533_std_rx_frame_is_ack(struct pn533_std_frame *frame) { - if (frame->start_frame != cpu_to_be16(PN533_SOF)) + if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF)) return false; if (frame->datalen != 0 || frame->datalen_checksum != 0xFF) @@ -471,34 +471,35 @@ static bool pn533_rx_frame_is_ack(struct pn533_frame *frame) return true; } -static inline int pn533_rx_frame_size(void *frame) +static inline int pn533_std_rx_frame_size(void *frame) { - struct pn533_frame *f = frame; + struct pn533_std_frame *f = frame; - return sizeof(struct pn533_frame) + f->datalen + PN533_FRAME_TAIL_LEN; + return sizeof(struct pn533_std_frame) + f->datalen + + PN533_STD_FRAME_TAIL_LEN; } -static u8 pn533_get_cmd_code(void *frame) +static u8 pn533_std_get_cmd_code(void *frame) { - struct pn533_frame *f = frame; + struct pn533_std_frame *f = frame; - return PN533_FRAME_CMD(f); + return PN533_STD_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, + .tx_frame_init = pn533_std_tx_frame_init, + .tx_frame_finish = pn533_std_tx_frame_finish, + .tx_update_payload_len = pn533_std_tx_update_payload_len, + .tx_header_len = PN533_STD_FRAME_HEADER_LEN, + .tx_tail_len = PN533_STD_FRAME_TAIL_LEN, + + .rx_is_frame_valid = pn533_std_rx_frame_is_valid, + .rx_frame_size = pn533_std_rx_frame_size, + .rx_header_len = PN533_STD_FRAME_HEADER_LEN, + .rx_tail_len = PN533_STD_FRAME_TAIL_LEN, + + .max_payload_len = PN533_STD_FRAME_MAX_PAYLOAD_LEN, + .get_cmd_code = pn533_std_get_cmd_code, }; static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame) @@ -575,7 +576,7 @@ static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) static void pn533_recv_ack(struct urb *urb) { struct pn533 *dev = urb->context; - struct pn533_frame *in_frame; + struct pn533_std_frame *in_frame; int rc; switch (urb->status) { @@ -598,7 +599,7 @@ static void pn533_recv_ack(struct urb *urb) in_frame = dev->in_urb->transfer_buffer; - if (!pn533_rx_frame_is_ack(in_frame)) { + if (!pn533_std_rx_frame_is_ack(in_frame)) { nfc_dev_err(&dev->interface->dev, "Received an invalid ack"); dev->wq_in_error = -EIO; goto sched_wq; @@ -627,7 +628,7 @@ static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) static int pn533_send_ack(struct pn533 *dev, gfp_t flags) { - u8 ack[PN533_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; + u8 ack[PN533_STD_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; /* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */ int rc; -- cgit v1.2.3-70-g09d2 From a45e1c8d17c04b8fbb27818ce3454d889696da08 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:01:59 +0200 Subject: NFC: pn533: Print out response status bits in hex For better debugging as the codes are defined in hex in the spec. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 8e809e083c3..8ee032d3faa 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1724,6 +1724,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev) rsp = (struct pn533_cmd_activate_response *)resp->data; rc = rsp->status & PN533_CMD_RET_MASK; if (rc != PN533_CMD_RET_SUCCESS) { + nfc_dev_err(&dev->interface->dev, + "Target activation failed (error 0x%x)", rc); dev_kfree_skb(resp); return -EIO; } @@ -1851,7 +1853,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, rc = rsp->status & PN533_CMD_RET_MASK; if (rc != PN533_CMD_RET_SUCCESS) { nfc_dev_err(&dev->interface->dev, - "Bringing DEP link up failed %d", rc); + "Bringing DEP link up failed (error 0x%x)", rc); goto error; } @@ -2065,8 +2067,7 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, if (ret != PN533_CMD_RET_SUCCESS) { nfc_dev_err(&dev->interface->dev, - "PN533 reported error %d when exchanging data", - ret); + "Exchanging data failed (error 0x%x)", ret); rc = -EIO; goto error; } -- cgit v1.2.3-70-g09d2 From 95cb9e10239583a8a849cdbaec689b139618319a Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:00 +0200 Subject: NFC: pn533: Fix div by zero while stopping polling Depends on timing division by zero can happen when user stops polling. pn533_stop_poll() resets modulation counter on stop_poll, but meanwhile we get response for last poll request and try, despite of stop poll request, to schedule next modulation for polling. Log message: [345.922515] pn533 1-1.3:1.0: pn533_stop_poll [345.928314] pn533 1-1.3:1.0: pn533_send_ack [345.932769] pn533 1-1.3:1.0: Received a frame. [345.937438] PN533 RX: 00 00 ff 03 fd d5 4b 00 e0 00 [345.942840] pn533 1-1.3:1.0: pn533_poll_complete [345.947753] pn533 1-1.3:1.0: pn533_start_poll_complete [345.953186] Division by zero in kernel. [345.957244] [] (unwind_backtrace+0x0/0xf0) [345.965698] [] (Ldiv0+0x8/0x10) [345.974060] [] (__aeabi_idivmod+0x8/0x18) [345.983978] [] (pn533_poll_complete+0x3c0/0x500) [345.994903] [] (pn533_send_async_complete+0x7c/0xc0) [346.005828] [] (pn533_wq_cmd_complete+0x1c/0x34) [346.016113] [] (process_one_work+0x1ac/0x57c) [346.025848] [] (worker_thread+0x168/0x42c) [346.034576] [] (kthread+0xa4/0xb0) Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 8ee032d3faa..c20778a56f4 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1550,6 +1550,11 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg, if (!rc) goto done; + if (!dev->poll_mod_count) { + nfc_dev_dbg(&dev->interface->dev, "Polling has been stoped."); + goto done; + } + pn533_poll_next_mod(dev); queue_work(dev->wq, &dev->poll_work); -- cgit v1.2.3-70-g09d2 From e70b96e95b61fcf7b1c85bc4e4db1f9478e3d2ff Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:01 +0200 Subject: NFC: pn533: Update copyrights note Remove duplicated authors info from the header as well. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index c20778a56f4..b193ae6998e 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1,9 +1,6 @@ /* * Copyright (C) 2011 Instituto Nokia de Tecnologia - * - * Authors: - * Lauro Ramos Venancio - * Aloisio Almeida Jr + * Copyright (C) 2012-2013 Tieto Poland * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -2607,8 +2604,9 @@ static struct usb_driver pn533_driver = { module_usb_driver(pn533_driver); -MODULE_AUTHOR("Lauro Ramos Venancio ," - " Aloisio Almeida Jr "); +MODULE_AUTHOR("Lauro Ramos Venancio "); +MODULE_AUTHOR("Aloisio Almeida Jr "); +MODULE_AUTHOR("Waldemar Rymarkiewicz "); MODULE_DESCRIPTION("PN533 usb driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From f75c291361fc646d42cd62d8ebfbdecaa13077cc Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:02 +0200 Subject: NFC: pn533: Rename pn533_fw_reset appropriately Define explicitely it is Pasori specific reset command. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index b193ae6998e..24ffbe04108 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -2314,7 +2314,7 @@ static int pn533_get_firmware_version(struct pn533 *dev, return 0; } -static int pn533_fw_reset(struct pn533 *dev) +static int pn533_pasori_fw_reset(struct pn533 *dev) { struct sk_buff *skb; struct sk_buff *resp; @@ -2409,7 +2409,7 @@ static int pn533_setup(struct pn533 *dev) break; case PN533_DEVICE_PASORI: - pn533_fw_reset(dev); + pn533_pasori_fw_reset(dev); rc = pn533_set_configuration(dev, PN533_CFGITEM_PASORI, pasori_cfg, 3); @@ -2419,7 +2419,7 @@ static int pn533_setup(struct pn533 *dev) return rc; } - pn533_fw_reset(dev); + pn533_pasori_fw_reset(dev); break; } -- cgit v1.2.3-70-g09d2 From 0ce1fbdd609875f523de0d8179c6f4f8500807c7 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:03 +0200 Subject: NFC: pn533: Fix memleak while scheduling next cmd In case of error from __pn533_send_frame_async() while sending next cmd from the queue (cmd_wq), cmd->req, cmd->resp and cmd->arg pointers won't be freed. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 24ffbe04108..48902e58cac 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -886,6 +886,7 @@ static void pn533_wq_cmd(struct work_struct *work) { struct pn533 *dev = container_of(work, struct pn533, cmd_work); struct pn533_cmd *cmd; + int rc; mutex_lock(&dev->cmd_lock); @@ -901,8 +902,13 @@ static void pn533_wq_cmd(struct work_struct *work) mutex_unlock(&dev->cmd_lock); - __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len, - pn533_send_async_complete, cmd->arg); + rc = __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len, + pn533_send_async_complete, cmd->arg); + if (rc < 0) { + dev_kfree_skb(cmd->req); + dev_kfree_skb(cmd->resp); + kfree(cmd->arg); + } kfree(cmd); } -- cgit v1.2.3-70-g09d2 From 4231604b3e867bd8cff7ae81a3068615954aa1c8 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:04 +0200 Subject: NFC: pn533: Optimise issued cmd context tracking Use struct pn533_cmd instead of pn533_send_async_complete_arg to track the context of the issued cmd. This way pn533_send_async_complete_arg struct is no needed anymore. Just move issuer complete callback to pn533_cmd struct. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 87 +++++++++++++++++++++-------------------------------- 1 file changed, 35 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 48902e58cac..2f39209507d 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -363,7 +363,8 @@ struct pn533_cmd { struct sk_buff *req; struct sk_buff *resp; int resp_len; - void *arg; + pn533_send_async_complete_t complete_cb; + void *complete_cb_context; }; struct pn533_std_frame { @@ -691,39 +692,32 @@ static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code, ops->tx_frame_finish(skb->data); } -struct pn533_send_async_complete_arg { - pn533_send_async_complete_t complete_cb; - void *complete_cb_context; - struct sk_buff *resp; - struct sk_buff *req; -}; - -static int pn533_send_async_complete(struct pn533 *dev, void *_arg, int status) +static int pn533_send_async_complete(struct pn533 *dev, void *arg, int status) { - struct pn533_send_async_complete_arg *arg = _arg; + struct pn533_cmd *cmd = arg; - struct sk_buff *req = arg->req; - struct sk_buff *resp = arg->resp; + struct sk_buff *req = cmd->req; + struct sk_buff *resp = cmd->resp; int rc; dev_kfree_skb(req); if (status < 0) { - arg->complete_cb(dev, arg->complete_cb_context, - ERR_PTR(status)); + rc = cmd->complete_cb(dev, cmd->complete_cb_context, + ERR_PTR(status)); dev_kfree_skb(resp); - kfree(arg); - return status; + kfree(cmd); + return rc; } 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); + rc = cmd->complete_cb(dev, cmd->complete_cb_context, resp); - kfree(arg); + kfree(cmd); return rc; } @@ -734,19 +728,20 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, void *complete_cb_context) { struct pn533_cmd *cmd; - struct pn533_send_async_complete_arg *arg; int rc = 0; nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", cmd_code); - arg = kzalloc(sizeof(*arg), GFP_KERNEL); - if (!arg) + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) return -ENOMEM; - arg->complete_cb = complete_cb; - arg->complete_cb_context = complete_cb_context; - arg->resp = resp; - arg->req = req; + cmd->cmd_code = cmd_code; + cmd->req = req; + cmd->resp = resp; + cmd->resp_len = resp_len; + cmd->complete_cb = complete_cb; + cmd->complete_cb_context = complete_cb_context; pn533_build_cmd_frame(dev, cmd_code, req); @@ -754,7 +749,7 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, if (!dev->cmd_pending) { rc = __pn533_send_frame_async(dev, req, resp, resp_len, - pn533_send_async_complete, arg); + pn533_send_async_complete, cmd); if (rc) goto error; @@ -765,25 +760,13 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, nfc_dev_dbg(&dev->interface->dev, "%s Queueing command 0x%x", __func__, cmd_code); - cmd = kzalloc(sizeof(struct pn533_cmd), GFP_KERNEL); - if (!cmd) { - rc = -ENOMEM; - goto error; - } - INIT_LIST_HEAD(&cmd->queue); - 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); goto unlock; error: - kfree(arg); + kfree(cmd); unlock: mutex_unlock(&dev->cmd_lock); return rc; @@ -848,8 +831,8 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, pn533_send_async_complete_t complete_cb, void *complete_cb_context) { - struct pn533_send_async_complete_arg *arg; struct sk_buff *resp; + struct pn533_cmd *cmd; int rc; int resp_len = dev->ops->rx_header_len + dev->ops->max_payload_len + @@ -859,24 +842,26 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, if (!resp) return -ENOMEM; - arg = kzalloc(sizeof(*arg), GFP_KERNEL); - if (!arg) { + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { dev_kfree_skb(resp); return -ENOMEM; } - arg->complete_cb = complete_cb; - arg->complete_cb_context = complete_cb_context; - arg->resp = resp; - arg->req = req; + cmd->cmd_code = cmd_code; + cmd->req = req; + cmd->resp = resp; + cmd->resp_len = resp_len; + cmd->complete_cb = complete_cb; + cmd->complete_cb_context = complete_cb_context; pn533_build_cmd_frame(dev, cmd_code, req); rc = __pn533_send_frame_async(dev, req, resp, resp_len, - pn533_send_async_complete, arg); + pn533_send_async_complete, cmd); if (rc < 0) { dev_kfree_skb(resp); - kfree(arg); + kfree(cmd); } return rc; @@ -903,14 +888,12 @@ static void pn533_wq_cmd(struct work_struct *work) mutex_unlock(&dev->cmd_lock); rc = __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len, - pn533_send_async_complete, cmd->arg); + pn533_send_async_complete, cmd); if (rc < 0) { dev_kfree_skb(cmd->req); dev_kfree_skb(cmd->resp); - kfree(cmd->arg); + kfree(cmd); } - - kfree(cmd); } struct pn533_sync_cmd_response { -- cgit v1.2.3-70-g09d2 From 2c206fb7fea4676f08c4b356003ada7ae462bed5 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:05 +0200 Subject: NFC: pn533: Keep cmd context in pn533 struct Keep cmd context in pn533 struct instead of only cmd code. The context already includes cmd_code. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 2f39209507d..147ad05122b 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -334,7 +334,7 @@ struct pn533 { void *cmd_complete_arg; void *cmd_complete_mi_arg; struct mutex cmd_lock; - u8 cmd; + struct pn533_cmd *cmd; struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1]; u8 poll_mod_count; @@ -502,7 +502,8 @@ static struct pn533_frame_ops pn533_std_frame_ops = { 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)); + return (dev->ops->get_cmd_code(frame) == + PN533_CMD_RESPONSE(dev->cmd->cmd_code)); } @@ -648,7 +649,6 @@ static int __pn533_send_frame_async(struct pn533 *dev, { int rc; - dev->cmd = dev->ops->get_cmd_code(out->data); dev->cmd_complete = cmd_complete; dev->cmd_complete_arg = arg; @@ -707,8 +707,7 @@ static int pn533_send_async_complete(struct pn533 *dev, void *arg, int status) rc = cmd->complete_cb(dev, cmd->complete_cb_context, ERR_PTR(status)); dev_kfree_skb(resp); - kfree(cmd); - return rc; + goto done; } skb_put(resp, dev->ops->rx_frame_size(resp->data)); @@ -717,7 +716,9 @@ static int pn533_send_async_complete(struct pn533 *dev, void *arg, int status) rc = cmd->complete_cb(dev, cmd->complete_cb_context, resp); +done: kfree(cmd); + dev->cmd = NULL; return rc; } @@ -754,6 +755,7 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, goto error; dev->cmd_pending = 1; + dev->cmd = cmd; goto unlock; } @@ -862,6 +864,8 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, if (rc < 0) { dev_kfree_skb(resp); kfree(cmd); + } else { + dev->cmd = cmd; } return rc; @@ -893,7 +897,10 @@ static void pn533_wq_cmd(struct work_struct *work) dev_kfree_skb(cmd->req); dev_kfree_skb(cmd->resp); kfree(cmd); + return; } + + dev->cmd = cmd; } struct pn533_sync_cmd_response { -- cgit v1.2.3-70-g09d2 From 4b2a9532763ac22685505ae116254cab3746d71d Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:06 +0200 Subject: NFC: pn533: Remove redundant cmd_ prefix in the struct 'cmd->code' looks better then 'cmd->cmd_code' Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 147ad05122b..80a6e7ceb16 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -359,7 +359,7 @@ struct pn533 { struct pn533_cmd { struct list_head queue; - u8 cmd_code; + u8 code; struct sk_buff *req; struct sk_buff *resp; int resp_len; @@ -503,7 +503,7 @@ static struct pn533_frame_ops pn533_std_frame_ops = { 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->cmd_code)); + PN533_CMD_RESPONSE(dev->cmd->code)); } @@ -737,7 +737,7 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, if (!cmd) return -ENOMEM; - cmd->cmd_code = cmd_code; + cmd->code = cmd_code; cmd->req = req; cmd->resp = resp; cmd->resp_len = resp_len; @@ -850,7 +850,7 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, return -ENOMEM; } - cmd->cmd_code = cmd_code; + cmd->code = cmd_code; cmd->req = req; cmd->resp = resp; cmd->resp_len = resp_len; -- cgit v1.2.3-70-g09d2 From 140ef7f6b08ff8ebfe5da619036c21a6382d7df9 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:07 +0200 Subject: NFC: pn533: Fix incorrect kfree of complete args We must free 'cmd_complete_mi_arg' and not 'cmd_complete_arg' when getting send error handling fragmented response. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 80a6e7ceb16..ef8e44785b5 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -2253,7 +2253,7 @@ static void pn533_wq_mi_recv(struct work_struct *work) "Error %d when trying to perform data_exchange", rc); dev_kfree_skb(skb); - kfree(dev->cmd_complete_arg); + kfree(dev->cmd_complete_mi_arg); error: pn533_send_ack(dev, GFP_KERNEL); -- cgit v1.2.3-70-g09d2 From ddf19d206fe4ba4e7dc9629bc14025ba50915886 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:08 +0200 Subject: NFC: pn533: Simplify __pn533_send_frame_async In all cases (send_cmd_async, send_data_async and send_sync) pn533_send_async_complete() handles all responses internally, so there is no need to pass this as a callback. Cmd context is passed to __pn533_send_frame_async in all the cases as well. It's already kept in struct pn533 which is available all the time the device is attached. So we can make use of it instead. Therefore, cmd_complete and cmd_complete_arg are no needed any more. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index ef8e44785b5..72860569fb1 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -330,8 +330,6 @@ struct pn533 { int wq_in_error; int cancel_listen; - pn533_cmd_complete_t cmd_complete; - void *cmd_complete_arg; void *cmd_complete_mi_arg; struct mutex cmd_lock; struct pn533_cmd *cmd; @@ -506,13 +504,14 @@ static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame) PN533_CMD_RESPONSE(dev->cmd->code)); } +static int pn533_send_async_complete(struct pn533 *dev); static void pn533_wq_cmd_complete(struct work_struct *work) { struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work); int rc; - rc = dev->cmd_complete(dev, dev->cmd_complete_arg, dev->wq_in_error); + rc = pn533_send_async_complete(dev); if (rc != -EINPROGRESS) queue_work(dev->wq, &dev->cmd_work); } @@ -643,15 +642,10 @@ static int pn533_send_ack(struct pn533 *dev, gfp_t flags) static int __pn533_send_frame_async(struct pn533 *dev, struct sk_buff *out, struct sk_buff *in, - int in_len, - pn533_cmd_complete_t cmd_complete, - void *arg) + int in_len) { int rc; - dev->cmd_complete = cmd_complete; - dev->cmd_complete_arg = arg; - dev->out_urb->transfer_buffer = out->data; dev->out_urb->transfer_buffer_length = out->len; @@ -692,9 +686,10 @@ static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code, ops->tx_frame_finish(skb->data); } -static int pn533_send_async_complete(struct pn533 *dev, void *arg, int status) +static int pn533_send_async_complete(struct pn533 *dev) { - struct pn533_cmd *cmd = arg; + struct pn533_cmd *cmd = dev->cmd; + int status = dev->wq_in_error; struct sk_buff *req = cmd->req; struct sk_buff *resp = cmd->resp; @@ -749,8 +744,7 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, mutex_lock(&dev->cmd_lock); if (!dev->cmd_pending) { - rc = __pn533_send_frame_async(dev, req, resp, resp_len, - pn533_send_async_complete, cmd); + rc = __pn533_send_frame_async(dev, req, resp, resp_len); if (rc) goto error; @@ -859,8 +853,7 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, pn533_build_cmd_frame(dev, cmd_code, req); - rc = __pn533_send_frame_async(dev, req, resp, resp_len, - pn533_send_async_complete, cmd); + rc = __pn533_send_frame_async(dev, req, resp, resp_len); if (rc < 0) { dev_kfree_skb(resp); kfree(cmd); @@ -891,8 +884,7 @@ static void pn533_wq_cmd(struct work_struct *work) mutex_unlock(&dev->cmd_lock); - rc = __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len, - pn533_send_async_complete, cmd); + rc = __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len); if (rc < 0) { dev_kfree_skb(cmd->req); dev_kfree_skb(cmd->resp); -- cgit v1.2.3-70-g09d2 From c79490e1b5ebf35415147fe06f02d8e77ccfe6d4 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:09 +0200 Subject: NFC: pn533: Avoid function declarations Reorder code to avoid functions declaration. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 72860569fb1..faf377aec73 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -504,18 +504,6 @@ static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame) PN533_CMD_RESPONSE(dev->cmd->code)); } -static int pn533_send_async_complete(struct pn533 *dev); - -static void pn533_wq_cmd_complete(struct work_struct *work) -{ - struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work); - int rc; - - rc = pn533_send_async_complete(dev); - if (rc != -EINPROGRESS) - queue_work(dev->wq, &dev->cmd_work); -} - static void pn533_recv_response(struct urb *urb) { struct pn533 *dev = urb->context; @@ -864,6 +852,16 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, return rc; } +static void pn533_wq_cmd_complete(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work); + int rc; + + rc = pn533_send_async_complete(dev); + if (rc != -EINPROGRESS) + queue_work(dev->wq, &dev->cmd_work); +} + static void pn533_wq_cmd(struct work_struct *work) { struct pn533 *dev = container_of(work, struct pn533, cmd_work); -- cgit v1.2.3-70-g09d2 From d5590bba37f3c7d496195648532d5313abb43891 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:10 +0200 Subject: NFC: pn533: Re-group fields in struct pn533 Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index faf377aec73..326cefbfb14 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -314,6 +314,7 @@ struct pn533 { struct usb_device *udev; struct usb_interface *interface; struct nfc_dev *nfc_dev; + u32 device_type; struct urb *out_urb; struct urb *in_urb; @@ -326,19 +327,22 @@ struct pn533 { struct work_struct poll_work; struct work_struct mi_work; struct work_struct tg_work; - struct timer_list listen_timer; + + struct list_head cmd_queue; + struct pn533_cmd *cmd; + u8 cmd_pending; int wq_in_error; - int cancel_listen; + struct mutex cmd_lock; /* protects cmd queue */ void *cmd_complete_mi_arg; - struct mutex cmd_lock; - struct pn533_cmd *cmd; struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1]; u8 poll_mod_count; u8 poll_mod_curr; u32 poll_protocols; u32 listen_protocols; + struct timer_list listen_timer; + int cancel_listen; u8 *gb; size_t gb_len; @@ -347,11 +351,6 @@ struct pn533 { u8 tgt_active_prot; u8 tgt_mode; - u32 device_type; - - struct list_head cmd_queue; - u8 cmd_pending; - struct pn533_frame_ops *ops; }; -- cgit v1.2.3-70-g09d2 From f87bc9fb62780970ff437e9d556b143cbe9f6528 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:11 +0200 Subject: NFC: pn533: Move wq_in_error to cmd context Rename 'wq_in_error' field to more relevant 'status' and move it to cmd context struct. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 326cefbfb14..edee0d55d8f 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -331,7 +331,6 @@ struct pn533 { struct list_head cmd_queue; struct pn533_cmd *cmd; u8 cmd_pending; - int wq_in_error; struct mutex cmd_lock; /* protects cmd queue */ void *cmd_complete_mi_arg; @@ -357,6 +356,7 @@ struct pn533 { struct pn533_cmd { struct list_head queue; u8 code; + int status; struct sk_buff *req; struct sk_buff *resp; int resp_len; @@ -506,8 +506,11 @@ static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame) static void pn533_recv_response(struct urb *urb) { struct pn533 *dev = urb->context; + struct pn533_cmd *cmd = dev->cmd; u8 *in_frame; + cmd->status = urb->status; + switch (urb->status) { case 0: break; /* success */ @@ -516,13 +519,11 @@ static void pn533_recv_response(struct urb *urb) nfc_dev_dbg(&dev->interface->dev, "The urb has been canceled (status %d)", urb->status); - dev->wq_in_error = urb->status; goto sched_wq; case -ESHUTDOWN: default: nfc_dev_err(&dev->interface->dev, "Urb failure (status %d)", urb->status); - dev->wq_in_error = urb->status; goto sched_wq; } @@ -534,19 +535,17 @@ static void pn533_recv_response(struct urb *urb) if (!dev->ops->rx_is_frame_valid(in_frame)) { nfc_dev_err(&dev->interface->dev, "Received an invalid frame"); - dev->wq_in_error = -EIO; + cmd->status = -EIO; goto sched_wq; } 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; + cmd->status = -EIO; goto sched_wq; } - dev->wq_in_error = 0; - sched_wq: queue_work(dev->wq, &dev->cmd_complete_work); } @@ -561,9 +560,12 @@ static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) static void pn533_recv_ack(struct urb *urb) { struct pn533 *dev = urb->context; + struct pn533_cmd *cmd = dev->cmd; struct pn533_std_frame *in_frame; int rc; + cmd->status = urb->status; + switch (urb->status) { case 0: break; /* success */ @@ -572,13 +574,11 @@ static void pn533_recv_ack(struct urb *urb) nfc_dev_dbg(&dev->interface->dev, "The urb has been stopped (status %d)", urb->status); - dev->wq_in_error = urb->status; goto sched_wq; case -ESHUTDOWN: default: nfc_dev_err(&dev->interface->dev, "Urb failure (status %d)", urb->status); - dev->wq_in_error = urb->status; goto sched_wq; } @@ -586,7 +586,7 @@ static void pn533_recv_ack(struct urb *urb) if (!pn533_std_rx_frame_is_ack(in_frame)) { nfc_dev_err(&dev->interface->dev, "Received an invalid ack"); - dev->wq_in_error = -EIO; + cmd->status = -EIO; goto sched_wq; } @@ -594,7 +594,7 @@ static void pn533_recv_ack(struct urb *urb) if (rc) { nfc_dev_err(&dev->interface->dev, "usb_submit_urb failed with result %d", rc); - dev->wq_in_error = rc; + cmd->status = rc; goto sched_wq; } @@ -676,7 +676,7 @@ static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code, static int pn533_send_async_complete(struct pn533 *dev) { struct pn533_cmd *cmd = dev->cmd; - int status = dev->wq_in_error; + int status = cmd->status; struct sk_buff *req = cmd->req; struct sk_buff *resp = cmd->resp; -- cgit v1.2.3-70-g09d2 From 58520373d8aff974f4b3f1bd9eb84c1ff3d6bd8b Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:12 +0200 Subject: NFC: pn533: Add protocol type for frame ops As not all devices require ACK confirmation of every request sent to the controller, differentiate two protocol types. First one, request-ack-response and the second one request-response type. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index edee0d55d8f..2fd8029f377 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -310,11 +310,17 @@ struct pn533_cmd_jump_dep_response { #define PN533_INIT_TARGET_RESP_ACTIVE 0x1 #define PN533_INIT_TARGET_RESP_DEP 0x4 +enum pn533_protocol_type { + PN533_PROTO_REQ_ACK_RESP = 0, + PN533_PROTO_REQ_RESP +}; + struct pn533 { struct usb_device *udev; struct usb_interface *interface; struct nfc_dev *nfc_dev; u32 device_type; + enum pn533_protocol_type protocol_type; struct urb *out_urb; struct urb *in_urb; @@ -646,9 +652,17 @@ static int __pn533_send_frame_async(struct pn533 *dev, if (rc) return rc; - rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL); - if (rc) - goto error; + if (dev->protocol_type == PN533_PROTO_REQ_RESP) { + /* request for response for sent packet directly */ + rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC); + if (rc) + goto error; + } else if (dev->protocol_type == PN533_PROTO_REQ_ACK_RESP) { + /* request for ACK if that's the case */ + rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL); + if (rc) + goto error; + } return 0; @@ -2485,6 +2499,7 @@ static int pn533_probe(struct usb_interface *interface, dev->ops = &pn533_std_frame_ops; + dev->protocol_type = PN533_PROTO_REQ_ACK_RESP; dev->device_type = id->driver_info; switch (dev->device_type) { case PN533_DEVICE_STD: -- cgit v1.2.3-70-g09d2 From 53cf48399ad3b08c9115b4fce73dee0b6e726c91 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:13 +0200 Subject: NFC: pn533: Add support for ACS ACR122U reader ACS ACR122U is an USB NFC reader, PC/SC and CCID compilant, based on NXP PN532 chip. Internally, it's build of MCU, PN532 and an antenna. MCU makes the device CCID and PC/SC compilant and provide USB connection. In this achitecture, a host cannot talk directly to PN532 and must rely on MCU. Luckily, MCU exposes pseud-APDU through PC/SC Escape mechanism which let the host to transmit standard PN532 commands directly to PN532 chip with some limitations. The frame roughly looks like: CCID header | APDU header | PN532 header (pc_to_rdr_escape) | (pseudo apdu Direct Tramsmit) | (len, TFI, cmd, params) Accordign to limitations, ACR122U does't provide any mechanism to abort last issued command. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 217 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 2fd8029f377..697f154331e 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -38,8 +38,12 @@ #define SONY_VENDOR_ID 0x054c #define PASORI_PRODUCT_ID 0x02e1 -#define PN533_DEVICE_STD 0x1 -#define PN533_DEVICE_PASORI 0x2 +#define ACS_VENDOR_ID 0x072f +#define ACR122U_PRODUCT_ID 0x2200 + +#define PN533_DEVICE_STD 0x1 +#define PN533_DEVICE_PASORI 0x2 +#define PN533_DEVICE_ACR122U 0x3 #define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ @@ -68,6 +72,11 @@ static const struct usb_device_id pn533_table[] = { .idProduct = PASORI_PRODUCT_ID, .driver_info = PN533_DEVICE_PASORI, }, + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = ACS_VENDOR_ID, + .idProduct = ACR122U_PRODUCT_ID, + .driver_info = PN533_DEVICE_ACR122U, + }, { } }; MODULE_DEVICE_TABLE(usb, pn533_table); @@ -99,6 +108,21 @@ MODULE_DEVICE_TABLE(usb, pn533_table); #define PN533_STD_FRAME_DIR_OUT 0xD4 #define PN533_STD_FRAME_DIR_IN 0xD5 +/* ACS ACR122 pn533 frame definitions */ +#define PN533_ACR122_TX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_tx_frame) \ + + 2) +#define PN533_ACR122_TX_FRAME_TAIL_LEN 0 +#define PN533_ACR122_RX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_rx_frame) \ + + 2) +#define PN533_ACR122_RX_FRAME_TAIL_LEN 2 +#define PN533_ACR122_FRAME_MAX_PAYLOAD_LEN PN533_STD_FRAME_MAX_PAYLOAD_LEN + +/* CCID messages types */ +#define PN533_ACR122_PC_TO_RDR_ICCPOWERON 0x62 +#define PN533_ACR122_PC_TO_RDR_ESCAPE 0x6B + +#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83 + /* PN533 Commands */ #define PN533_STD_FRAME_CMD(f) (f->data[1]) @@ -394,6 +418,116 @@ struct pn533_frame_ops { u8 (*get_cmd_code)(void *frame); }; +struct pn533_acr122_ccid_hdr { + u8 type; + u32 datalen; + u8 slot; + u8 seq; + u8 params[3]; /* 3 msg specific bytes or status, error and 1 specific + byte for reposnse msg */ + u8 data[]; /* payload */ +} __packed; + +struct pn533_acr122_apdu_hdr { + u8 class; + u8 ins; + u8 p1; + u8 p2; +} __packed; + +struct pn533_acr122_tx_frame { + struct pn533_acr122_ccid_hdr ccid; + struct pn533_acr122_apdu_hdr apdu; + u8 datalen; + u8 data[]; /* pn533 frame: TFI ... */ +} __packed; + +struct pn533_acr122_rx_frame { + struct pn533_acr122_ccid_hdr ccid; + u8 data[]; /* pn533 frame : TFI ... */ +} __packed; + +static void pn533_acr122_tx_frame_init(void *_frame, u8 cmd_code) +{ + struct pn533_acr122_tx_frame *frame = _frame; + + frame->ccid.type = PN533_ACR122_PC_TO_RDR_ESCAPE; + frame->ccid.datalen = sizeof(frame->apdu) + 1; /* sizeof(apdu_hdr) + + sizeof(datalen) */ + frame->ccid.slot = 0; + frame->ccid.seq = 0; + frame->ccid.params[0] = 0; + frame->ccid.params[1] = 0; + frame->ccid.params[2] = 0; + + frame->data[0] = PN533_STD_FRAME_DIR_OUT; + frame->data[1] = cmd_code; + frame->datalen = 2; /* data[0] + data[1] */ + + frame->apdu.class = 0xFF; + frame->apdu.ins = 0; + frame->apdu.p1 = 0; + frame->apdu.p2 = 0; +} + +static void pn533_acr122_tx_frame_finish(void *_frame) +{ + struct pn533_acr122_tx_frame *frame = _frame; + + frame->ccid.datalen += frame->datalen; +} + +static void pn533_acr122_tx_update_payload_len(void *_frame, int len) +{ + struct pn533_acr122_tx_frame *frame = _frame; + + frame->datalen += len; +} + +static bool pn533_acr122_is_rx_frame_valid(void *_frame) +{ + struct pn533_acr122_rx_frame *frame = _frame; + + if (frame->ccid.type != 0x83) + return false; + + if (frame->data[frame->ccid.datalen - 2] == 0x63) + return false; + + return true; +} + +static int pn533_acr122_rx_frame_size(void *frame) +{ + struct pn533_acr122_rx_frame *f = frame; + + /* f->ccid.datalen already includes tail length */ + return sizeof(struct pn533_acr122_rx_frame) + f->ccid.datalen; +} + +static u8 pn533_acr122_get_cmd_code(void *frame) +{ + struct pn533_acr122_rx_frame *f = frame; + + return PN533_STD_FRAME_CMD(f); +} + +static struct pn533_frame_ops pn533_acr122_frame_ops = { + .tx_frame_init = pn533_acr122_tx_frame_init, + .tx_frame_finish = pn533_acr122_tx_frame_finish, + .tx_update_payload_len = pn533_acr122_tx_update_payload_len, + .tx_header_len = PN533_ACR122_TX_FRAME_HEADER_LEN, + .tx_tail_len = PN533_ACR122_TX_FRAME_TAIL_LEN, + + .rx_is_frame_valid = pn533_acr122_is_rx_frame_valid, + .rx_header_len = PN533_ACR122_RX_FRAME_HEADER_LEN, + .rx_tail_len = PN533_ACR122_RX_FRAME_TAIL_LEN, + .rx_frame_size = pn533_acr122_rx_frame_size, + + .max_payload_len = PN533_ACR122_FRAME_MAX_PAYLOAD_LEN, + .get_cmd_code = pn533_acr122_get_cmd_code, +}; + /* The rule: value + checksum = 0 */ static inline u8 pn533_std_checksum(u8 value) { @@ -2335,6 +2469,72 @@ static int pn533_pasori_fw_reset(struct pn533 *dev) return 0; } +struct pn533_acr122_poweron_rdr_arg { + int rc; + struct completion done; +}; + +static void pn533_acr122_poweron_rdr_resp(struct urb *urb) +{ + struct pn533_acr122_poweron_rdr_arg *arg = urb->context; + + nfc_dev_dbg(&urb->dev->dev, "%s", __func__); + + print_hex_dump(KERN_ERR, "ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1, + urb->transfer_buffer, urb->transfer_buffer_length, + false); + + arg->rc = urb->status; + complete(&arg->done); +} + +static int pn533_acr122_poweron_rdr(struct pn533 *dev) +{ + /* Power on th reader (CCID cmd) */ + u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON, + 0, 0, 0, 0, 0, 0, 3, 0, 0}; + u8 buf[255]; + int rc; + void *cntx; + struct pn533_acr122_poweron_rdr_arg arg; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + init_completion(&arg.done); + cntx = dev->in_urb->context; /* backup context */ + + dev->in_urb->transfer_buffer = buf; + dev->in_urb->transfer_buffer_length = 255; + dev->in_urb->complete = pn533_acr122_poweron_rdr_resp; + dev->in_urb->context = &arg; + + dev->out_urb->transfer_buffer = cmd; + dev->out_urb->transfer_buffer_length = sizeof(cmd); + + print_hex_dump(KERN_ERR, "ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1, + cmd, sizeof(cmd), false); + + rc = usb_submit_urb(dev->out_urb, GFP_KERNEL); + if (rc) { + nfc_dev_err(&dev->interface->dev, + "Reader power on cmd error %d", rc); + return rc; + } + + rc = usb_submit_urb(dev->in_urb, GFP_KERNEL); + if (rc) { + nfc_dev_err(&dev->interface->dev, + "Can't submit for reader power on cmd response %d", + rc); + return rc; + } + + wait_for_completion(&arg.done); + dev->in_urb->context = cntx; /* restore context */ + + return arg.rc; +} + static struct nfc_ops pn533_nfc_ops = { .dev_up = NULL, .dev_down = NULL, @@ -2369,6 +2569,7 @@ static int pn533_setup(struct pn533 *dev) break; case PN533_DEVICE_PASORI: + case PN533_DEVICE_ACR122U: max_retries.mx_rty_atr = 0x2; max_retries.mx_rty_psl = 0x1; max_retries.mx_rty_passive_act = @@ -2510,6 +2711,20 @@ static int pn533_probe(struct usb_interface *interface, protocols = PN533_NO_TYPE_B_PROTOCOLS; break; + case PN533_DEVICE_ACR122U: + protocols = PN533_NO_TYPE_B_PROTOCOLS; + dev->ops = &pn533_acr122_frame_ops; + dev->protocol_type = PN533_PROTO_REQ_RESP, + + rc = pn533_acr122_poweron_rdr(dev); + if (rc < 0) { + nfc_dev_err(&dev->interface->dev, + "Couldn't poweron the reader (error %d)", + rc); + goto destroy_wq; + } + break; + default: nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n", dev->device_type); -- cgit v1.2.3-70-g09d2 From 10cff29af6ae12725d4cb338abb5768e139b808a Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:14 +0200 Subject: NFC: pn533: Add pn533_abort_cmd procedure pn533_abort_cmd() aborts last command sent to the controller and cancels already requested urb. As ACR122U does not support any mechanism (as ACK for standard PN533) which aborts last command this cannot be issued for this device. Otherwise, acr122u will behave in an unstable way. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 697f154331e..22efb6a672c 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1113,6 +1113,23 @@ static void pn533_send_complete(struct urb *urb) } } +static void pn533_abort_cmd(struct pn533 *dev, gfp_t flags) +{ + /* ACR122U does not support any command which aborts last + * issued command i.e. as ACK for standard PN533. Additionally, + * it behaves stange, sending broken or incorrect responses, + * when we cancel urb before the chip will send response. + */ + if (dev->device_type == PN533_DEVICE_ACR122U) + return; + + /* An ack will cancel the last issued command */ + pn533_send_ack(dev, flags); + + /* cancel the urb request */ + usb_kill_urb(dev->in_urb); +} + static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size) { struct sk_buff *skb; @@ -1631,9 +1648,6 @@ static void pn533_listen_mode_timer(unsigned long data) nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout"); - /* An ack will cancel the last issued command (poll) */ - pn533_send_ack(dev, GFP_ATOMIC); - dev->cancel_listen = 1; pn533_poll_next_mod(dev); @@ -1763,7 +1777,7 @@ static void pn533_wq_poll(struct work_struct *work) if (dev->cancel_listen == 1) { dev->cancel_listen = 0; - usb_kill_urb(dev->in_urb); + pn533_abort_cmd(dev, GFP_ATOMIC); } rc = pn533_send_poll_frame(dev); @@ -1825,12 +1839,7 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev) return; } - /* An ack will cancel the last issued command (poll) */ - pn533_send_ack(dev, GFP_KERNEL); - - /* prevent pn533_start_poll_complete to issue a new poll meanwhile */ - usb_kill_urb(dev->in_urb); - + pn533_abort_cmd(dev, GFP_KERNEL); pn533_poll_reset_mod_list(dev); } @@ -2123,10 +2132,8 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev) pn533_poll_reset_mod_list(dev); - if (dev->tgt_mode || dev->tgt_active_prot) { - pn533_send_ack(dev, GFP_KERNEL); - usb_kill_urb(dev->in_urb); - } + if (dev->tgt_mode || dev->tgt_active_prot) + pn533_abort_cmd(dev, GFP_KERNEL); dev->tgt_active_prot = 0; dev->tgt_mode = 0; -- cgit v1.2.3-70-g09d2 From 96aac226a4cb19fde1bb3593fcbb8b2a86e7b0f5 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:15 +0200 Subject: NFC: pn533: Remove unused pn533_cmd_complete_t Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 22efb6a672c..32737a68e74 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -149,8 +149,6 @@ MODULE_DEVICE_TABLE(usb, pn533_table); struct pn533; -typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, int status); - typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg, struct sk_buff *resp); -- cgit v1.2.3-70-g09d2 From 495af72e1434724559e756ba32d9040125ac506b Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Wed, 3 Apr 2013 08:02:16 +0200 Subject: NFC: pn533: Increase version number Major features added in 0.2 version: * frame ops added to support wider set of devices * support of ACS ACR122U Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 32737a68e74..4d56ad4c8bf 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -27,7 +27,7 @@ #include #include -#define VERSION "0.1" +#define VERSION "0.2" #define PN533_VENDOR_ID 0x4CC #define PN533_PRODUCT_ID 0x2533 -- cgit v1.2.3-70-g09d2 From 7c5a54fb869d980c2a3c0972fe1e22816dd5b7b2 Mon Sep 17 00:00:00 2001 From: Marina Makienko Date: Tue, 26 Feb 2013 11:41:18 +0400 Subject: NFC: pn533: Add missing usb_put_dev Add missing usb_put_dev on failure path in pn533_probe(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Marina Makienko Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 4d56ad4c8bf..3569b9e621e 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -2779,6 +2779,7 @@ destroy_wq: error: usb_free_urb(dev->in_urb); usb_free_urb(dev->out_urb); + usb_put_dev(dev->udev); kfree(dev); return rc; } -- cgit v1.2.3-70-g09d2 From 60d9edd50b9b9c5b9cb434ebea7892057ae4b889 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 11 Apr 2013 11:45:41 +0200 Subject: NFC: pn533: Turn radio on and off when bringing the device up and down Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 3569b9e621e..8f6f2baa930 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -163,9 +163,13 @@ struct pn533_fw_version { }; /* PN533_CMD_RF_CONFIGURATION */ -#define PN533_CFGITEM_TIMING 0x02 +#define PN533_CFGITEM_RF_FIELD 0x01 +#define PN533_CFGITEM_TIMING 0x02 #define PN533_CFGITEM_MAX_RETRIES 0x05 -#define PN533_CFGITEM_PASORI 0x82 +#define PN533_CFGITEM_PASORI 0x82 + +#define PN533_CFGITEM_RF_FIELD_ON 0x1 +#define PN533_CFGITEM_RF_FIELD_OFF 0x0 #define PN533_CONFIG_TIMING_102 0xb #define PN533_CONFIG_TIMING_204 0xc @@ -2540,9 +2544,36 @@ static int pn533_acr122_poweron_rdr(struct pn533 *dev) return arg.rc; } +static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + u8 rf_field = !!rf; + int rc; + + rc = pn533_set_configuration(dev, PN533_CFGITEM_RF_FIELD, + (u8 *)&rf_field, 1); + if (rc) { + nfc_dev_err(&dev->interface->dev, + "Error on setting RF field"); + return rc; + } + + return rc; +} + +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) +{ + return pn533_rf_field(nfc_dev, 0); +} + static struct nfc_ops pn533_nfc_ops = { - .dev_up = NULL, - .dev_down = NULL, + .dev_up = pn533_dev_up, + .dev_down = pn533_dev_down, .dep_link_up = pn533_dep_link_up, .dep_link_down = pn533_dep_link_down, .start_poll = pn533_start_poll, -- cgit v1.2.3-70-g09d2 From 4912e2fe74811693703e9b4e21bf36c067643a03 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 15 Apr 2013 11:19:20 +0200 Subject: NFC: mei: Add a common mei bus API for NFC drivers This isolates the common code that is required to use an mei bus nfc device from an NFC HCI drivers. This prepares for future drivers for NFC chips connected behind an Intel Management Engine controller. The microread_mei HCI driver is also modified to use that common code. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- drivers/nfc/Kconfig | 10 +++ drivers/nfc/Makefile | 1 + drivers/nfc/mei_phy.c | 164 ++++++++++++++++++++++++++++++++++++++++++ drivers/nfc/mei_phy.h | 30 ++++++++ drivers/nfc/microread/Kconfig | 2 +- drivers/nfc/microread/mei.c | 139 +++-------------------------------- 6 files changed, 215 insertions(+), 131 deletions(-) create mode 100644 drivers/nfc/mei_phy.c create mode 100644 drivers/nfc/mei_phy.h (limited to 'drivers') diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index e57034971cc..4775d4e61b8 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -26,6 +26,16 @@ config NFC_WILINK Say Y here to compile support for Texas Instrument's NFC WiLink driver into the kernel or say M to compile it as module. +config NFC_MEI_PHY + tristate "MEI bus NFC device support" + depends on INTEL_MEI_BUS_NFC && NFC_HCI + help + This adds support to use an mei bus nfc device. Select this if you + will use an HCI NFC driver for an NFC chip connected behind an + Intel's Management Engine chip. + + If unsure, say N. + source "drivers/nfc/pn544/Kconfig" source "drivers/nfc/microread/Kconfig" diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index a189ada0926..aa6bd657ef4 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_NFC_PN544) += pn544/ obj-$(CONFIG_NFC_MICROREAD) += microread/ obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_WILINK) += nfcwilink.o +obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c new file mode 100644 index 00000000000..b8f8abc422f --- /dev/null +++ b/drivers/nfc/mei_phy.c @@ -0,0 +1,164 @@ +/* + * MEI Library for mei bus nfc device access + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include "mei_phy.h" + +struct mei_nfc_hdr { + u8 cmd; + u8 status; + u16 req_id; + u32 reserved; + u16 data_size; +} __attribute__((packed)); + +#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD) + +#define MEI_DUMP_SKB_IN(info, skb) \ +do { \ + pr_debug("%s:\n", info); \ + print_hex_dump_debug("mei in : ", DUMP_PREFIX_OFFSET, \ + 16, 1, (skb)->data, (skb)->len, false); \ +} while (0) + +#define MEI_DUMP_SKB_OUT(info, skb) \ +do { \ + pr_debug("%s:\n", info); \ + print_hex_dump_debug("mei out: ", DUMP_PREFIX_OFFSET, \ + 16, 1, (skb)->data, (skb)->len, false); \ +} while (0) + +int nfc_mei_phy_enable(void *phy_id) +{ + int r; + struct nfc_mei_phy *phy = phy_id; + + pr_info("%s\n", __func__); + + if (phy->powered == 1) + return 0; + + r = mei_cl_enable_device(phy->device); + if (r < 0) { + pr_err("MEI_PHY: Could not enable device\n"); + return r; + } + + phy->powered = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(nfc_mei_phy_enable); + +void nfc_mei_phy_disable(void *phy_id) +{ + struct nfc_mei_phy *phy = phy_id; + + pr_info("%s\n", __func__); + + mei_cl_disable_device(phy->device); + + phy->powered = 0; +} +EXPORT_SYMBOL_GPL(nfc_mei_phy_disable); + +/* + * Writing a frame must not return the number of written bytes. + * It must return either zero for success, or <0 for error. + * In addition, it must not alter the skb + */ +static int nfc_mei_phy_write(void *phy_id, struct sk_buff *skb) +{ + struct nfc_mei_phy *phy = phy_id; + int r; + + MEI_DUMP_SKB_OUT("mei frame sent", skb); + + r = mei_cl_send(phy->device, skb->data, skb->len); + if (r > 0) + r = 0; + + return r; +} + +void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context) +{ + struct nfc_mei_phy *phy = context; + + if (phy->hard_fault != 0) + return; + + if (events & BIT(MEI_CL_EVENT_RX)) { + struct sk_buff *skb; + int reply_size; + + skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL); + if (!skb) + return; + + reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ); + if (reply_size < MEI_NFC_HEADER_SIZE) { + kfree(skb); + return; + } + + skb_put(skb, reply_size); + skb_pull(skb, MEI_NFC_HEADER_SIZE); + + MEI_DUMP_SKB_IN("mei frame read", skb); + + nfc_hci_recv_frame(phy->hdev, skb); + } +} +EXPORT_SYMBOL_GPL(nfc_mei_event_cb); + +struct nfc_phy_ops mei_phy_ops = { + .write = nfc_mei_phy_write, + .enable = nfc_mei_phy_enable, + .disable = nfc_mei_phy_disable, +}; +EXPORT_SYMBOL_GPL(mei_phy_ops); + +struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device) +{ + struct nfc_mei_phy *phy; + + phy = kzalloc(sizeof(struct nfc_mei_phy), GFP_KERNEL); + if (!phy) + return NULL; + + phy->device = device; + mei_cl_set_drvdata(device, phy); + + return phy; +} +EXPORT_SYMBOL_GPL(nfc_mei_phy_alloc); + +void nfc_mei_phy_free(struct nfc_mei_phy *phy) +{ + kfree(phy); +} +EXPORT_SYMBOL_GPL(nfc_mei_phy_free); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("mei bus NFC device interface"); diff --git a/drivers/nfc/mei_phy.h b/drivers/nfc/mei_phy.h new file mode 100644 index 00000000000..d669900f827 --- /dev/null +++ b/drivers/nfc/mei_phy.h @@ -0,0 +1,30 @@ +#ifndef __LOCAL_MEI_PHY_H_ +#define __LOCAL_MEI_PHY_H_ + +#include +#include + +#define MEI_NFC_HEADER_SIZE 10 +#define MEI_NFC_MAX_HCI_PAYLOAD 300 + +struct nfc_mei_phy { + struct mei_cl_device *device; + struct nfc_hci_dev *hdev; + + int powered; + + int hard_fault; /* + * < 0 if hardware error occured + * and prevents normal operation. + */ +}; + +extern struct nfc_phy_ops mei_phy_ops; + +int nfc_mei_phy_enable(void *phy_id); +void nfc_mei_phy_disable(void *phy_id); +void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context); +struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device); +void nfc_mei_phy_free(struct nfc_mei_phy *phy); + +#endif /* __LOCAL_MEI_PHY_H_ */ diff --git a/drivers/nfc/microread/Kconfig b/drivers/nfc/microread/Kconfig index 572305be6e3..951d5542f6b 100644 --- a/drivers/nfc/microread/Kconfig +++ b/drivers/nfc/microread/Kconfig @@ -25,7 +25,7 @@ config NFC_MICROREAD_I2C config NFC_MICROREAD_MEI tristate "NFC Microread MEI support" - depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC + depends on NFC_MICROREAD && NFC_MEI_PHY ---help--- This module adds support for the mei interface of adapters using Inside microread chipsets. Select this if your microread chipset diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c index ca33ae19393..1ad044dce7b 100644 --- a/drivers/nfc/microread/mei.c +++ b/drivers/nfc/microread/mei.c @@ -19,151 +19,31 @@ */ #include -#include -#include -#include -#include - +#include #include #include #include +#include "../mei_phy.h" #include "microread.h" #define MICROREAD_DRIVER_NAME "microread" -struct mei_nfc_hdr { - u8 cmd; - u8 status; - u16 req_id; - u32 reserved; - u16 data_size; -} __attribute__((packed)); - -#define MEI_NFC_HEADER_SIZE 10 -#define MEI_NFC_MAX_HCI_PAYLOAD 300 -#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD) - -struct microread_mei_phy { - struct mei_cl_device *device; - struct nfc_hci_dev *hdev; - - int powered; - - int hard_fault; /* - * < 0 if hardware error occured (e.g. i2c err) - * and prevents normal operation. - */ -}; - -#define MEI_DUMP_SKB_IN(info, skb) \ -do { \ - pr_debug("%s:\n", info); \ - print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET, \ - 16, 1, (skb)->data, (skb)->len, 0); \ -} while (0) - -#define MEI_DUMP_SKB_OUT(info, skb) \ -do { \ - pr_debug("%s:\n", info); \ - print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET, \ - 16, 1, (skb)->data, (skb)->len, 0); \ -} while (0) - -static int microread_mei_enable(void *phy_id) -{ - struct microread_mei_phy *phy = phy_id; - - pr_info(DRIVER_DESC ": %s\n", __func__); - - phy->powered = 1; - - return 0; -} - -static void microread_mei_disable(void *phy_id) -{ - struct microread_mei_phy *phy = phy_id; - - pr_info(DRIVER_DESC ": %s\n", __func__); - - phy->powered = 0; -} - -/* - * Writing a frame must not return the number of written bytes. - * It must return either zero for success, or <0 for error. - * In addition, it must not alter the skb - */ -static int microread_mei_write(void *phy_id, struct sk_buff *skb) -{ - struct microread_mei_phy *phy = phy_id; - int r; - - MEI_DUMP_SKB_OUT("mei frame sent", skb); - - r = mei_cl_send(phy->device, skb->data, skb->len); - if (r > 0) - r = 0; - - return r; -} - -static void microread_event_cb(struct mei_cl_device *device, u32 events, - void *context) -{ - struct microread_mei_phy *phy = context; - - if (phy->hard_fault != 0) - return; - - if (events & BIT(MEI_CL_EVENT_RX)) { - struct sk_buff *skb; - int reply_size; - - skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL); - if (!skb) - return; - - reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ); - if (reply_size < MEI_NFC_HEADER_SIZE) { - kfree(skb); - return; - } - - skb_put(skb, reply_size); - skb_pull(skb, MEI_NFC_HEADER_SIZE); - - MEI_DUMP_SKB_IN("mei frame read", skb); - - nfc_hci_recv_frame(phy->hdev, skb); - } -} - -static struct nfc_phy_ops mei_phy_ops = { - .write = microread_mei_write, - .enable = microread_mei_enable, - .disable = microread_mei_disable, -}; - static int microread_mei_probe(struct mei_cl_device *device, const struct mei_cl_device_id *id) { - struct microread_mei_phy *phy; + struct nfc_mei_phy *phy; int r; pr_info("Probing NFC microread\n"); - phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL); + phy = nfc_mei_phy_alloc(device); if (!phy) { pr_err("Cannot allocate memory for microread mei phy.\n"); return -ENOMEM; } - phy->device = device; - mei_cl_set_drvdata(device, phy); - - r = mei_cl_register_event_cb(device, microread_event_cb, phy); + r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy); if (r) { pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n"); goto err_out; @@ -178,23 +58,22 @@ static int microread_mei_probe(struct mei_cl_device *device, return 0; err_out: - kfree(phy); + nfc_mei_phy_free(phy); return r; } static int microread_mei_remove(struct mei_cl_device *device) { - struct microread_mei_phy *phy = mei_cl_get_drvdata(device); + struct nfc_mei_phy *phy = mei_cl_get_drvdata(device); pr_info("Removing microread\n"); microread_remove(phy->hdev); - if (phy->powered) - microread_mei_disable(phy); + nfc_mei_phy_disable(phy); - kfree(phy); + nfc_mei_phy_free(phy); return 0; } -- cgit v1.2.3-70-g09d2 From bb03dceb83852614ae3ad6b3731a31422890b0b9 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 16 Apr 2013 00:14:35 +0200 Subject: NFC: pn544: Add MEI physical layer With the new mei_phy NFC driver API, the pn544 MEI physical layer is minimal and similar to the microread one. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544/Kconfig | 13 ++++- drivers/nfc/pn544/Makefile | 2 + drivers/nfc/pn544/mei.c | 121 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 drivers/nfc/pn544/mei.c (limited to 'drivers') diff --git a/drivers/nfc/pn544/Kconfig b/drivers/nfc/pn544/Kconfig index c277790ac71..ccf06f5f6eb 100644 --- a/drivers/nfc/pn544/Kconfig +++ b/drivers/nfc/pn544/Kconfig @@ -20,4 +20,15 @@ config NFC_PN544_I2C Select this if your platform is using the i2c bus. If you choose to build a module, it'll be called pn544_i2c. - Say N if unsure. \ No newline at end of file + Say N if unsure. + +config NFC_PN544_MEI + tristate "NFC PN544 MEI support" + depends on NFC_PN544 && NFC_MEI_PHY + ---help--- + This module adds support for the mei interface of adapters using + NXP pn544 chipsets. Select this if your pn544 chipset + is handled by Intel's Management Engine Interface on your platform. + + If you choose to build a module, it'll be called pn544_mei. + Say N if unsure. diff --git a/drivers/nfc/pn544/Makefile b/drivers/nfc/pn544/Makefile index ac076793687..29fb5a17403 100644 --- a/drivers/nfc/pn544/Makefile +++ b/drivers/nfc/pn544/Makefile @@ -3,6 +3,8 @@ # pn544_i2c-objs = i2c.o +pn544_mei-objs = mei.o obj-$(CONFIG_NFC_PN544) += pn544.o obj-$(CONFIG_NFC_PN544_I2C) += pn544_i2c.o +obj-$(CONFIG_NFC_PN544_MEI) += pn544_mei.o diff --git a/drivers/nfc/pn544/mei.c b/drivers/nfc/pn544/mei.c new file mode 100644 index 00000000000..1eb48848a35 --- /dev/null +++ b/drivers/nfc/pn544/mei.c @@ -0,0 +1,121 @@ +/* + * HCI based Driver for NXP pn544 NFC Chip + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include "../mei_phy.h" +#include "pn544.h" + +#define PN544_DRIVER_NAME "pn544" + +static int pn544_mei_probe(struct mei_cl_device *device, + const struct mei_cl_device_id *id) +{ + struct nfc_mei_phy *phy; + int r; + + pr_info("Probing NFC pn544\n"); + + phy = nfc_mei_phy_alloc(device); + if (!phy) { + pr_err("Cannot allocate memory for pn544 mei phy.\n"); + return -ENOMEM; + } + + r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy); + if (r) { + pr_err(PN544_DRIVER_NAME ": event cb registration failed\n"); + goto err_out; + } + + r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME, + MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, + &phy->hdev); + if (r < 0) + goto err_out; + + return 0; + +err_out: + nfc_mei_phy_free(phy); + + return r; +} + +static int pn544_mei_remove(struct mei_cl_device *device) +{ + struct nfc_mei_phy *phy = mei_cl_get_drvdata(device); + + pr_info("Removing pn544\n"); + + pn544_hci_remove(phy->hdev); + + nfc_mei_phy_disable(phy); + + nfc_mei_phy_free(phy); + + return 0; +} + +static struct mei_cl_device_id pn544_mei_tbl[] = { + { PN544_DRIVER_NAME }, + + /* required last entry */ + { } +}; +MODULE_DEVICE_TABLE(mei, pn544_mei_tbl); + +static struct mei_cl_driver pn544_driver = { + .id_table = pn544_mei_tbl, + .name = PN544_DRIVER_NAME, + + .probe = pn544_mei_probe, + .remove = pn544_mei_remove, +}; + +static int pn544_mei_init(void) +{ + int r; + + pr_debug(DRIVER_DESC ": %s\n", __func__); + + r = mei_cl_driver_register(&pn544_driver); + if (r) { + pr_err(PN544_DRIVER_NAME ": driver registration failed\n"); + return r; + } + + return 0; +} + +static void pn544_mei_exit(void) +{ + mei_cl_driver_unregister(&pn544_driver); +} + +module_init(pn544_mei_init); +module_exit(pn544_mei_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); -- cgit v1.2.3-70-g09d2