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.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJSCr8sAAoJEIqAPN1PVmxKPRwP/3hMmPn7xTRHh+snJW/aLl+P
 nKpLg+kLcT8QedPzB5W/N1jmI9KCdEEtw5WAzwaWW55hpc5rBpw3/aF0/WJfkZqv
 b4SSJ42R6XKctN+6LRFeFZyBzhgObFZqEoNsXx1C22wKCJJ4rt9HT3XFlsMihn7q
 723VIWpoKc3IzUn6GAEGJNm54519aiLwVisSWsSVF1L8uRP3MBuPb2jD1/QaY19n
 x8J3Cj/SIXBAz1F0+J81Un1Qpi+QegGCIsQZhE7xk4s2PwmbI6dd5ic9ew5P1OlN
 kb79OZAG69eyI4Z3yi4ozk51gWL6gRAkhhYQIPehYa03wh4tP14dfGM+reYLUOMt
 7PiWMDPtmWNfylFiLdFYbWOee6uDGtI4+AsHMMqLSjvICTtjJFIsQ4ZLnHZv/xuw
 E8n0vZJaEGY2g6z1LNjflFO7Ajv9oMuM+oYxPRxJsAL9olID+zlNTdEefr5gt8oL
 xhLvzCZjgrGCzHv+HdpNSGYL6jLjeJ5rosETw3VbC99JXBJ/YEA1ycF4hRLjPUrS
 88IEODyIIGCKjf7hUoF91XRlfSVKefiDWaXKmYW6JeXnvxYdaZhILwz+VwzLbFyp
 dlRn5dbovkMglmiTo17awySQukw0M6OdbsisGPhDB6qvSpn2ceDlBht020hh9rTv
 HnEL351h1Ll1QWnZkQPQ
 =G1Os
 -----END PGP SIGNATURE-----

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: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
John W. Linville 2013-08-15 15:55:10 -04:00
commit 74ea1f4524
13 changed files with 810 additions and 123 deletions

View File

@ -5791,7 +5791,7 @@ M: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
M: Samuel Ortiz <sameo@linux.intel.com>
L: linux-wireless@vger.kernel.org
L: linux-nfc@lists.01.org (moderated for non-subscribers)
S: Maintained
S: Supported
F: net/nfc/
F: include/net/nfc/
F: include/uapi/linux/nfc.h

View File

