Commit 74ea1f45 authored by John W. Linville's avatar John W. Linville

Merge tag 'nfc-next-3.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next

Samuel Ortiz <sameo@linux.intel.com> says:

"This is the first NFC pull request for the 3.12 release.

With this one we have:

- A few pn533 improvements and minor fixes. Testing our pn533 driver
  against Google's NCI stack triggered a few issues that we fixed now.
  We also added Tx fragmentation support to this driver.

- More NFC secure element handling. We added a GET_SE netlink command
  for getting all the discovered secure elements, and we defined 2
  additional secure element netlink event (transaction and connectivity).
  We also fixed a couple of typos and copy-paste bugs from the secure
  element handling code.

- Firmware download support for the pn544 driver. This chipset can enter a
  special mode where it's waiting for firmware blobs to replace the
  already flashed one. We now support that mode."
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parents 946951e1 39525ee1
...@@ -5791,7 +5791,7 @@ M: Aloisio Almeida Jr <aloisio.almeida@openbossa.org> ...@@ -5791,7 +5791,7 @@ M: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
M: Samuel Ortiz <sameo@linux.intel.com> M: Samuel Ortiz <sameo@linux.intel.com>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
L: linux-nfc@lists.01.org (moderated for non-subscribers) L: linux-nfc@lists.01.org (moderated for non-subscribers)
S: Maintained S: Supported
F: net/nfc/ F: net/nfc/
F: include/net/nfc/ F: include/net/nfc/
F: include/uapi/linux/nfc.h F: include/uapi/linux/nfc.h
......
...@@ -60,7 +60,7 @@ struct nfcsim { ...@@ -60,7 +60,7 @@ struct nfcsim {
static struct nfcsim *dev0; static struct nfcsim *dev0;
static struct nfcsim *dev1; static struct nfcsim *dev1;
struct workqueue_struct *wq; static struct workqueue_struct *wq;
static void nfcsim_cleanup_dev(struct nfcsim *dev, u8 shutdown) static void nfcsim_cleanup_dev(struct nfcsim *dev, u8 shutdown)
{ {
...@@ -481,7 +481,7 @@ static void nfcsim_free_device(struct nfcsim *dev) ...@@ -481,7 +481,7 @@ static void nfcsim_free_device(struct nfcsim *dev)
kfree(dev); kfree(dev);
} }
int __init nfcsim_init(void) static int __init nfcsim_init(void)
{ {
int rc; int rc;
...@@ -522,7 +522,7 @@ int __init nfcsim_init(void) ...@@ -522,7 +522,7 @@ int __init nfcsim_init(void)
return rc; return rc;
} }
void __exit nfcsim_exit(void) static void __exit nfcsim_exit(void)
{ {
nfcsim_cleanup_dev(dev0, 1); nfcsim_cleanup_dev(dev0, 1);
nfcsim_cleanup_dev(dev1, 1); nfcsim_cleanup_dev(dev1, 1);
......
...@@ -83,12 +83,20 @@ MODULE_DEVICE_TABLE(usb, pn533_table); ...@@ -83,12 +83,20 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
/* How much time we spend listening for initiators */ /* How much time we spend listening for initiators */
#define PN533_LISTEN_TIME 2 #define PN533_LISTEN_TIME 2
/* Delay between each poll frame (ms) */
#define PN533_POLL_INTERVAL 10
/* Standard pn533 frame definitions */ /* Standard pn533 frame definitions (standard and extended)*/
#define PN533_STD_FRAME_HEADER_LEN (sizeof(struct pn533_std_frame) \ #define PN533_STD_FRAME_HEADER_LEN (sizeof(struct pn533_std_frame) \
+ 2) /* data[0] TFI, data[1] CC */ + 2) /* data[0] TFI, data[1] CC */
#define PN533_STD_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*/
#define PN533_EXT_FRAME_HEADER_LEN (sizeof(struct pn533_ext_frame) \
+ 2) /* data[0] TFI, data[1] CC */
#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
#define PN533_CMD_DATAFRAME_MAXLEN 240 /* max data length (send) */
/* /*
* Max extended frame payload len, excluding TFI and CC * Max extended frame payload len, excluding TFI and CC
* which are already in PN533_FRAME_HEADER_LEN. * which are already in PN533_FRAME_HEADER_LEN.
...@@ -99,6 +107,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table); ...@@ -99,6 +107,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
Postamble (1) */ Postamble (1) */
#define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen]) #define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen])
#define PN533_STD_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1]) #define PN533_STD_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
/* Half start code (3), LEN (4) should be 0xffff for extended frame */
#define PN533_STD_IS_EXTENDED(hdr) ((hdr)->datalen == 0xFF \
&& (hdr)->datalen_checksum == 0xFF)
#define PN533_EXT_FRAME_CHECKSUM(f) (f->data[be16_to_cpu(f->datalen)])
/* start of frame */ /* start of frame */
#define PN533_STD_FRAME_SOF 0x00FF #define PN533_STD_FRAME_SOF 0x00FF
...@@ -124,7 +136,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table); ...@@ -124,7 +136,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83 #define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83
/* PN533 Commands */ /* PN533 Commands */
#define PN533_STD_FRAME_CMD(f) (f->data[1]) #define PN533_FRAME_CMD(f) (f->data[1])
#define PN533_CMD_GET_FIRMWARE_VERSION 0x02 #define PN533_CMD_GET_FIRMWARE_VERSION 0x02
#define PN533_CMD_RF_CONFIGURATION 0x32 #define PN533_CMD_RF_CONFIGURATION 0x32
...@@ -168,8 +180,9 @@ struct pn533_fw_version { ...@@ -168,8 +180,9 @@ struct pn533_fw_version {
#define PN533_CFGITEM_MAX_RETRIES 0x05 #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_AUTO_RFCA 0x2
#define PN533_CFGITEM_RF_FIELD_OFF 0x0 #define PN533_CFGITEM_RF_FIELD_ON 0x1
#define PN533_CFGITEM_RF_FIELD_OFF 0x0
#define PN533_CONFIG_TIMING_102 0xb #define PN533_CONFIG_TIMING_102 0xb
#define PN533_CONFIG_TIMING_204 0xc #define PN533_CONFIG_TIMING_204 0xc
...@@ -257,7 +270,7 @@ static const struct pn533_poll_modulations poll_mod[] = { ...@@ -257,7 +270,7 @@ static const struct pn533_poll_modulations poll_mod[] = {
.initiator_data.felica = { .initiator_data.felica = {
.opcode = PN533_FELICA_OPC_SENSF_REQ, .opcode = PN533_FELICA_OPC_SENSF_REQ,
.sc = PN533_FELICA_SENSF_SC_ALL, .sc = PN533_FELICA_SENSF_SC_ALL,
.rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE, .rc = PN533_FELICA_SENSF_RC_SYSTEM_CODE,
.tsn = 0x03, .tsn = 0x03,
}, },
}, },
...@@ -270,7 +283,7 @@ static const struct pn533_poll_modulations poll_mod[] = { ...@@ -270,7 +283,7 @@ static const struct pn533_poll_modulations poll_mod[] = {
.initiator_data.felica = { .initiator_data.felica = {
.opcode = PN533_FELICA_OPC_SENSF_REQ, .opcode = PN533_FELICA_OPC_SENSF_REQ,
.sc = PN533_FELICA_SENSF_SC_ALL, .sc = PN533_FELICA_SENSF_SC_ALL,
.rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE, .rc = PN533_FELICA_SENSF_RC_SYSTEM_CODE,
.tsn = 0x03, .tsn = 0x03,
}, },
}, },
...@@ -352,13 +365,16 @@ struct pn533 { ...@@ -352,13 +365,16 @@ struct pn533 {
struct urb *in_urb; struct urb *in_urb;
struct sk_buff_head resp_q; struct sk_buff_head resp_q;
struct sk_buff_head fragment_skb;
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct work_struct cmd_work; struct work_struct cmd_work;
struct work_struct cmd_complete_work; struct work_struct cmd_complete_work;
struct work_struct poll_work; struct delayed_work poll_work;
struct work_struct mi_work; struct work_struct mi_rx_work;
struct work_struct mi_tx_work;
struct work_struct tg_work; struct work_struct tg_work;
struct work_struct rf_work;
struct list_head cmd_queue; struct list_head cmd_queue;
struct pn533_cmd *cmd; struct pn533_cmd *cmd;
...@@ -366,6 +382,7 @@ struct pn533 { ...@@ -366,6 +382,7 @@ struct pn533 {
struct mutex cmd_lock; /* protects cmd queue */ struct mutex cmd_lock; /* protects cmd queue */
void *cmd_complete_mi_arg; void *cmd_complete_mi_arg;
void *cmd_complete_dep_arg;
struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1]; struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
u8 poll_mod_count; u8 poll_mod_count;
...@@ -404,6 +421,15 @@ struct pn533_std_frame { ...@@ -404,6 +421,15 @@ struct pn533_std_frame {
u8 data[]; u8 data[];
} __packed; } __packed;
struct pn533_ext_frame { /* Extended Information frame */
u8 preamble;
__be16 start_frame;
__be16 eif_flag; /* fixed to 0xFFFF */
__be16 datalen;
u8 datalen_checksum;
u8 data[];
} __packed;
struct pn533_frame_ops { struct pn533_frame_ops {
void (*tx_frame_init)(void *frame, u8 cmd_code); void (*tx_frame_init)(void *frame, u8 cmd_code);
void (*tx_frame_finish)(void *frame); void (*tx_frame_finish)(void *frame);
...@@ -411,7 +437,7 @@ struct pn533_frame_ops { ...@@ -411,7 +437,7 @@ struct pn533_frame_ops {
int tx_header_len; int tx_header_len;
int tx_tail_len; int tx_tail_len;
bool (*rx_is_frame_valid)(void *frame); bool (*rx_is_frame_valid)(void *frame, struct pn533 *dev);
int (*rx_frame_size)(void *frame); int (*rx_frame_size)(void *frame);
int rx_header_len; int rx_header_len;
int rx_tail_len; int rx_tail_len;
...@@ -486,7 +512,7 @@ static void pn533_acr122_tx_update_payload_len(void *_frame, int len) ...@@ -486,7 +512,7 @@ static void pn533_acr122_tx_update_payload_len(void *_frame, int len)
frame->datalen += len; frame->datalen += len;
} }
static bool pn533_acr122_is_rx_frame_valid(void *_frame) static bool pn533_acr122_is_rx_frame_valid(void *_frame, struct pn533 *dev)
{ {
struct pn533_acr122_rx_frame *frame = _frame; struct pn533_acr122_rx_frame *frame = _frame;
...@@ -511,7 +537,7 @@ static u8 pn533_acr122_get_cmd_code(void *frame) ...@@ -511,7 +537,7 @@ static u8 pn533_acr122_get_cmd_code(void *frame)
{ {
struct pn533_acr122_rx_frame *f = frame; struct pn533_acr122_rx_frame *f = frame;
return PN533_STD_FRAME_CMD(f); return PN533_FRAME_CMD(f);
} }
static struct pn533_frame_ops pn533_acr122_frame_ops = { static struct pn533_frame_ops pn533_acr122_frame_ops = {
...@@ -530,6 +556,12 @@ static struct pn533_frame_ops pn533_acr122_frame_ops = { ...@@ -530,6 +556,12 @@ static struct pn533_frame_ops pn533_acr122_frame_ops = {
.get_cmd_code = pn533_acr122_get_cmd_code, .get_cmd_code = pn533_acr122_get_cmd_code,
}; };
/* The rule: value(high byte) + value(low byte) + checksum = 0 */
static inline u8 pn533_ext_checksum(u16 value)
{
return ~(u8)(((value & 0xFF00) >> 8) + (u8)(value & 0xFF)) + 1;
}
/* The rule: value + checksum = 0 */ /* The rule: value + checksum = 0 */
static inline u8 pn533_std_checksum(u8 value) static inline u8 pn533_std_checksum(u8 value)
{ {
...@@ -555,7 +587,7 @@ static void pn533_std_tx_frame_init(void *_frame, u8 cmd_code) ...@@ -555,7 +587,7 @@ static void pn533_std_tx_frame_init(void *_frame, u8 cmd_code)
frame->preamble = 0; frame->preamble = 0;
frame->start_frame = cpu_to_be16(PN533_STD_FRAME_SOF); frame->start_frame = cpu_to_be16(PN533_STD_FRAME_SOF);
PN533_STD_FRAME_IDENTIFIER(frame) = PN533_STD_FRAME_DIR_OUT; PN533_STD_FRAME_IDENTIFIER(frame) = PN533_STD_FRAME_DIR_OUT;
PN533_STD_FRAME_CMD(frame) = cmd_code; PN533_FRAME_CMD(frame) = cmd_code;
frame->datalen = 2; frame->datalen = 2;
} }
...@@ -578,21 +610,41 @@ static void pn533_std_tx_update_payload_len(void *_frame, int len) ...@@ -578,21 +610,41 @@ static void pn533_std_tx_update_payload_len(void *_frame, int len)
frame->datalen += len; frame->datalen += len;
} }
static bool pn533_std_rx_frame_is_valid(void *_frame) static bool pn533_std_rx_frame_is_valid(void *_frame, struct pn533 *dev)
{ {
u8 checksum; u8 checksum;
struct pn533_std_frame *frame = _frame; struct pn533_std_frame *stdf = _frame;
if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF)) if (stdf->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF))
return false; return false;
checksum = pn533_std_checksum(frame->datalen); if (likely(!PN533_STD_IS_EXTENDED(stdf))) {
if (checksum != frame->datalen_checksum) /* Standard frame code */
return false; dev->ops->rx_header_len = PN533_STD_FRAME_HEADER_LEN;
checksum = pn533_std_data_checksum(frame->data, frame->datalen); checksum = pn533_std_checksum(stdf->datalen);
if (checksum != PN533_STD_FRAME_CHECKSUM(frame)) if (checksum != stdf->datalen_checksum)
return false; return false;
checksum = pn533_std_data_checksum(stdf->data, stdf->datalen);
if (checksum != PN533_STD_FRAME_CHECKSUM(stdf))
return false;
} else {
/* Extended */
struct pn533_ext_frame *eif = _frame;
dev->ops->rx_header_len = PN533_EXT_FRAME_HEADER_LEN;
checksum = pn533_ext_checksum(be16_to_cpu(eif->datalen));
if (checksum != eif->datalen_checksum)
return false;
/* check data checksum */
checksum = pn533_std_data_checksum(eif->data,
be16_to_cpu(eif->datalen));
if (checksum != PN533_EXT_FRAME_CHECKSUM(eif))
return false;
}
return true; return true;
} }
...@@ -612,6 +664,14 @@ static inline int pn533_std_rx_frame_size(void *frame) ...@@ -612,6 +664,14 @@ static inline int pn533_std_rx_frame_size(void *frame)
{ {
struct pn533_std_frame *f = frame; struct pn533_std_frame *f = frame;
/* check for Extended Information frame */
if (PN533_STD_IS_EXTENDED(f)) {
struct pn533_ext_frame *eif = frame;
return sizeof(struct pn533_ext_frame)
+ be16_to_cpu(eif->datalen) + PN533_STD_FRAME_TAIL_LEN;
}
return sizeof(struct pn533_std_frame) + f->datalen + return sizeof(struct pn533_std_frame) + f->datalen +
PN533_STD_FRAME_TAIL_LEN; PN533_STD_FRAME_TAIL_LEN;
} }
...@@ -619,8 +679,12 @@ static inline int pn533_std_rx_frame_size(void *frame) ...@@ -619,8 +679,12 @@ static inline int pn533_std_rx_frame_size(void *frame)
static u8 pn533_std_get_cmd_code(void *frame) static u8 pn533_std_get_cmd_code(void *frame)
{ {
struct pn533_std_frame *f = frame; struct pn533_std_frame *f = frame;
struct pn533_ext_frame *eif = frame;
return PN533_STD_FRAME_CMD(f); if (PN533_STD_IS_EXTENDED(f))
return PN533_FRAME_CMD(eif);
else
return PN533_FRAME_CMD(f);
} }
static struct pn533_frame_ops pn533_std_frame_ops = { static struct pn533_frame_ops pn533_std_frame_ops = {
...@@ -675,7 +739,7 @@ static void pn533_recv_response(struct urb *urb) ...@@ -675,7 +739,7 @@ static void pn533_recv_response(struct urb *urb)
print_hex_dump_debug("PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, in_frame, print_hex_dump_debug("PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, in_frame,
dev->ops->rx_frame_size(in_frame), false); dev->ops->rx_frame_size(in_frame), false);
if (!dev->ops->rx_is_frame_valid(in_frame)) { if (!dev->ops->rx_is_frame_valid(in_frame, dev)) {
nfc_dev_err(&dev->interface->dev, "Received an invalid frame"); nfc_dev_err(&dev->interface->dev, "Received an invalid frame");
cmd->status = -EIO; cmd->status = -EIO;
goto sched_wq; goto sched_wq;
...@@ -1657,7 +1721,56 @@ static void pn533_listen_mode_timer(unsigned long data) ...@@ -1657,7 +1721,56 @@ static void pn533_listen_mode_timer(unsigned long data)
pn533_poll_next_mod(dev); pn533_poll_next_mod(dev);
queue_work(dev->wq, &dev->poll_work); queue_delayed_work(dev->wq, &dev->poll_work,
msecs_to_jiffies(PN533_POLL_INTERVAL));
}
static int pn533_rf_complete(struct pn533 *dev, void *arg,
struct sk_buff *resp)
{
int rc = 0;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
if (IS_ERR(resp)) {
rc = PTR_ERR(resp);
nfc_dev_err(&dev->interface->dev, "%s RF setting error %d",
__func__, rc);
return rc;
}
queue_delayed_work(dev->wq, &dev->poll_work,
msecs_to_jiffies(PN533_POLL_INTERVAL));
dev_kfree_skb(resp);
return rc;
}
static void pn533_wq_rf(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, rf_work);
struct sk_buff *skb;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
skb = pn533_alloc_skb(dev, 2);
if (!skb)
return;
*skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD;
*skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD_AUTO_RFCA;
rc = pn533_send_cmd_async(dev, PN533_CMD_RF_CONFIGURATION, skb,
pn533_rf_complete, NULL);
if (rc < 0) {
dev_kfree_skb(skb);
nfc_dev_err(&dev->interface->dev, "RF setting error %d", rc);
}
return;
} }
static int pn533_poll_complete(struct pn533 *dev, void *arg, static int pn533_poll_complete(struct pn533 *dev, void *arg,
...@@ -1705,7 +1818,8 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg, ...@@ -1705,7 +1818,8 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,
} }
pn533_poll_next_mod(dev); pn533_poll_next_mod(dev);
queue_work(dev->wq, &dev->poll_work); /* Not target found, turn radio off */
queue_work(dev->wq, &dev->rf_work);
done: done:
dev_kfree_skb(resp); dev_kfree_skb(resp);
...@@ -1770,7 +1884,7 @@ static int pn533_send_poll_frame(struct pn533 *dev) ...@@ -1770,7 +1884,7 @@ static int pn533_send_poll_frame(struct pn533 *dev)
static void pn533_wq_poll(struct work_struct *work) static void pn533_wq_poll(struct work_struct *work)
{ {
struct pn533 *dev = container_of(work, struct pn533, poll_work); struct pn533 *dev = container_of(work, struct pn533, poll_work.work);
struct pn533_poll_modulations *cur_mod; struct pn533_poll_modulations *cur_mod;
int rc; int rc;
...@@ -1799,6 +1913,7 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev, ...@@ -1799,6 +1913,7 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev,
u32 im_protocols, u32 tm_protocols) u32 im_protocols, u32 tm_protocols)
{ {
struct pn533 *dev = nfc_get_drvdata(nfc_dev); struct pn533 *dev = nfc_get_drvdata(nfc_dev);
u8 rand_mod;
nfc_dev_dbg(&dev->interface->dev, nfc_dev_dbg(&dev->interface->dev,
"%s: im protocols 0x%x tm protocols 0x%x", "%s: im protocols 0x%x tm protocols 0x%x",
...@@ -1822,11 +1937,15 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev, ...@@ -1822,11 +1937,15 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev,
tm_protocols = 0; tm_protocols = 0;
} }
dev->poll_mod_curr = 0;
pn533_poll_create_mod_list(dev, im_protocols, tm_protocols); pn533_poll_create_mod_list(dev, im_protocols, tm_protocols);
dev->poll_protocols = im_protocols; dev->poll_protocols = im_protocols;
dev->listen_protocols = tm_protocols; dev->listen_protocols = tm_protocols;
/* Do not always start polling from the same modulation */
get_random_bytes(&rand_mod, sizeof(rand_mod));
rand_mod %= dev->poll_mod_count;
dev->poll_mod_curr = rand_mod;
return pn533_send_poll_frame(dev); return pn533_send_poll_frame(dev);
} }
...@@ -1845,6 +1964,7 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev) ...@@ -1845,6 +1964,7 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
} }
pn533_abort_cmd(dev, GFP_KERNEL); pn533_abort_cmd(dev, GFP_KERNEL);
flush_delayed_work(&dev->poll_work);
pn533_poll_reset_mod_list(dev); pn533_poll_reset_mod_list(dev);
} }
...@@ -2037,28 +2157,15 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, ...@@ -2037,28 +2157,15 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
return rc; return rc;
} }
static int pn533_mod_to_baud(struct pn533 *dev) static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf);
{
switch (dev->poll_mod_curr) {
case PN533_POLL_MOD_106KBPS_A:
return 0;
case PN533_POLL_MOD_212KBPS_FELICA:
return 1;
case PN533_POLL_MOD_424KBPS_FELICA:
return 2;
default:
return -EINVAL;
}
}
#define PASSIVE_DATA_LEN 5 #define PASSIVE_DATA_LEN 5
static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
u8 comm_mode, u8 *gb, size_t gb_len) u8 comm_mode, u8 *gb, size_t gb_len)
{ {
struct pn533 *dev = nfc_get_drvdata(nfc_dev); struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct sk_buff *skb; struct sk_buff *skb;
int rc, baud, skb_len; int rc, skb_len;
u8 *next, *arg; u8 *next, *arg, nfcid3[NFC_NFCID3_MAXSIZE];
u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3}; u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
...@@ -2076,41 +2183,39 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, ...@@ -2076,41 +2183,39 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
return -EBUSY; return -EBUSY;
} }
baud = pn533_mod_to_baud(dev);
if (baud < 0) {
nfc_dev_err(&dev->interface->dev,
"Invalid curr modulation %d", dev->poll_mod_curr);
return baud;
}
skb_len = 3 + gb_len; /* ActPass + BR + Next */ skb_len = 3 + gb_len; /* ActPass + BR + Next */
if (comm_mode == NFC_COMM_PASSIVE) skb_len += PASSIVE_DATA_LEN;
skb_len += PASSIVE_DATA_LEN;
if (target && target->nfcid2_len) /* NFCID3 */
skb_len += NFC_NFCID3_MAXSIZE; skb_len += NFC_NFCID3_MAXSIZE;
if (target && !target->nfcid2_len) {
nfcid3[0] = 0x1;
nfcid3[1] = 0xfe;
get_random_bytes(nfcid3 + 2, 6);
}
skb = pn533_alloc_skb(dev, skb_len); skb = pn533_alloc_skb(dev, skb_len);
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
*skb_put(skb, 1) = !comm_mode; /* ActPass */ *skb_put(skb, 1) = !comm_mode; /* ActPass */
*skb_put(skb, 1) = baud; /* Baud rate */ *skb_put(skb, 1) = 0x02; /* 424 kbps */
next = skb_put(skb, 1); /* Next */ next = skb_put(skb, 1); /* Next */
*next = 0; *next = 0;
if (comm_mode == NFC_COMM_PASSIVE && baud > 0) { /* Copy passive data */
memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, PASSIVE_DATA_LEN);
PASSIVE_DATA_LEN); *next |= 1;
*next |= 1;
}
if (target && target->nfcid2_len) { /* Copy NFCID3 (which is NFCID2 from SENSF_RES) */
if (target && target->nfcid2_len)
memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), target->nfcid2, memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), target->nfcid2,
target->nfcid2_len); target->nfcid2_len);
*next |= 2; else
} memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), nfcid3,
NFC_NFCID3_MAXSIZE);
*next |= 2;
if (gb != NULL && gb_len > 0) { if (gb != NULL && gb_len > 0) {
memcpy(skb_put(skb, gb_len), gb, gb_len); memcpy(skb_put(skb, gb_len), gb, gb_len);
...@@ -2127,6 +2232,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, ...@@ -2127,6 +2232,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
*arg = !comm_mode; *arg = !comm_mode;
pn533_rf_field(dev->nfc_dev, 0);
rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb, rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb,
pn533_in_dep_link_up_complete, arg); pn533_in_dep_link_up_complete, arg);
...@@ -2232,7 +2339,15 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, ...@@ -2232,7 +2339,15 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
if (mi) { if (mi) {
dev->cmd_complete_mi_arg = arg; dev->cmd_complete_mi_arg = arg;
queue_work(dev->wq, &dev->mi_work); queue_work(dev->wq, &dev->mi_rx_work);
return -EINPROGRESS;
}
/* Prepare for the next round */
if (skb_queue_len(&dev->fragment_skb) > 0) {
dev->cmd_complete_dep_arg = arg;
queue_work(dev->wq, &dev->mi_tx_work);
return -EINPROGRESS; return -EINPROGRESS;
} }
...@@ -2253,6 +2368,50 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, ...@@ -2253,6 +2368,50 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
return rc; return rc;
} }
/* Split the Tx skb into small chunks */
static int pn533_fill_fragment_skbs(struct pn533 *dev, struct sk_buff *skb)
{
struct sk_buff *frag;
int frag_size;
do {
/* Remaining size */
if (skb->len > PN533_CMD_DATAFRAME_MAXLEN)
frag_size = PN533_CMD_DATAFRAME_MAXLEN;
else
frag_size = skb->len;
/* Allocate and reserve */
frag = pn533_alloc_skb(dev, frag_size);
if (!frag) {
skb_queue_purge(&dev->fragment_skb);
break;
}
/* Reserve the TG/MI byte */
skb_reserve(frag, 1);
/* MI + TG */
if (frag_size == PN533_CMD_DATAFRAME_MAXLEN)
*skb_push(frag, sizeof(u8)) = (PN533_CMD_MI_MASK | 1);
else
*skb_push(frag, sizeof(u8)) = 1; /* TG */
memcpy(skb_put(frag, frag_size), skb->data, frag_size);
/* Reduce the size of incoming buffer */
skb_pull(skb, frag_size);
/* Add this to skb_queue */
skb_queue_tail(&dev->fragment_skb, frag);
} while (skb->len > 0);
dev_kfree_skb(skb);
return skb_queue_len(&dev->fragment_skb);
}
static int pn533_transceive(struct nfc_dev *nfc_dev, static int pn533_transceive(struct nfc_dev *nfc_dev,
struct nfc_target *target, struct sk_buff *skb, struct nfc_target *target, struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context) data_exchange_cb_t cb, void *cb_context)
...@@ -2263,15 +2422,6 @@ static int pn533_transceive(struct nfc_dev *nfc_dev, ...@@ -2263,15 +2422,6 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
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, nfc_dev_err(&dev->interface->dev,
"Can't exchange data if there is no active target"); "Can't exchange data if there is no active target");
...@@ -2299,7 +2449,20 @@ static int pn533_transceive(struct nfc_dev *nfc_dev, ...@@ -2299,7 +2449,20 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
break; break;
} }
default: default:
*skb_push(skb, sizeof(u8)) = 1; /*TG*/ /* jumbo frame ? */
if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
rc = pn533_fill_fragment_skbs(dev, skb);
if (rc <= 0)
goto error;
skb = skb_dequeue(&dev->fragment_skb);
if (!skb) {
rc = -EIO;
goto error;
}
} else {
*skb_push(skb, sizeof(u8)) = 1; /* TG */
}
rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE, rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE,
skb, pn533_data_exchange_complete, skb, pn533_data_exchange_complete,
...@@ -2370,7 +2533,7 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) ...@@ -2370,7 +2533,7 @@ 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_rx_work);
struct sk_buff *skb; struct sk_buff *skb;
int rc; int rc;
...@@ -2418,6 +2581,61 @@ static void pn533_wq_mi_recv(struct work_struct *work) ...@@ -2418,6 +2581,61 @@ static void pn533_wq_mi_recv(struct work_struct *work)
queue_work(dev->wq, &dev->cmd_work); queue_work(dev->wq, &dev->cmd_work);
} }
static void pn533_wq_mi_send(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, mi_tx_work);
struct sk_buff *skb;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
/* Grab the first skb in the queue */
skb = skb_dequeue(&dev->fragment_skb);
if (skb == NULL) { /* No more data */
/* Reset the queue for future use */
skb_queue_head_init(&dev->fragment_skb);
goto error;
}
switch (dev->device_type) {
case PN533_DEVICE_PASORI:
if (dev->tgt_active_prot != NFC_PROTO_FELICA) {
rc = -EIO;
break;
}
rc = pn533_send_cmd_direct_async(dev, PN533_CMD_IN_COMM_THRU,
skb,
pn533_data_exchange_complete,
dev->cmd_complete_dep_arg);
break;
default:
/* Still some fragments? */
rc = pn533_send_cmd_direct_async(dev,PN533_CMD_IN_DATA_EXCHANGE,
skb,
pn533_data_exchange_complete,
dev->cmd_complete_dep_arg);
break;
}
if (rc == 0) /* success */
return;
nfc_dev_err(&dev->interface->dev,
"Error %d when trying to perform data_exchange", rc);
dev_kfree_skb(skb);
kfree(dev->cmd_complete_dep_arg);
error:
pn533_send_ack(dev, GFP_KERNEL);
queue_work(dev->wq, &dev->cmd_work);
}
static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
u8 cfgdata_len) u8 cfgdata_len)
{ {
...@@ -2562,6 +2780,8 @@ static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf) ...@@ -2562,6 +2780,8 @@ static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf)
u8 rf_field = !!rf; u8 rf_field = !!rf;
int rc; int rc;
rf_field |= PN533_CFGITEM_RF_FIELD_AUTO_RFCA;
rc = pn533_set_configuration(dev, PN533_CFGITEM_RF_FIELD, rc = pn533_set_configuration(dev, PN533_CFGITEM_RF_FIELD,
(u8 *)&rf_field, 1); (u8 *)&rf_field, 1);
if (rc) { if (rc) {
...@@ -2605,17 +2825,6 @@ static int pn533_setup(struct pn533 *dev) ...@@ -2605,17 +2825,6 @@ static int pn533_setup(struct pn533 *dev)
switch (dev->device_type) { switch (dev->device_type) {
case PN533_DEVICE_STD: case PN533_DEVICE_STD:
max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS;
max_retries.mx_rty_psl = 2;
max_retries.mx_rty_passive_act =
PN533_CONFIG_MAX_RETRIES_NO_RETRY;
timing.rfu = PN533_CONFIG_TIMING_102;
timing.atr_res_timeout = PN533_CONFIG_TIMING_204;
timing.dep_timeout = PN533_CONFIG_TIMING_409;
break;
case PN533_DEVICE_PASORI: case PN533_DEVICE_PASORI:
case PN533_DEVICE_ACR122U: case PN533_DEVICE_ACR122U:
max_retries.mx_rty_atr = 0x2; max_retries.mx_rty_atr = 0x2;
...@@ -2729,9 +2938,11 @@ static int pn533_probe(struct usb_interface *interface, ...@@ -2729,9 +2938,11 @@ static int pn533_probe(struct usb_interface *interface,
INIT_WORK(&dev->cmd_work, pn533_wq_cmd); INIT_WORK(&dev->cmd_work, pn533_wq_cmd);
INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete); INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete);
INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); INIT_WORK(&dev->mi_rx_work, pn533_wq_mi_recv);
INIT_WORK(&dev->mi_tx_work, pn533_wq_mi_send);
INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data);
INIT_WORK(&dev->poll_work, pn533_wq_poll); INIT_DELAYED_WORK(&dev->poll_work, pn533_wq_poll);
INIT_WORK(&dev->rf_work, pn533_wq_rf);
dev->wq = alloc_ordered_workqueue("pn533", 0); dev->wq = alloc_ordered_workqueue("pn533", 0);
if (dev->wq == NULL) if (dev->wq == NULL)
goto error; goto error;
...@@ -2741,6 +2952,7 @@ static int pn533_probe(struct usb_interface *interface, ...@@ -2741,6 +2952,7 @@ static int pn533_probe(struct usb_interface *interface,
dev->listen_timer.function = pn533_listen_mode_timer; dev->listen_timer.function = pn533_listen_mode_timer;
skb_queue_head_init(&dev->resp_q); skb_queue_head_init(&dev->resp_q);
skb_queue_head_init(&dev->fragment_skb);
INIT_LIST_HEAD(&dev->cmd_queue); INIT_LIST_HEAD(&dev->cmd_queue);
...@@ -2842,6 +3054,7 @@ static void pn533_disconnect(struct usb_interface *interface) ...@@ -2842,6 +3054,7 @@ static void pn533_disconnect(struct usb_interface *interface)
usb_kill_urb(dev->in_urb); usb_kill_urb(dev->in_urb);
usb_kill_urb(dev->out_urb); usb_kill_urb(dev->out_urb);
flush_delayed_work(&dev->poll_work);
destroy_workqueue(dev->wq); destroy_workqueue(dev->wq);
skb_queue_purge(&dev->resp_q); skb_queue_purge(&dev->resp_q);
......
...@@ -25,11 +25,14 @@ ...@@ -25,11 +25,14 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/nfc.h>
#include <linux/firmware.h>
#include <linux/unaligned/access_ok.h>
#include <linux/platform_data/pn544.h> #include <linux/platform_data/pn544.h>
#include <net/nfc/hci.h> #include <net/nfc/hci.h>
#include <net/nfc/llc.h> #include <net/nfc/llc.h>
#include <net/nfc/nfc.h>
#include "pn544.h" #include "pn544.h"
...@@ -55,6 +58,58 @@ MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table); ...@@ -55,6 +58,58 @@ MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table);
#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c" #define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c"
#define PN544_FW_CMD_WRITE 0x08
#define PN544_FW_CMD_CHECK 0x06
struct pn544_i2c_fw_frame_write {
u8 cmd;
u16 be_length;
u8 be_dest_addr[3];
u16 be_datalen;
u8 data[];
} __packed;
struct pn544_i2c_fw_frame_check {
u8 cmd;
u16 be_length;
u8 be_start_addr[3];
u16 be_datalen;
u16 be_crc;
} __packed;
struct pn544_i2c_fw_frame_response {
u8 status;
u16 be_length;
} __packed;
struct pn544_i2c_fw_blob {
u32 be_size;
u32 be_destaddr;
u8 data[];
};
#define PN544_FW_CMD_RESULT_TIMEOUT 0x01
#define PN544_FW_CMD_RESULT_BAD_CRC 0x02
#define PN544_FW_CMD_RESULT_ACCESS_DENIED 0x08
#define PN544_FW_CMD_RESULT_PROTOCOL_ERROR 0x0B
#define PN544_FW_CMD_RESULT_INVALID_PARAMETER 0x11
#define PN544_FW_CMD_RESULT_INVALID_LENGTH 0x18
#define PN544_FW_CMD_RESULT_WRITE_FAILED 0x74
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define PN544_FW_WRITE_BUFFER_MAX_LEN 0x9f7
#define PN544_FW_I2C_MAX_PAYLOAD PN544_HCI_I2C_LLC_MAX_SIZE
#define PN544_FW_I2C_WRITE_FRAME_HEADER_LEN 8
#define PN544_FW_I2C_WRITE_DATA_MAX_LEN MIN((PN544_FW_I2C_MAX_PAYLOAD -\
PN544_FW_I2C_WRITE_FRAME_HEADER_LEN),\
PN544_FW_WRITE_BUFFER_MAX_LEN)
#define FW_WORK_STATE_IDLE 1
#define FW_WORK_STATE_START 2
#define FW_WORK_STATE_WAIT_WRITE_ANSWER 3
#define FW_WORK_STATE_WAIT_CHECK_ANSWER 4
struct pn544_i2c_phy { struct pn544_i2c_phy {
struct i2c_client *i2c_dev; struct i2c_client *i2c_dev;
struct nfc_hci_dev *hdev; struct nfc_hci_dev *hdev;
...@@ -64,7 +119,18 @@ struct pn544_i2c_phy { ...@@ -64,7 +119,18 @@ struct pn544_i2c_phy {
unsigned int gpio_fw; unsigned int gpio_fw;
unsigned int en_polarity; unsigned int en_polarity;
struct work_struct fw_work;
int fw_work_state;
char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
const struct firmware *fw;
u32 fw_blob_dest_addr;
size_t fw_blob_size;
const u8 *fw_blob_data;
size_t fw_written;
int fw_cmd_result;
int powered; int powered;
int run_mode;
int hard_fault; /* int hard_fault; /*
* < 0 if hardware error occured (e.g. i2c err) * < 0 if hardware error occured (e.g. i2c err)
...@@ -122,15 +188,22 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy) ...@@ -122,15 +188,22 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
gpio_set_value(phy->gpio_en, !phy->en_polarity); gpio_set_value(phy->gpio_en, !phy->en_polarity);
} }
static void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode)
{
gpio_set_value(phy->gpio_fw, run_mode == PN544_FW_MODE ? 1 : 0);
gpio_set_value(phy->gpio_en, phy->en_polarity);
usleep_range(10000, 15000);
phy->run_mode = run_mode;
}
static int pn544_hci_i2c_enable(void *phy_id) static int pn544_hci_i2c_enable(void *phy_id)
{ {
struct pn544_i2c_phy *phy = phy_id; struct pn544_i2c_phy *phy = phy_id;
pr_info(DRIVER_DESC ": %s\n", __func__); pr_info(DRIVER_DESC ": %s\n", __func__);
gpio_set_value(phy->gpio_fw, 0); pn544_hci_i2c_enable_mode(phy, PN544_HCI_MODE);
gpio_set_value(phy->gpio_en, phy->en_polarity);
usleep_range(10000, 15000);
phy->powered = 1; phy->powered = 1;
...@@ -305,6 +378,42 @@ static int pn544_hci_i2c_read(struct pn544_i2c_phy *phy, struct sk_buff **skb) ...@@ -305,6 +378,42 @@ static int pn544_hci_i2c_read(struct pn544_i2c_phy *phy, struct sk_buff **skb)
return r; return r;
} }
static int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy)
{
int r;
struct pn544_i2c_fw_frame_response response;
struct i2c_client *client = phy->i2c_dev;
r = i2c_master_recv(client, (char *) &response, sizeof(response));
if (r != sizeof(response)) {
dev_err(&client->dev, "cannot read fw status\n");
return -EIO;
}
usleep_range(3000, 6000);
switch (response.status) {
case 0:
return 0;
case PN544_FW_CMD_RESULT_TIMEOUT:
return -ETIMEDOUT;
case PN544_FW_CMD_RESULT_BAD_CRC:
return -ENODATA;
case PN544_FW_CMD_RESULT_ACCESS_DENIED:
return -EACCES;
case PN544_FW_CMD_RESULT_PROTOCOL_ERROR:
return -EPROTO;
case PN544_FW_CMD_RESULT_INVALID_PARAMETER:
return -EINVAL;
case PN544_FW_CMD_RESULT_INVALID_LENGTH:
return -EBADMSG;
case PN544_FW_CMD_RESULT_WRITE_FAILED:
return -EIO;
default:
return -EIO;
}
}
/* /*
* Reads an shdlc frame from the chip. This is not as straightforward as it * Reads an shdlc frame from the chip. This is not as straightforward as it
* seems. There are cases where we could loose the frame start synchronization. * seems. There are cases where we could loose the frame start synchronization.
...@@ -339,19 +448,23 @@ static irqreturn_t pn544_hci_i2c_irq_thread_fn(int irq, void *phy_id) ...@@ -339,19 +448,23 @@ static irqreturn_t pn544_hci_i2c_irq_thread_fn(int irq, void *phy_id)
if (phy->hard_fault != 0) if (phy->hard_fault != 0)
return IRQ_HANDLED; return IRQ_HANDLED;
r = pn544_hci_i2c_read(phy, &skb); if (phy->run_mode == PN544_FW_MODE) {
if (r == -EREMOTEIO) { phy->fw_cmd_result = pn544_hci_i2c_fw_read_status(phy);
phy->hard_fault = r; schedule_work(&phy->fw_work);
} else {
r = pn544_hci_i2c_read(phy, &skb);
if (r == -EREMOTEIO) {
phy->hard_fault = r;
nfc_hci_recv_frame(phy->hdev, NULL); nfc_hci_recv_frame(phy->hdev, NULL);
return IRQ_HANDLED; return IRQ_HANDLED;
} else if ((r == -ENOMEM) || (r == -EBADMSG)) { } else if ((r == -ENOMEM) || (r == -EBADMSG)) {
return IRQ_HANDLED; return IRQ_HANDLED;
} }
nfc_hci_recv_frame(phy->hdev, skb);
nfc_hci_recv_frame(phy->hdev, skb);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -361,6 +474,215 @@ static struct nfc_phy_ops i2c_phy_ops = { ...@@ -361,6 +474,215 @@ static struct nfc_phy_ops i2c_phy_ops = {
.disable = pn544_hci_i2c_disable, .disable = pn544_hci_i2c_disable,
}; };
static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name)
{
struct pn544_i2c_phy *phy = phy_id;
pr_info(DRIVER_DESC ": Starting Firmware Download (%s)\n",
firmware_name);
strcpy(phy->firmware_name, firmware_name);
phy->fw_work_state = FW_WORK_STATE_START;
schedule_work(&phy->fw_work);
return 0;
}
static void pn544_hci_i2c_fw_work_complete(struct pn544_i2c_phy *phy,
int result)
{
pr_info(DRIVER_DESC ": Firmware Download Complete, result=%d\n", result);
pn544_hci_i2c_disable(phy);
phy->fw_work_state = FW_WORK_STATE_IDLE;
if (phy->fw) {
release_firmware(phy->fw);
phy->fw = NULL;
}
nfc_fw_download_done(phy->hdev->ndev, phy->firmware_name, (u32) -result);
}
static int pn544_hci_i2c_fw_write_cmd(struct i2c_client *client, u32 dest_addr,
const u8 *data, u16 datalen)
{
u8 frame[PN544_FW_I2C_MAX_PAYLOAD];
struct pn544_i2c_fw_frame_write *framep;
u16 params_len;
int framelen;
int r;
if (datalen > PN544_FW_I2C_WRITE_DATA_MAX_LEN)
datalen = PN544_FW_I2C_WRITE_DATA_MAX_LEN;
framep = (struct pn544_i2c_fw_frame_write *) frame;
params_len = sizeof(framep->be_dest_addr) +
sizeof(framep->be_datalen) + datalen;
framelen = params_len + sizeof(framep->cmd) +
sizeof(framep->be_length);
framep->cmd = PN544_FW_CMD_WRITE;
put_unaligned_be16(params_len, &framep->be_length);
framep->be_dest_addr[0] = (dest_addr & 0xff0000) >> 16;
framep->be_dest_addr[1] = (dest_addr & 0xff00) >> 8;
framep->be_dest_addr[2] = dest_addr & 0xff;
put_unaligned_be16(datalen, &framep->be_datalen);
memcpy(framep->data, data, datalen);
r = i2c_master_send(client, frame, framelen);
if (r == framelen)
return datalen;
else if (r < 0)
return r;
else
return -EIO;
}
static int pn544_hci_i2c_fw_check_cmd(struct i2c_client *client, u32 start_addr,
const u8 *data, u16 datalen)
{
struct pn544_i2c_fw_frame_check frame;
int r;
u16 crc;
/* calculate local crc for the data we want to check */
crc = crc_ccitt(0xffff, data, datalen);
frame.cmd = PN544_FW_CMD_CHECK;
put_unaligned_be16(sizeof(frame.be_start_addr) +
sizeof(frame.be_datalen) + sizeof(frame.be_crc),
&frame.be_length);
/* tell the chip the memory region to which our crc applies */
frame.be_start_addr[0] = (start_addr & 0xff0000) >> 16;
frame.be_start_addr[1] = (start_addr & 0xff00) >> 8;
frame.be_start_addr[2] = start_addr & 0xff;
put_unaligned_be16(datalen, &frame.be_datalen);
/*
* and give our local crc. Chip will calculate its own crc for the
* region and compare with ours.
*/
put_unaligned_be16(crc, &frame.be_crc);
r = i2c_master_send(client, (const char *) &frame, sizeof(frame));
if (r == sizeof(frame))
return 0;
else if (r < 0)
return r;
else
return -EIO;
}
static int pn544_hci_i2c_fw_write_chunk(struct pn544_i2c_phy *phy)
{
int r;
r = pn544_hci_i2c_fw_write_cmd(phy->i2c_dev,
phy->fw_blob_dest_addr + phy->fw_written,
phy->fw_blob_data + phy->fw_written,
phy->fw_blob_size - phy->fw_written);
if (r < 0)
return r;
phy->fw_written += r;
phy->fw_work_state = FW_WORK_STATE_WAIT_WRITE_ANSWER;
return 0;
}
static void pn544_hci_i2c_fw_work(struct work_struct *work)
{
struct pn544_i2c_phy *phy = container_of(work, struct pn544_i2c_phy,
fw_work);
int r;
struct pn544_i2c_fw_blob *blob;
switch (phy->fw_work_state) {
case FW_WORK_STATE_START:
pn544_hci_i2c_enable_mode(phy, PN544_FW_MODE);
r = request_firmware(&phy->fw, phy->firmware_name,
&phy->i2c_dev->dev);
if (r < 0)
goto exit_state_start;
blob = (struct pn544_i2c_fw_blob *) phy->fw->data;
phy->fw_blob_size = get_unaligned_be32(&blob->be_size);
phy->fw_blob_dest_addr = get_unaligned_be32(&blob->be_destaddr);
phy->fw_blob_data = blob->data;
phy->fw_written = 0;
r = pn544_hci_i2c_fw_write_chunk(phy);
exit_state_start:
if (r < 0)
pn544_hci_i2c_fw_work_complete(phy, r);
break;
case FW_WORK_STATE_WAIT_WRITE_ANSWER:
r = phy->fw_cmd_result;
if (r < 0)
goto exit_state_wait_write_answer;
if (phy->fw_written == phy->fw_blob_size) {
r = pn544_hci_i2c_fw_check_cmd(phy->i2c_dev,
phy->fw_blob_dest_addr,
phy->fw_blob_data,
phy->fw_blob_size);
if (r < 0)
goto exit_state_wait_write_answer;
phy->fw_work_state = FW_WORK_STATE_WAIT_CHECK_ANSWER;
break;
}
r = pn544_hci_i2c_fw_write_chunk(phy);
exit_state_wait_write_answer:
if (r < 0)
pn544_hci_i2c_fw_work_complete(phy, r);
break;
case FW_WORK_STATE_WAIT_CHECK_ANSWER:
r = phy->fw_cmd_result;
if (r < 0)
goto exit_state_wait_check_answer;
blob = (struct pn544_i2c_fw_blob *) (phy->fw_blob_data +
phy->fw_blob_size);
phy->fw_blob_size = get_unaligned_be32(&blob->be_size);
if (phy->fw_blob_size != 0) {
phy->fw_blob_dest_addr =
get_unaligned_be32(&blob->be_destaddr);
phy->fw_blob_data = blob->data;
phy->fw_written = 0;
r = pn544_hci_i2c_fw_write_chunk(phy);
}
exit_state_wait_check_answer:
if (r < 0 || phy->fw_blob_size == 0)
pn544_hci_i2c_fw_work_complete(phy, r);
break;
default:
break;
}
}
static int pn544_hci_i2c_probe(struct i2c_client *client, static int pn544_hci_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
...@@ -384,6 +706,9 @@ static int pn544_hci_i2c_probe(struct i2c_client *client, ...@@ -384,6 +706,9 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
return -ENOMEM; return -ENOMEM;
} }
INIT_WORK(&phy->fw_work, pn544_hci_i2c_fw_work);
phy->fw_work_state = FW_WORK_STATE_IDLE;
phy->i2c_dev = client; phy->i2c_dev = client;
i2c_set_clientdata(client, phy); i2c_set_clientdata(client, phy);
...@@ -420,7 +745,8 @@ static int pn544_hci_i2c_probe(struct i2c_client *client, ...@@ -420,7 +745,8 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
r = pn544_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME, r = pn544_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
PN544_I2C_FRAME_HEADROOM, PN544_I2C_FRAME_TAILROOM, PN544_I2C_FRAME_HEADROOM, PN544_I2C_FRAME_TAILROOM,
PN544_HCI_I2C_LLC_MAX_PAYLOAD, &phy->hdev); PN544_HCI_I2C_LLC_MAX_PAYLOAD,
pn544_hci_i2c_fw_download, &phy->hdev);
if (r < 0) if (r < 0)
goto err_hci; goto err_hci;
...@@ -443,6 +769,10 @@ static int pn544_hci_i2c_remove(struct i2c_client *client) ...@@ -443,6 +769,10 @@ static int pn544_hci_i2c_remove(struct i2c_client *client)
dev_dbg(&client->dev, "%s\n", __func__); dev_dbg(&client->dev, "%s\n", __func__);
cancel_work_sync(&phy->fw_work);
if (phy->fw_work_state != FW_WORK_STATE_IDLE)
pn544_hci_i2c_fw_work_complete(phy, -ENODEV);
pn544_hci_remove(phy->hdev); pn544_hci_remove(phy->hdev);
if (phy->powered) if (phy->powered)
......
...@@ -45,7 +45,7 @@ static int pn544_mei_probe(struct mei_cl_device *device, ...@@ -45,7 +45,7 @@ static int pn544_mei_probe(struct mei_cl_device *device,
r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME, r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
&phy->hdev); NULL, &phy->hdev);
if (r < 0) { if (r < 0) {
nfc_mei_phy_free(phy); nfc_mei_phy_free(phy);
......
...@@ -31,9 +31,6 @@ ...@@ -31,9 +31,6 @@
/* Timing restrictions (ms) */ /* Timing restrictions (ms) */
#define PN544_HCI_RESETVEN_TIME 30 #define PN544_HCI_RESETVEN_TIME 30
#define HCI_MODE 0
#define FW_MODE 1
enum pn544_state { enum pn544_state {
PN544_ST_COLD, PN544_ST_COLD,
PN544_ST_FW_READY, PN544_ST_FW_READY,
...@@ -130,6 +127,8 @@ struct pn544_hci_info { ...@@ -130,6 +127,8 @@ struct pn544_hci_info {
int async_cb_type; int async_cb_type;
data_exchange_cb_t async_cb; data_exchange_cb_t async_cb;
void *async_cb_context; void *async_cb_context;
fw_download_t fw_download;
}; };
static int pn544_hci_open(struct nfc_hci_dev *hdev) static int pn544_hci_open(struct nfc_hci_dev *hdev)
...@@ -782,6 +781,17 @@ static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event, ...@@ -782,6 +781,17 @@ static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event,
return r; return r;
} }
static int pn544_hci_fw_download(struct nfc_hci_dev *hdev,
const char *firmware_name)
{
struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
if (info->fw_download == NULL)
return -ENOTSUPP;
return info->fw_download(info->phy_id, firmware_name);
}
static struct nfc_hci_ops pn544_hci_ops = { static struct nfc_hci_ops pn544_hci_ops = {
.open = pn544_hci_open, .open = pn544_hci_open,
.close = pn544_hci_close, .close = pn544_hci_close,
...@@ -796,11 +806,12 @@ static struct nfc_hci_ops pn544_hci_ops = { ...@@ -796,11 +806,12 @@ static struct nfc_hci_ops pn544_hci_ops = {
.tm_send = pn544_hci_tm_send, .tm_send = pn544_hci_tm_send,
.check_presence = pn544_hci_check_presence, .check_presence = pn544_hci_check_presence,
.event_received = pn544_hci_event_received, .event_received = pn544_hci_event_received,
.fw_download = pn544_hci_fw_download,
}; };
int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
int phy_headroom, int phy_tailroom, int phy_payload, int phy_headroom, int phy_tailroom, int phy_payload,
struct nfc_hci_dev **hdev) fw_download_t fw_download, struct nfc_hci_dev **hdev)
{ {
struct pn544_hci_info *info; struct pn544_hci_info *info;
u32 protocols; u32 protocols;
...@@ -816,6 +827,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, ...@@ -816,6 +827,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
info->phy_ops = phy_ops; info->phy_ops = phy_ops;
info->phy_id = phy_id; info->phy_id = phy_id;
info->fw_download = fw_download;
info->state = PN544_ST_COLD; info->state = PN544_ST_COLD;
mutex_init(&info->info_lock); mutex_init(&info->info_lock);
......
...@@ -24,9 +24,14 @@ ...@@ -24,9 +24,14 @@
#define DRIVER_DESC "HCI NFC driver for PN544" #define DRIVER_DESC "HCI NFC driver for PN544"
#define PN544_HCI_MODE 0
#define PN544_FW_MODE 1
typedef int (*fw_download_t)(void *context, const char *firmware_name);
int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
int phy_headroom, int phy_tailroom, int phy_payload, int phy_headroom, int phy_tailroom, int phy_payload,
struct nfc_hci_dev **hdev); fw_download_t fw_download, struct nfc_hci_dev **hdev);
void pn544_hci_remove(struct nfc_hci_dev *hdev); void pn544_hci_remove(struct nfc_hci_dev *hdev);
#endif /* __LOCAL_PN544_H_ */ #endif /* __LOCAL_PN544_H_ */
...@@ -224,6 +224,9 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev, ...@@ -224,6 +224,9 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev,
u8 *gt, u8 gt_len); u8 *gt, u8 gt_len);
u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len); u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len);
int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name,
u32 result);
int nfc_targets_found(struct nfc_dev *dev, int nfc_targets_found(struct nfc_dev *dev,
struct nfc_target *targets, int ntargets); struct nfc_target *targets, int ntargets);
int nfc_target_lost(struct nfc_dev *dev, u32 target_idx); int nfc_target_lost(struct nfc_dev *dev, u32 target_idx);
......
...@@ -71,6 +71,20 @@ ...@@ -71,6 +71,20 @@
* @NFC_CMD_DISABLE_SE: Disable the physical link to a specific secure element. * @NFC_CMD_DISABLE_SE: Disable the physical link to a specific secure element.
* @NFC_CMD_FW_DOWNLOAD: Request to Load/flash firmware, or event to inform * @NFC_CMD_FW_DOWNLOAD: Request to Load/flash firmware, or event to inform
* that some firmware was loaded * that some firmware was loaded
* @NFC_EVENT_SE_ADDED: Event emitted when a new secure element is discovered.
* This typically will be sent whenever a new NFC controller with either
* an embedded SE or an UICC one connected to it through SWP.
* @NFC_EVENT_SE_REMOVED: Event emitted when a secure element is removed from
* the system, as a consequence of e.g. an NFC controller being unplugged.
* @NFC_EVENT_SE_CONNECTIVITY: This event is emitted whenever a secure element
* is requesting connectivity access. For example a UICC SE may need to
* talk with a sleeping modem and will notify this need by sending this
* event. It is then up to userspace to decide if it will wake the modem
* up or not.
* @NFC_EVENT_SE_TRANSACTION: This event is sent when an application running on
* a specific SE notifies us about the end of a transaction. The parameter
* for this event is the application ID (AID).
* @NFC_CMD_GET_SE: Dump all discovered secure elements from an NFC controller.
*/ */
enum nfc_commands { enum nfc_commands {
NFC_CMD_UNSPEC, NFC_CMD_UNSPEC,
...@@ -97,6 +111,9 @@ enum nfc_commands { ...@@ -97,6 +111,9 @@ enum nfc_commands {
NFC_CMD_FW_DOWNLOAD, NFC_CMD_FW_DOWNLOAD,
NFC_EVENT_SE_ADDED, NFC_EVENT_SE_ADDED,
NFC_EVENT_SE_REMOVED, NFC_EVENT_SE_REMOVED,
NFC_EVENT_SE_CONNECTIVITY,
NFC_EVENT_SE_TRANSACTION,
NFC_CMD_GET_SE,
/* private: internal use only */ /* private: internal use only */
__NFC_CMD_AFTER_LAST __NFC_CMD_AFTER_LAST
}; };
...@@ -129,6 +146,7 @@ enum nfc_commands { ...@@ -129,6 +146,7 @@ enum nfc_commands {
* @NFC_ATTR_FIRMWARE_NAME: Free format firmware version * @NFC_ATTR_FIRMWARE_NAME: Free format firmware version
* @NFC_ATTR_SE_INDEX: Secure element index * @NFC_ATTR_SE_INDEX: Secure element index
* @NFC_ATTR_SE_TYPE: Secure element type (UICC or EMBEDDED) * @NFC_ATTR_SE_TYPE: Secure element type (UICC or EMBEDDED)
* @NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS: Firmware download operation status
*/ */
enum nfc_attrs { enum nfc_attrs {
NFC_ATTR_UNSPEC, NFC_ATTR_UNSPEC,
...@@ -154,6 +172,8 @@ enum nfc_attrs { ...@@ -154,6 +172,8 @@ enum nfc_attrs {
NFC_ATTR_FIRMWARE_NAME, NFC_ATTR_FIRMWARE_NAME,
NFC_ATTR_SE_INDEX, NFC_ATTR_SE_INDEX,
NFC_ATTR_SE_TYPE, NFC_ATTR_SE_TYPE,
NFC_ATTR_SE_AID,
NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS,
/* private: internal use only */ /* private: internal use only */
__NFC_ATTR_AFTER_LAST __NFC_ATTR_AFTER_LAST
}; };
......
...@@ -77,11 +77,19 @@ int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name) ...@@ -77,11 +77,19 @@ int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name)
return rc; return rc;
} }
int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name) /**
* nfc_fw_download_done - inform that a firmware download was completed
*
* @dev: The nfc device to which firmware was downloaded
* @firmware_name: The firmware filename
* @result: The positive value of a standard errno value
*/
int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name,
u32 result)
{ {
dev->fw_download_in_progress = false; dev->fw_download_in_progress = false;
return nfc_genl_fw_download_done(dev, firmware_name); return nfc_genl_fw_download_done(dev, firmware_name, result);
} }
EXPORT_SYMBOL(nfc_fw_download_done); EXPORT_SYMBOL(nfc_fw_download_done);
...@@ -129,7 +137,7 @@ int nfc_dev_up(struct nfc_dev *dev) ...@@ -129,7 +137,7 @@ int nfc_dev_up(struct nfc_dev *dev)
/* We have to enable the device before discovering SEs */ /* We have to enable the device before discovering SEs */
if (dev->ops->discover_se) { if (dev->ops->discover_se) {
rc = dev->ops->discover_se(dev); rc = dev->ops->discover_se(dev);
if (!rc) if (rc)
pr_warn("SE discovery failed\n"); pr_warn("SE discovery failed\n");
} }
...@@ -575,12 +583,14 @@ int nfc_enable_se(struct nfc_dev *dev, u32 se_idx) ...@@ -575,12 +583,14 @@ int nfc_enable_se(struct nfc_dev *dev, u32 se_idx)
goto error; goto error;
} }
if (se->type == NFC_SE_ENABLED) { if (se->state == NFC_SE_ENABLED) {
rc = -EALREADY; rc = -EALREADY;
goto error; goto error;
} }
rc = dev->ops->enable_se(dev, se_idx); rc = dev->ops->enable_se(dev, se_idx);
if (rc >= 0)
se->state = NFC_SE_ENABLED;
error: error:
device_unlock(&dev->dev); device_unlock(&dev->dev);
...@@ -618,12 +628,14 @@ int nfc_disable_se(struct nfc_dev *dev, u32 se_idx) ...@@ -618,12 +628,14 @@ int nfc_disable_se(struct nfc_dev *dev, u32 se_idx)
goto error; goto error;
} }
if (se->type == NFC_SE_DISABLED) { if (se->state == NFC_SE_DISABLED) {
rc = -EALREADY; rc = -EALREADY;
goto error; goto error;
} }
rc = dev->ops->disable_se(dev, se_idx); rc = dev->ops->disable_se(dev, se_idx);
if (rc >= 0)
se->state = NFC_SE_DISABLED;
error: error:
device_unlock(&dev->dev); device_unlock(&dev->dev);
......
...@@ -717,7 +717,7 @@ static int hci_disable_se(struct nfc_dev *nfc_dev, u32 se_idx) ...@@ -717,7 +717,7 @@ static int hci_disable_se(struct nfc_dev *nfc_dev, u32 se_idx)
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
if (hdev->ops->disable_se) if (hdev->ops->disable_se)
return hdev->ops->enable_se(hdev, se_idx); return hdev->ops->disable_se(hdev, se_idx);
return 0; return 0;
} }
......
...@@ -1114,7 +1114,8 @@ static int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info) ...@@ -1114,7 +1114,8 @@ static int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info)
return rc; return rc;
} }
int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name) int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name,
u32 result)
{ {
struct sk_buff *msg; struct sk_buff *msg;
void *hdr; void *hdr;
...@@ -1129,6 +1130,7 @@ int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name) ...@@ -1129,6 +1130,7 @@ int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name)
goto free_msg; goto free_msg;
if (nla_put_string(msg, NFC_ATTR_FIRMWARE_NAME, firmware_name) || if (nla_put_string(msg, NFC_ATTR_FIRMWARE_NAME, firmware_name) ||
nla_put_u32(msg, NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS, result) ||
nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
goto nla_put_failure; goto nla_put_failure;
...@@ -1191,6 +1193,91 @@ static int nfc_genl_disable_se(struct sk_buff *skb, struct genl_info *info) ...@@ -1191,6 +1193,91 @@ static int nfc_genl_disable_se(struct sk_buff *skb, struct genl_info *info)
return rc; return rc;
} }
static int nfc_genl_send_se(struct sk_buff *msg, struct nfc_dev *dev,
u32 portid, u32 seq,
struct netlink_callback *cb,
int flags)
{
void *hdr;
struct nfc_se *se, *n;
list_for_each_entry_safe(se, n, &dev->secure_elements, list) {
hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, flags,
NFC_CMD_GET_SE);
if (!hdr)
goto nla_put_failure;
if (cb)
genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
nla_put_u32(msg, NFC_ATTR_SE_INDEX, se->idx) ||
nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type))
goto nla_put_failure;
if (genlmsg_end(msg, hdr) < 0)
goto nla_put_failure;
}
return 0;
nla_put_failure:
genlmsg_cancel(msg, hdr);
return -EMSGSIZE;
}
static int nfc_genl_dump_ses(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
bool first_call = false;
if (!iter) {
first_call = true;
iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL);
if (!iter)
return -ENOMEM;
cb->args[0] = (long) iter;
}
mutex_lock(&nfc_devlist_mutex);
cb->seq = nfc_devlist_generation;
if (first_call) {
nfc_device_iter_init(iter);
dev = nfc_device_iter_next(iter);
}
while (dev) {
int rc;
rc = nfc_genl_send_se(skb, dev, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
if (rc < 0)
break;
dev = nfc_device_iter_next(iter);
}
mutex_unlock(&nfc_devlist_mutex);
cb->args[1] = (long) dev;
return skb->len;
}
static int nfc_genl_dump_ses_done(struct netlink_callback *cb)
{
struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
nfc_device_iter_exit(iter);
kfree(iter);
return 0;
}
static struct genl_ops nfc_genl_ops[] = { static struct genl_ops nfc_genl_ops[] = {
{ {
.cmd = NFC_CMD_GET_DEVICE, .cmd = NFC_CMD_GET_DEVICE,
...@@ -1265,6 +1352,12 @@ static struct genl_ops nfc_genl_ops[] = { ...@@ -1265,6 +1352,12 @@ static struct genl_ops nfc_genl_ops[] = {
.doit = nfc_genl_disable_se, .doit = nfc_genl_disable_se,
.policy = nfc_genl_policy, .policy = nfc_genl_policy,
}, },
{
.cmd = NFC_CMD_GET_SE,
.dumpit = nfc_genl_dump_ses,
.done = nfc_genl_dump_ses_done,
.policy = nfc_genl_policy,
},
}; };
......
...@@ -124,9 +124,8 @@ static inline void nfc_device_iter_exit(struct class_dev_iter *iter) ...@@ -124,9 +124,8 @@ static inline void nfc_device_iter_exit(struct class_dev_iter *iter)
} }
int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name); int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name);
int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name); int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name,
u32 result);
int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name);
int nfc_dev_up(struct nfc_dev *dev); int nfc_dev_up(struct nfc_dev *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment