diff options
author | Christophe Ricard <christophe.ricard@gmail.com> | 2014-03-25 01:51:50 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-04-21 18:37:26 -0400 |
commit | 58e1e0a920358cd0dd7fdccc8cbcaa1d117078cf (patch) | |
tree | db23840b06a3a7faebfc8ad7cb0f3004bab471de /drivers/nfc | |
parent | e240bc36125691b0e18e70407c2d18ca6117c2f5 (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.c | 117 |
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 | ||
62 | static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES); | 72 | static 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 | |||
86 | struct 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 | ||
97 | static 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)); | ||
185 | free_info: | ||
186 | kfree_skb(skb_pipe_info); | ||
187 | free_list: | ||
188 | kfree_skb(skb_pipe_list); | ||
189 | return r; | ||
190 | } | ||
191 | |||
78 | static int st21nfca_hci_open(struct nfc_hci_dev *hdev) | 192 | static 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, | |||
407 | static struct nfc_hci_ops st21nfca_hci_ops = { | 521 | static 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, |