@ -60,7 +60,7 @@ struct nfcsim {
static struct nfcsim *dev0;
static struct nfcsim *dev1;
struct workqueue_struct *wq;
static struct workqueue_struct *wq;
static void nfcsim_cleanup_dev(struct nfcsim *dev, u8 shutdown)
{
@ -481,7 +481,7 @@ static void nfcsim_free_device(struct nfcsim *dev)
kfree(dev);
}
int __init nfcsim_init(void)
static int __init nfcsim_init(void)
{
int rc;
@ -522,7 +522,7 @@ exit:
return rc;
}
void __exit nfcsim_exit(void)
static void __exit nfcsim_exit(void)
{
nfcsim_cleanup_dev(dev0, 1);
nfcsim_cleanup_dev(dev1, 1);

View File

@ -83,12 +83,20 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
/* How much time we spend listening for initiators */
#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) \
+ 2) /* data[0] TFI, data[1] CC */
#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
* which are already in PN533_FRAME_HEADER_LEN.
@ -99,6 +107,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
Postamble (1) */
#define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen])
#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 */
#define PN533_STD_FRAME_SOF 0x00FF
@ -124,7 +136,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83
/* 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_RF_CONFIGURATION 0x32
@ -168,8 +180,9 @@ struct pn533_fw_version {
#define PN533_CFGITEM_MAX_RETRIES 0x05
#define PN533_CFGITEM_PASORI 0x82
#define PN533_CFGITEM_RF_FIELD_ON 0x1
#define PN533_CFGITEM_RF_FIELD_OFF 0x0
#define PN533_CFGITEM_RF_FIELD_AUTO_RFCA 0x2
#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
@ -257,7 +270,7 @@ static const struct pn533_poll_modulations poll_mod[] = {
.initiator_data.felica = {
.opcode = PN533_FELICA_OPC_SENSF_REQ,
.sc = PN533_FELICA_SENSF_SC_ALL,
.rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE,
.rc = PN533_FELICA_SENSF_RC_SYSTEM_CODE,
.tsn = 0x03,
},
},
@ -270,7 +283,7 @@ static const struct pn533_poll_modulations poll_mod[] = {
.initiator_data.felica = {
.opcode = PN533_FELICA_OPC_SENSF_REQ,
.sc = PN533_FELICA_SENSF_SC_ALL,
.rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE,
.rc = PN533_FELICA_SENSF_RC_SYSTEM_CODE,
.tsn = 0x03,
},
},
@ -352,13 +365,16 @@ struct pn533 {
struct urb *in_urb;
struct sk_buff_head resp_q;
struct sk_buff_head fragment_skb;
struct workqueue_struct *wq;
struct work_struct cmd_work;
struct work_struct cmd_complete_work;
struct work_struct poll_work;
struct work_struct mi_work;
struct delayed_work poll_work;
struct work_struct mi_rx_work;
struct work_struct mi_tx_work;
struct work_struct tg_work;
struct work_struct rf_work;
struct list_head cmd_queue;
struct pn533_cmd *cmd;
@ -366,6 +382,7 @@ struct pn533 {
struct mutex cmd_lock; /* protects cmd queue */
void *cmd_complete_mi_arg;
void *cmd_complete_dep_arg;
struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
u8 poll_mod_count;
@ -404,6 +421,15 @@ struct pn533_std_frame {
u8 data[];
} __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 {
void (*tx_frame_init)(void *frame, u8 cmd_code);
void (*tx_frame_finish)(void *frame);
@ -411,7 +437,7 @@ struct pn533_frame_ops {
int tx_header_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_header_len;
int rx_tail_len;
@ -486,7 +512,7 @@ static void pn533_acr122_tx_update_payload_len(void *_frame, int 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;
@ -511,7 +537,7 @@ static u8 pn533_acr122_get_cmd_code(void *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 = {
@ -530,6 +556,12 @@ static struct pn533_frame_ops pn533_acr122_frame_ops = {
.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 */
static inline u8 pn533_std_checksum(u8 value)
{
@ -555,7 +587,7 @@ static void pn533_std_tx_frame_init(void *_frame, u8 cmd_code)
frame->preamble = 0;
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;
PN533_FRAME_CMD(frame) = cmd_code;
frame->datalen = 2;
}
@ -578,21 +610,41 @@ static void pn533_std_tx_update_payload_len(void *_frame, int 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;
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;
checksum = pn533_std_checksum(frame->datalen);
if (checksum != frame->datalen_checksum)
return false;
if (likely(!PN533_STD_IS_EXTENDED(stdf))) {
/* Standard frame code */
dev->ops->rx_header_len = PN533_STD_FRAME_HEADER_LEN;
checksum = pn533_std_data_checksum(frame->data, frame->datalen);
if (checksum != PN533_STD_FRAME_CHECKSUM(frame))
return false;
checksum = pn533_std_checksum(stdf->datalen);
if (checksum != stdf->datalen_checksum)
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;
}
@ -612,6 +664,14 @@ static inline int pn533_std_rx_frame_size(void *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 +
PN533_STD_FRAME_TAIL_LEN;
}
@ -619,8 +679,12 @@ static inline int pn533_std_rx_frame_size(void *frame)
static u8 pn533_std_get_cmd_code(void *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 = {
@ -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,
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");
cmd->status = -EIO;
goto sched_wq;
@ -1657,7 +1721,56 @@ static void pn533_listen_mode_timer(unsigned long data)
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,
@ -1705,7 +1818,8 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,
}
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:
dev_kfree_skb(resp);
@ -1770,7 +1884,7 @@ static int pn533_send_poll_frame(struct pn533 *dev)
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;
int rc;
@ -1799,6 +1913,7 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev,
u32 im_protocols, u32 tm_protocols)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
u8 rand_mod;
nfc_dev_dbg(&dev->interface->dev,
"%s: im protocols 0x%x tm protocols 0x%x",
@ -1822,11 +1937,15 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev,
tm_protocols = 0;
}
dev->poll_mod_curr = 0;
pn533_poll_create_mod_list(dev, im_protocols, tm_protocols);
dev->poll_protocols = im_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);
}
@ -1845,6 +1964,7 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
}
pn533_abort_cmd(dev, GFP_KERNEL);
flush_delayed_work(&dev->poll_work);
pn533_poll_reset_mod_list(dev);
}
@ -2037,28 +2157,15 @@ error:
return rc;
}
static int pn533_mod_to_baud(struct pn533 *dev)
{
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;
}
}
static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf);
#define PASSIVE_DATA_LEN 5
static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
u8 comm_mode, u8 *gb, size_t gb_len)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct sk_buff *skb;
int rc, baud, skb_len;
u8 *next, *arg;
int rc, skb_len;
u8 *next, *arg, nfcid3[NFC_NFCID3_MAXSIZE];
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,
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 */
if (comm_mode == NFC_COMM_PASSIVE)
skb_len += PASSIVE_DATA_LEN;
skb_len += PASSIVE_DATA_LEN;
if (target && target->nfcid2_len)
skb_len += NFC_NFCID3_MAXSIZE;
/* NFCID3 */
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);
if (!skb)
return -ENOMEM;
*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 = 0;
if (comm_mode == NFC_COMM_PASSIVE && baud > 0) {
memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data,
PASSIVE_DATA_LEN);
*next |= 1;
}
/* Copy passive data */
memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, PASSIVE_DATA_LEN);
*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,
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) {
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,
*arg = !comm_mode;
pn533_rf_field(dev->nfc_dev, 0);
rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb,
pn533_in_dep_link_up_complete, arg);
@ -2232,7 +2339,15 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
if (mi) {
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;
}
@ -2253,6 +2368,50 @@ _error:
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,
struct nfc_target *target, struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context)
@ -2263,15 +2422,6 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
/* TODO: Implement support to multi-part data exchange */
nfc_dev_err(&dev->interface->dev,
"Data length greater than the max allowed: %d",
PN533_CMD_DATAEXCH_DATA_MAXLEN);
rc = -ENOSYS;
goto error;
}
if (!dev->tgt_active_prot) {
nfc_dev_err(&dev->interface->dev,
"Can't exchange data if there is no active target");
@ -2299,7 +2449,20 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
break;
}
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,
skb, pn533_data_exchange_complete,
@ -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)
{
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;
int rc;
@ -2418,6 +2581,61 @@ error:
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,
u8 cfgdata_len)
{
@ -2562,6 +2780,8 @@ static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf)
u8 rf_field = !!rf;
int rc;
rf_field |= PN533_CFGITEM_RF_FIELD_AUTO_RFCA;
rc = pn533_set_configuration(dev, PN533_CFGITEM_RF_FIELD,
(u8 *)&rf_field, 1);
if (rc) {
@ -2605,17 +2825,6 @@ static int pn533_setup(struct pn533 *dev)
switch (dev->device_type) {
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_ACR122U:
max_retries.mx_rty_atr = 0x2;
@ -2729,9 +2938,11 @@ static int pn533_probe(struct usb_interface *interface,
INIT_WORK(&dev->cmd_work, pn533_wq_cmd);
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->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);
if (dev->wq == NULL)
goto error;
@ -2741,6 +2952,7 @@ static int pn533_probe(struct usb_interface *interface,
dev->listen_timer.function = pn533_listen_mode_timer;
skb_queue_head_init(&dev->resp_q);
skb_queue_head_init(&dev->fragment_skb);
INIT_LIST_HEAD(&dev->cmd_queue);
@ -2842,6 +3054,7 @@ static void pn533_disconnect(struct usb_interface *interface)
usb_kill_urb(dev->in_urb);
usb_kill_urb(dev->out_urb);
flush_delayed_work(&dev->poll_work);
destroy_workqueue(dev->wq);
skb_queue_purge(&dev->resp_q);

View File

@ -25,11 +25,14 @@
#include <linux/miscdevice.h>
#include <linux/interrupt.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 <net/nfc/hci.h>
#include <net/nfc/llc.h>
#include <net/nfc/nfc.h>
#include "pn544.h"
@ -55,6 +58,58 @@ MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table);
#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 i2c_client *i2c_dev;
struct nfc_hci_dev *hdev;
@ -64,7 +119,18 @@ struct pn544_i2c_phy {
unsigned int gpio_fw;
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 run_mode;
int hard_fault; /*
* < 0 if hardware error occured (e.g. i2c err)
@ -122,15 +188,22 @@ out:
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)
{
struct pn544_i2c_phy *phy = phy_id;
pr_info(DRIVER_DESC ": %s\n", __func__);
gpio_set_value(phy->gpio_fw, 0);
gpio_set_value(phy->gpio_en, phy->en_polarity);
usleep_range(10000, 15000);
pn544_hci_i2c_enable_mode(phy, PN544_HCI_MODE);
phy->powered = 1;
@ -305,6 +378,42 @@ flush:
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
* 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)
if (phy->hard_fault != 0)
return IRQ_HANDLED;
r = pn544_hci_i2c_read(phy, &skb);
if (r == -EREMOTEIO) {
phy->hard_fault = r;
if (phy->run_mode == PN544_FW_MODE) {
phy->fw_cmd_result = pn544_hci_i2c_fw_read_status(phy);
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;
} else if ((r == -ENOMEM) || (r == -EBADMSG)) {
return IRQ_HANDLED;
return IRQ_HANDLED;
} else if ((r == -ENOMEM) || (r == -EBADMSG)) {
return IRQ_HANDLED;
}
nfc_hci_recv_frame(phy->hdev, skb);
}
nfc_hci_recv_frame(phy->hdev, skb);
return IRQ_HANDLED;
}
@ -361,6 +474,215 @@ static struct nfc_phy_ops i2c_phy_ops = {
.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,
const struct i2c_device_id *id)
{
@ -384,6 +706,9 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
return -ENOMEM;
}
INIT_WORK(&phy->fw_work, pn544_hci_i2c_fw_work);
phy->fw_work_state = FW_WORK_STATE_IDLE;
phy->i2c_dev = client;
i2c_set_clientdata(client, phy);
@ -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,
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)
goto err_hci;
@ -443,6 +769,10 @@ static int pn544_hci_i2c_remove(struct i2c_client *client)
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);
if (phy->powered)

View File

@ -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,
MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
&phy->hdev);
NULL, &phy->hdev);
if (r < 0) {
nfc_mei_phy_free(phy);

View File

@ -31,9 +31,6 @@
/* Timing restrictions (ms) */
#define PN544_HCI_RESETVEN_TIME 30
#define HCI_MODE 0
#define FW_MODE 1
enum pn544_state {
PN544_ST_COLD,
PN544_ST_FW_READY,
@ -130,6 +127,8 @@ struct pn544_hci_info {
int async_cb_type;
data_exchange_cb_t async_cb;
void *async_cb_context;
fw_download_t fw_download;
};
static int pn544_hci_open(struct nfc_hci_dev *hdev)
@ -782,6 +781,17 @@ exit:
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 = {
.open = pn544_hci_open,
.close = pn544_hci_close,
@ -796,11 +806,12 @@ static struct nfc_hci_ops pn544_hci_ops = {
.tm_send = pn544_hci_tm_send,
.check_presence = pn544_hci_check_presence,
.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 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;
u32 protocols;
@ -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_id = phy_id;
info->fw_download = fw_download;
info->state = PN544_ST_COLD;
mutex_init(&info->info_lock);

View File

@ -24,9 +24,14 @@
#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 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);
#endif /* __LOCAL_PN544_H_ */

View File

@ -224,6 +224,9 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev,
u8 *gt, u8 gt_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,
struct nfc_target *targets, int ntargets);
int nfc_target_lost(struct nfc_dev *dev, u32 target_idx);

View File

@ -71,6 +71,20 @@
* @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
* 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 {
NFC_CMD_UNSPEC,
@ -97,6 +111,9 @@ enum nfc_commands {
NFC_CMD_FW_DOWNLOAD,
NFC_EVENT_SE_ADDED,
NFC_EVENT_SE_REMOVED,
NFC_EVENT_SE_CONNECTIVITY,
NFC_EVENT_SE_TRANSACTION,
NFC_CMD_GET_SE,
/* private: internal use only */
__NFC_CMD_AFTER_LAST
};
@ -129,6 +146,7 @@ enum nfc_commands {
* @NFC_ATTR_FIRMWARE_NAME: Free format firmware version
* @NFC_ATTR_SE_INDEX: Secure element index
* @NFC_ATTR_SE_TYPE: Secure element type (UICC or EMBEDDED)
* @NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS: Firmware download operation status
*/
enum nfc_attrs {
NFC_ATTR_UNSPEC,
@ -154,6 +172,8 @@ enum nfc_attrs {
NFC_ATTR_FIRMWARE_NAME,
NFC_ATTR_SE_INDEX,
NFC_ATTR_SE_TYPE,
NFC_ATTR_SE_AID,
NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS,
/* private: internal use only */
__NFC_ATTR_AFTER_LAST
};

View File

@ -77,11 +77,19 @@ error:
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;
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);
@ -129,7 +137,7 @@ int nfc_dev_up(struct nfc_dev *dev)
/* We have to enable the device before discovering SEs */
if (dev->ops->discover_se) {
rc = dev->ops->discover_se(dev);
if (!rc)
if (rc)
pr_warn("SE discovery failed\n");
}
@ -575,12 +583,14 @@ int nfc_enable_se(struct nfc_dev *dev, u32 se_idx)
goto error;
}
if (se->type == NFC_SE_ENABLED) {
if (se->state == NFC_SE_ENABLED) {
rc = -EALREADY;
goto error;
}
rc = dev->ops->enable_se(dev, se_idx);
if (rc >= 0)
se->state = NFC_SE_ENABLED;
error:
device_unlock(&dev->dev);
@ -618,12 +628,14 @@ int nfc_disable_se(struct nfc_dev *dev, u32 se_idx)
goto error;
}
if (se->type == NFC_SE_DISABLED) {
if (se->state == NFC_SE_DISABLED) {
rc = -EALREADY;
goto error;
}
rc = dev->ops->disable_se(dev, se_idx);
if (rc >= 0)
se->state = NFC_SE_DISABLED;
error:
device_unlock(&dev->dev);

View File

@ -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);
if (hdev->ops->disable_se)
return hdev->ops->enable_se(hdev, se_idx);
return hdev->ops->disable_se(hdev, se_idx);
return 0;
}

View File

@ -1114,7 +1114,8 @@ static int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info)
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;
void *hdr;
@ -1129,6 +1130,7 @@ int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name)
goto free_msg;
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))
goto nla_put_failure;
@ -1191,6 +1193,91 @@ static int nfc_genl_disable_se(struct sk_buff *skb, struct genl_info *info)
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[] = {
{
.cmd = NFC_CMD_GET_DEVICE,
@ -1265,6 +1352,12 @@ static struct genl_ops nfc_genl_ops[] = {
.doit = nfc_genl_disable_se,
.policy = nfc_genl_policy,
},
{
.cmd = NFC_CMD_GET_SE,
.dumpit = nfc_genl_dump_ses,
.done = nfc_genl_dump_ses_done,
.policy = nfc_genl_policy,
},
};

View File

@ -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_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name);
int nfc_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_dev_up(struct nfc_dev *dev);