|
@@ -167,6 +167,18 @@ static __u8 *nci_extract_rf_params_nfcv_passive_poll(struct nci_dev *ndev,
|
|
|
return data;
|
|
|
}
|
|
|
|
|
|
+static __u8 *nci_extract_rf_params_nfcf_passive_listen(struct nci_dev *ndev,
|
|
|
+ struct rf_tech_specific_params_nfcf_listen *nfcf_listen,
|
|
|
+ __u8 *data)
|
|
|
+{
|
|
|
+ nfcf_listen->local_nfcid2_len = min_t(__u8, *data++,
|
|
|
+ NFC_NFCID2_MAXSIZE);
|
|
|
+ memcpy(nfcf_listen->local_nfcid2, data, nfcf_listen->local_nfcid2_len);
|
|
|
+ data += nfcf_listen->local_nfcid2_len;
|
|
|
+
|
|
|
+ return data;
|
|
|
+}
|
|
|
+
|
|
|
__u32 nci_get_prop_rf_protocol(struct nci_dev *ndev, __u8 rf_protocol)
|
|
|
{
|
|
|
if (ndev->ops->get_rfprotocol)
|
|
@@ -401,17 +413,29 @@ static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev,
|
|
|
struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
|
|
|
{
|
|
|
struct activation_params_poll_nfc_dep *poll;
|
|
|
+ struct activation_params_listen_nfc_dep *listen;
|
|
|
|
|
|
switch (ntf->activation_rf_tech_and_mode) {
|
|
|
case NCI_NFC_A_PASSIVE_POLL_MODE:
|
|
|
case NCI_NFC_F_PASSIVE_POLL_MODE:
|
|
|
poll = &ntf->activation_params.poll_nfc_dep;
|
|
|
- poll->atr_res_len = min_t(__u8, *data++, 63);
|
|
|
+ poll->atr_res_len = min_t(__u8, *data++,
|
|
|
+ NFC_ATR_RES_MAXSIZE - 2);
|
|
|
pr_debug("atr_res_len %d\n", poll->atr_res_len);
|
|
|
if (poll->atr_res_len > 0)
|
|
|
memcpy(poll->atr_res, data, poll->atr_res_len);
|
|
|
break;
|
|
|
|
|
|
+ case NCI_NFC_A_PASSIVE_LISTEN_MODE:
|
|
|
+ case NCI_NFC_F_PASSIVE_LISTEN_MODE:
|
|
|
+ listen = &ntf->activation_params.listen_nfc_dep;
|
|
|
+ listen->atr_req_len = min_t(__u8, *data++,
|
|
|
+ NFC_ATR_REQ_MAXSIZE - 2);
|
|
|
+ pr_debug("atr_req_len %d\n", listen->atr_req_len);
|
|
|
+ if (listen->atr_req_len > 0)
|
|
|
+ memcpy(listen->atr_req, data, listen->atr_req_len);
|
|
|
+ break;
|
|
|
+
|
|
|
default:
|
|
|
pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
|
|
|
ntf->activation_rf_tech_and_mode);
|
|
@@ -444,6 +468,50 @@ static void nci_target_auto_activated(struct nci_dev *ndev,
|
|
|
nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets);
|
|
|
}
|
|
|
|
|
|
+static int nci_store_general_bytes_nfc_dep(struct nci_dev *ndev,
|
|
|
+ struct nci_rf_intf_activated_ntf *ntf)
|
|
|
+{
|
|
|
+ ndev->remote_gb_len = 0;
|
|
|
+
|
|
|
+ if (ntf->activation_params_len <= 0)
|
|
|
+ return NCI_STATUS_OK;
|
|
|
+
|
|
|
+ switch (ntf->activation_rf_tech_and_mode) {
|
|
|
+ case NCI_NFC_A_PASSIVE_POLL_MODE:
|
|
|
+ case NCI_NFC_F_PASSIVE_POLL_MODE:
|
|
|
+ /* ATR_RES general bytes at offset 15 */
|
|
|
+ ndev->remote_gb_len = min_t(__u8,
|
|
|
+ (ntf->activation_params.poll_nfc_dep.atr_res_len
|
|
|
+ - NFC_ATR_RES_GT_OFFSET),
|
|
|
+ NFC_MAX_GT_LEN);
|
|
|
+ memcpy(ndev->remote_gb,
|
|
|
+ (ntf->activation_params.poll_nfc_dep .atr_res
|
|
|
+ + NFC_ATR_RES_GT_OFFSET),
|
|
|
+ ndev->remote_gb_len);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case NCI_NFC_A_PASSIVE_LISTEN_MODE:
|
|
|
+ case NCI_NFC_F_PASSIVE_LISTEN_MODE:
|
|
|
+ /* ATR_REQ general bytes at offset 14 */
|
|
|
+ ndev->remote_gb_len = min_t(__u8,
|
|
|
+ (ntf->activation_params.listen_nfc_dep.atr_req_len
|
|
|
+ - NFC_ATR_REQ_GT_OFFSET),
|
|
|
+ NFC_MAX_GT_LEN);
|
|
|
+ memcpy(ndev->remote_gb,
|
|
|
+ (ntf->activation_params.listen_nfc_dep.atr_req
|
|
|
+ + NFC_ATR_REQ_GT_OFFSET),
|
|
|
+ ndev->remote_gb_len);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
|
|
|
+ ntf->activation_rf_tech_and_mode);
|
|
|
+ return NCI_STATUS_RF_PROTOCOL_ERROR;
|
|
|
+ }
|
|
|
+
|
|
|
+ return NCI_STATUS_OK;
|
|
|
+}
|
|
|
+
|
|
|
static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
|
|
struct sk_buff *skb)
|
|
|
{
|
|
@@ -493,6 +561,16 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
|
|
&(ntf.rf_tech_specific_params.nfcv_poll), data);
|
|
|
break;
|
|
|
|
|
|
+ case NCI_NFC_A_PASSIVE_LISTEN_MODE:
|
|
|
+ /* no RF technology specific parameters */
|
|
|
+ break;
|
|
|
+
|
|
|
+ case NCI_NFC_F_PASSIVE_LISTEN_MODE:
|
|
|
+ data = nci_extract_rf_params_nfcf_passive_listen(ndev,
|
|
|
+ &(ntf.rf_tech_specific_params.nfcf_listen),
|
|
|
+ data);
|
|
|
+ break;
|
|
|
+
|
|
|
default:
|
|
|
pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
|
|
|
ntf.activation_rf_tech_and_mode);
|
|
@@ -546,32 +624,39 @@ exit:
|
|
|
|
|
|
/* store general bytes to be reported later in dep_link_up */
|
|
|
if (ntf.rf_interface == NCI_RF_INTERFACE_NFC_DEP) {
|
|
|
- ndev->remote_gb_len = 0;
|
|
|
-
|
|
|
- if (ntf.activation_params_len > 0) {
|
|
|
- /* ATR_RES general bytes at offset 15 */
|
|
|
- ndev->remote_gb_len = min_t(__u8,
|
|
|
- (ntf.activation_params
|
|
|
- .poll_nfc_dep.atr_res_len
|
|
|
- - NFC_ATR_RES_GT_OFFSET),
|
|
|
- NFC_MAX_GT_LEN);
|
|
|
- memcpy(ndev->remote_gb,
|
|
|
- (ntf.activation_params.poll_nfc_dep
|
|
|
- .atr_res + NFC_ATR_RES_GT_OFFSET),
|
|
|
- ndev->remote_gb_len);
|
|
|
- }
|
|
|
+ err = nci_store_general_bytes_nfc_dep(ndev, &ntf);
|
|
|
+ if (err != NCI_STATUS_OK)
|
|
|
+ pr_err("unable to store general bytes\n");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (atomic_read(&ndev->state) == NCI_DISCOVERY) {
|
|
|
- /* A single target was found and activated automatically */
|
|
|
- atomic_set(&ndev->state, NCI_POLL_ACTIVE);
|
|
|
- if (err == NCI_STATUS_OK)
|
|
|
- nci_target_auto_activated(ndev, &ntf);
|
|
|
- } else { /* ndev->state == NCI_W4_HOST_SELECT */
|
|
|
- /* A selected target was activated, so complete the request */
|
|
|
- atomic_set(&ndev->state, NCI_POLL_ACTIVE);
|
|
|
- nci_req_complete(ndev, err);
|
|
|
+ if (!(ntf.activation_rf_tech_and_mode & NCI_RF_TECH_MODE_LISTEN_MASK)) {
|
|
|
+ /* Poll mode */
|
|
|
+ if (atomic_read(&ndev->state) == NCI_DISCOVERY) {
|
|
|
+ /* A single target was found and activated
|
|
|
+ * automatically */
|
|
|
+ atomic_set(&ndev->state, NCI_POLL_ACTIVE);
|
|
|
+ if (err == NCI_STATUS_OK)
|
|
|
+ nci_target_auto_activated(ndev, &ntf);
|
|
|
+ } else { /* ndev->state == NCI_W4_HOST_SELECT */
|
|
|
+ /* A selected target was activated, so complete the
|
|
|
+ * request */
|
|
|
+ atomic_set(&ndev->state, NCI_POLL_ACTIVE);
|
|
|
+ nci_req_complete(ndev, err);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Listen mode */
|
|
|
+ atomic_set(&ndev->state, NCI_LISTEN_ACTIVE);
|
|
|
+ if (err == NCI_STATUS_OK &&
|
|
|
+ ntf.rf_protocol == NCI_RF_PROTOCOL_NFC_DEP) {
|
|
|
+ err = nfc_tm_activated(ndev->nfc_dev,
|
|
|
+ NFC_PROTO_NFC_DEP_MASK,
|
|
|
+ NFC_COMM_PASSIVE,
|
|
|
+ ndev->remote_gb,
|
|
|
+ ndev->remote_gb_len);
|
|
|
+ if (err != NCI_STATUS_OK)
|
|
|
+ pr_err("error when signaling tm activation\n");
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|