aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nfc
diff options
context:
space:
mode:
authorChristophe Ricard <christophe.ricard@gmail.com>2014-03-25 01:51:50 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2014-04-21 18:37:26 -0400
commit58e1e0a920358cd0dd7fdccc8cbcaa1d117078cf (patch)
treedb23840b06a3a7faebfc8ad7cb0f3004bab471de /drivers/nfc
parente240bc36125691b0e18e70407c2d18ca6117c2f5 (diff)
NFC: st21nfca: Implement load_session HCI hook
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>
Diffstat (limited to 'drivers/nfc')
-rw-r--r--drivers/nfc/st21nfca/st21nfca.c117
1 files changed, 116 insertions, 1 deletions
diff --git a/drivers/nfc/st21nfca/st21nfca.c b/drivers/nfc/st21nfca/st21nfca.c
index 69213f37b7ba..9e9b9f1140c8 100644
--- a/drivers/nfc/st21nfca/st21nfca.c
+++ b/drivers/nfc/st21nfca/st21nfca.c
@@ -56,8 +56,18 @@
56 56
57#define ST21NFCA_DEVICE_MGNT_GATE 0x01 57#define ST21NFCA_DEVICE_MGNT_GATE 0x01
58#define ST21NFCA_DEVICE_MGNT_PIPE 0x02 58#define ST21NFCA_DEVICE_MGNT_PIPE 0x02
59#define ST21NFCA_NFC_MODE 0x03 /* NFC_MODE parameter*/
60 59
60#define ST21NFCA_DM_GETINFO 0x13
61#define ST21NFCA_DM_GETINFO_PIPE_LIST 0x02
62#define ST21NFCA_DM_GETINFO_PIPE_INFO 0x01
63#define ST21NFCA_DM_PIPE_CREATED 0x02
64#define ST21NFCA_DM_PIPE_OPEN 0x04
65#define ST21NFCA_DM_RF_ACTIVE 0x80
66
67#define ST21NFCA_DM_IS_PIPE_OPEN(p) \
68 ((p & 0x0f) == (ST21NFCA_DM_PIPE_CREATED | ST21NFCA_DM_PIPE_OPEN))
69
70#define ST21NFCA_NFC_MODE 0x03 /* NFC_MODE parameter*/
61 71
62static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES); 72static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES);
63 73
@@ -72,9 +82,113 @@ static struct nfc_hci_gate st21nfca_gates[] = {
72 {ST21NFCA_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE}, 82 {ST21NFCA_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE},
73 {ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE}, 83 {ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE},
74}; 84};
85
86struct st21nfca_pipe_info {
87 u8 pipe_state;
88 u8 src_host_id;
89 u8 src_gate_id;
90 u8 dst_host_id;
91 u8 dst_gate_id;
92};
93
75/* Largest headroom needed for outgoing custom commands */ 94/* Largest headroom needed for outgoing custom commands */
76#define ST21NFCA_CMDS_HEADROOM 7 95#define ST21NFCA_CMDS_HEADROOM 7
77 96
97static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
98{
99 int i, j, r;
100 struct sk_buff *skb_pipe_list, *skb_pipe_info;
101 struct st21nfca_pipe_info *info;
102
103 u8 pipe_list[] = { ST21NFCA_DM_GETINFO_PIPE_LIST,
104 NFC_HCI_TERMINAL_HOST_ID
105 };
106 u8 pipe_info[] = { ST21NFCA_DM_GETINFO_PIPE_INFO,
107 NFC_HCI_TERMINAL_HOST_ID, 0
108 };
109
110 skb_pipe_list = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE, GFP_KERNEL);
111 if (!skb_pipe_list) {
112 r = -ENOMEM;
113 goto free_list;
114 }
115
116 skb_pipe_info = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE, GFP_KERNEL);
117 if (!skb_pipe_info) {
118 r = -ENOMEM;
119 goto free_info;
120 }
121
122 /* On ST21NFCA device pipes number are dynamics
123 * A maximum of 16 pipes can be created at the same time
124 * If pipes are already created, hci_dev_up will fail.
125 * Doing a clear all pipe is a bad idea because:
126 * - It does useless EEPROM cycling
127 * - It might cause issue for secure elements support
128 * (such as removing connectivity or APDU reader pipe)
129 * A better approach on ST21NFCA is to:
130 * - get a pipe list for each host.
131 * (eg: NFC_HCI_HOST_CONTROLLER_ID for now).
132 * (TODO Later on UICC HOST and eSE HOST)
133 * - get pipe information
134 * - match retrieved pipe list in st21nfca_gates
135 * ST21NFCA_DEVICE_MGNT_GATE is a proprietary gate
136 * with ST21NFCA_DEVICE_MGNT_PIPE.
137 * Pipe can be closed and need to be open.
138 */
139 r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID,
140 ST21NFCA_DEVICE_MGNT_GATE, ST21NFCA_DEVICE_MGNT_PIPE);
141 if (r < 0)
142 goto free_info;
143
144 /* Get pipe list */
145 r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
146 ST21NFCA_DM_GETINFO, pipe_list, sizeof(pipe_list),
147 &skb_pipe_list);
148 if (r < 0)
149 goto free_info;
150
151 /* Complete the existing gate_pipe table */
152 for (i = 0; i < skb_pipe_list->len; i++) {
153 pipe_info[2] = skb_pipe_list->data[i];
154 r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
155 ST21NFCA_DM_GETINFO, pipe_info,
156 sizeof(pipe_info), &skb_pipe_info);
157
158 if (r)
159 continue;
160
161 /*
162 * Match pipe ID and gate ID
163 * Output format from ST21NFC_DM_GETINFO is:
164 * - pipe state (1byte)
165 * - source hid (1byte)
166 * - source gid (1byte)
167 * - destination hid (1byte)
168 * - destination gid (1byte)
169 */
170 info = (struct st21nfca_pipe_info *)
171 skb_pipe_info->data;
172 for (j = 0; (j < ARRAY_SIZE(st21nfca_gates)) &&
173 (st21nfca_gates[j].gate != info->dst_gate_id);
174 j++)
175 ;
176
177 if (st21nfca_gates[j].gate == info->dst_gate_id &&
178 ST21NFCA_DM_IS_PIPE_OPEN(info->pipe_state)) {
179 st21nfca_gates[j].pipe = pipe_info[2];
180 hdev->gate2pipe[st21nfca_gates[j].gate] =
181 st21nfca_gates[j].pipe;
182 }
183 }
184 memcpy(hdev->init_data.gates, st21nfca_gates, sizeof(st21nfca_gates));
185free_info:
186 kfree_skb(skb_pipe_info);
187free_list:
188 kfree_skb(skb_pipe_list);
189 return r;
190}
191
78static int st21nfca_hci_open(struct nfc_hci_dev *hdev) 192static int st21nfca_hci_open(struct nfc_hci_dev *hdev)
79{ 193{
80 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 194 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,
407static struct nfc_hci_ops st21nfca_hci_ops = { 521static struct nfc_hci_ops st21nfca_hci_ops = {
408 .open = st21nfca_hci_open, 522 .open = st21nfca_hci_open,
409 .close = st21nfca_hci_close, 523 .close = st21nfca_hci_close,
524 .load_session = st21nfca_hci_load_session,
410 .hci_ready = st21nfca_hci_ready, 525 .hci_ready = st21nfca_hci_ready,
411 .xmit = st21nfca_hci_xmit, 526 .xmit = st21nfca_hci_xmit,
412 .start_poll = st21nfca_hci_start_poll, 527 .start_poll = st21nfca_hci_start_poll,