]> git.openfabrics.org - ~emulex/infiniband.git/commitdiff
NFC: st21nfca: Implement load_session HCI hook
authorChristophe Ricard <christophe.ricard@gmail.com>
Tue, 25 Mar 2014 05:51:50 +0000 (06:51 +0100)
committerSamuel Ortiz <sameo@linux.intel.com>
Mon, 21 Apr 2014 22:37:26 +0000 (00:37 +0200)
This implementation rely on the ST21NFCA_DEVICE_MGNT_GATE and
ST21NFCA_DM_GETINFO proprietary gates commands.

First we are retrieving a pipe list available on the CLF with the
ST21NFCA_DM_GETINFO_PIPE_LIST parameter. A gate<->pipe table match
is done with ST21NFCA_DM_GETINFO_PIPE_INFO for each pipe.
If the pipe is created and open, we fill st21nfca_gates table.
If the pipe is create but closed or is not created we keep the gate
with NFC_HCI_INVALID_PIPE.

Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/nfc/st21nfca/st21nfca.c

index 69213f37b7ba93416724dc9376d0e29fc285f02c..9e9b9f1140c89b98d3f9ba628dc42e3fec072c7d 100644 (file)
 
 #define ST21NFCA_DEVICE_MGNT_GATE              0x01
 #define ST21NFCA_DEVICE_MGNT_PIPE              0x02
-#define ST21NFCA_NFC_MODE      0x03    /* NFC_MODE parameter*/
 
+#define ST21NFCA_DM_GETINFO         0x13
+#define ST21NFCA_DM_GETINFO_PIPE_LIST       0x02
+#define ST21NFCA_DM_GETINFO_PIPE_INFO       0x01
+#define ST21NFCA_DM_PIPE_CREATED        0x02
+#define ST21NFCA_DM_PIPE_OPEN           0x04
+#define ST21NFCA_DM_RF_ACTIVE           0x80
+
+#define ST21NFCA_DM_IS_PIPE_OPEN(p) \
+       ((p & 0x0f) == (ST21NFCA_DM_PIPE_CREATED | ST21NFCA_DM_PIPE_OPEN))
+
+#define ST21NFCA_NFC_MODE      0x03    /* NFC_MODE parameter*/
 
 static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES);
 
@@ -72,9 +82,113 @@ static struct nfc_hci_gate st21nfca_gates[] = {
        {ST21NFCA_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE},
        {ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE},
 };
+
+struct st21nfca_pipe_info {
+       u8 pipe_state;
+       u8 src_host_id;
+       u8 src_gate_id;
+       u8 dst_host_id;
+       u8 dst_gate_id;
+};
+
 /* Largest headroom needed for outgoing custom commands */
 #define ST21NFCA_CMDS_HEADROOM  7
 
+static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
+{
+       int i, j, r;
+       struct sk_buff *skb_pipe_list, *skb_pipe_info;
+       struct st21nfca_pipe_info *info;
+
+       u8 pipe_list[] = { ST21NFCA_DM_GETINFO_PIPE_LIST,
+               NFC_HCI_TERMINAL_HOST_ID
+       };
+       u8 pipe_info[] = { ST21NFCA_DM_GETINFO_PIPE_INFO,
+               NFC_HCI_TERMINAL_HOST_ID, 0
+       };
+
+       skb_pipe_list = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE, GFP_KERNEL);
+       if (!skb_pipe_list) {
+               r = -ENOMEM;
+               goto free_list;
+       }
+
+       skb_pipe_info = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE, GFP_KERNEL);
+       if (!skb_pipe_info) {
+               r = -ENOMEM;
+               goto free_info;
+       }
+
+       /* On ST21NFCA device pipes number are dynamics
+        * A maximum of 16 pipes can be created at the same time
+        * If pipes are already created, hci_dev_up will fail.
+        * Doing a clear all pipe is a bad idea because:
+        * - It does useless EEPROM cycling
+        * - It might cause issue for secure elements support
+        * (such as removing connectivity or APDU reader pipe)
+        * A better approach on ST21NFCA is to:
+        * - get a pipe list for each host.
+        * (eg: NFC_HCI_HOST_CONTROLLER_ID for now).
+        * (TODO Later on UICC HOST and eSE HOST)
+        * - get pipe information
+        * - match retrieved pipe list in st21nfca_gates
+        * ST21NFCA_DEVICE_MGNT_GATE is a proprietary gate
+        * with ST21NFCA_DEVICE_MGNT_PIPE.
+        * Pipe can be closed and need to be open.
+        */
+       r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID,
+               ST21NFCA_DEVICE_MGNT_GATE, ST21NFCA_DEVICE_MGNT_PIPE);
+       if (r < 0)
+               goto free_info;
+
+       /* Get pipe list */
+       r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
+                       ST21NFCA_DM_GETINFO, pipe_list, sizeof(pipe_list),
+                       &skb_pipe_list);
+       if (r < 0)
+               goto free_info;
+
+       /* Complete the existing gate_pipe table */
+       for (i = 0; i < skb_pipe_list->len; i++) {
+               pipe_info[2] = skb_pipe_list->data[i];
+               r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
+                                       ST21NFCA_DM_GETINFO, pipe_info,
+                                       sizeof(pipe_info), &skb_pipe_info);
+
+               if (r)
+                       continue;
+
+               /*
+                * Match pipe ID and gate ID
+                * Output format from ST21NFC_DM_GETINFO is:
+                * - pipe state (1byte)
+                * - source hid (1byte)
+                * - source gid (1byte)
+                * - destination hid (1byte)
+                * - destination gid (1byte)
+                */
+               info = (struct st21nfca_pipe_info *)
+                                       skb_pipe_info->data;
+               for (j = 0; (j < ARRAY_SIZE(st21nfca_gates)) &&
+                       (st21nfca_gates[j].gate != info->dst_gate_id);
+                       j++)
+                       ;
+
+               if (st21nfca_gates[j].gate == info->dst_gate_id &&
+                       ST21NFCA_DM_IS_PIPE_OPEN(info->pipe_state)) {
+                       st21nfca_gates[j].pipe = pipe_info[2];
+                       hdev->gate2pipe[st21nfca_gates[j].gate] =
+                               st21nfca_gates[j].pipe;
+               }
+       }
+       memcpy(hdev->init_data.gates, st21nfca_gates, sizeof(st21nfca_gates));
+free_info:
+       kfree_skb(skb_pipe_info);
+free_list:
+       kfree_skb(skb_pipe_list);
+       return r;
+}
+
 static int st21nfca_hci_open(struct nfc_hci_dev *hdev)
 {
        struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
@@ -407,6 +521,7 @@ static int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev,
 static struct nfc_hci_ops st21nfca_hci_ops = {
        .open = st21nfca_hci_open,
        .close = st21nfca_hci_close,
+       .load_session = st21nfca_hci_load_session,
        .hci_ready = st21nfca_hci_ready,
        .xmit = st21nfca_hci_xmit,
        .start_poll = st21nfca_hci_start_poll,