1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2012 Intel Corporation. All rights reserved.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #define pr_fmt(fmt) "hci: %s: " fmt, __func__
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/init.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/sched.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <net/nfc/hci.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include "hci.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define MAX_FWI 4949
18*4882a593Smuzhiyun
nfc_hci_execute_cmd_async(struct nfc_hci_dev * hdev,u8 pipe,u8 cmd,const u8 * param,size_t param_len,data_exchange_cb_t cb,void * cb_context)19*4882a593Smuzhiyun static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
20*4882a593Smuzhiyun const u8 *param, size_t param_len,
21*4882a593Smuzhiyun data_exchange_cb_t cb, void *cb_context)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun pr_debug("exec cmd async through pipe=%d, cmd=%d, plen=%zd\n", pipe,
24*4882a593Smuzhiyun cmd, param_len);
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* TODO: Define hci cmd execution delay. Should it be the same
27*4882a593Smuzhiyun * for all commands?
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_COMMAND, cmd,
30*4882a593Smuzhiyun param, param_len, cb, cb_context, MAX_FWI);
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun * HCI command execution completion callback.
35*4882a593Smuzhiyun * err will be a standard linux error (may be converted from HCI response)
36*4882a593Smuzhiyun * skb contains the response data and must be disposed, or may be NULL if
37*4882a593Smuzhiyun * an error occured
38*4882a593Smuzhiyun */
nfc_hci_execute_cb(void * context,struct sk_buff * skb,int err)39*4882a593Smuzhiyun static void nfc_hci_execute_cb(void *context, struct sk_buff *skb, int err)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)context;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun pr_debug("HCI Cmd completed with result=%d\n", err);
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun hcp_ew->exec_result = err;
46*4882a593Smuzhiyun if (hcp_ew->exec_result == 0)
47*4882a593Smuzhiyun hcp_ew->result_skb = skb;
48*4882a593Smuzhiyun else
49*4882a593Smuzhiyun kfree_skb(skb);
50*4882a593Smuzhiyun hcp_ew->exec_complete = true;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun wake_up(hcp_ew->wq);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
nfc_hci_execute_cmd(struct nfc_hci_dev * hdev,u8 pipe,u8 cmd,const u8 * param,size_t param_len,struct sk_buff ** skb)55*4882a593Smuzhiyun static int nfc_hci_execute_cmd(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
56*4882a593Smuzhiyun const u8 *param, size_t param_len,
57*4882a593Smuzhiyun struct sk_buff **skb)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun DECLARE_WAIT_QUEUE_HEAD_ONSTACK(ew_wq);
60*4882a593Smuzhiyun struct hcp_exec_waiter hcp_ew;
61*4882a593Smuzhiyun hcp_ew.wq = &ew_wq;
62*4882a593Smuzhiyun hcp_ew.exec_complete = false;
63*4882a593Smuzhiyun hcp_ew.result_skb = NULL;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun pr_debug("exec cmd sync through pipe=%d, cmd=%d, plen=%zd\n", pipe,
66*4882a593Smuzhiyun cmd, param_len);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /* TODO: Define hci cmd execution delay. Should it be the same
69*4882a593Smuzhiyun * for all commands?
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun hcp_ew.exec_result = nfc_hci_hcp_message_tx(hdev, pipe,
72*4882a593Smuzhiyun NFC_HCI_HCP_COMMAND, cmd,
73*4882a593Smuzhiyun param, param_len,
74*4882a593Smuzhiyun nfc_hci_execute_cb, &hcp_ew,
75*4882a593Smuzhiyun MAX_FWI);
76*4882a593Smuzhiyun if (hcp_ew.exec_result < 0)
77*4882a593Smuzhiyun return hcp_ew.exec_result;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun wait_event(ew_wq, hcp_ew.exec_complete == true);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun if (hcp_ew.exec_result == 0) {
82*4882a593Smuzhiyun if (skb)
83*4882a593Smuzhiyun *skb = hcp_ew.result_skb;
84*4882a593Smuzhiyun else
85*4882a593Smuzhiyun kfree_skb(hcp_ew.result_skb);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun return hcp_ew.exec_result;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
nfc_hci_send_event(struct nfc_hci_dev * hdev,u8 gate,u8 event,const u8 * param,size_t param_len)91*4882a593Smuzhiyun int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,
92*4882a593Smuzhiyun const u8 *param, size_t param_len)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun u8 pipe;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun pr_debug("%d to gate %d\n", event, gate);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun pipe = hdev->gate2pipe[gate];
99*4882a593Smuzhiyun if (pipe == NFC_HCI_INVALID_PIPE)
100*4882a593Smuzhiyun return -EADDRNOTAVAIL;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_EVENT, event,
103*4882a593Smuzhiyun param, param_len, NULL, NULL, 0);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun EXPORT_SYMBOL(nfc_hci_send_event);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /*
108*4882a593Smuzhiyun * Execute an hci command sent to gate.
109*4882a593Smuzhiyun * skb will contain response data if success. skb can be NULL if you are not
110*4882a593Smuzhiyun * interested by the response.
111*4882a593Smuzhiyun */
nfc_hci_send_cmd(struct nfc_hci_dev * hdev,u8 gate,u8 cmd,const u8 * param,size_t param_len,struct sk_buff ** skb)112*4882a593Smuzhiyun int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
113*4882a593Smuzhiyun const u8 *param, size_t param_len, struct sk_buff **skb)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun u8 pipe;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun pr_debug("\n");
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun pipe = hdev->gate2pipe[gate];
120*4882a593Smuzhiyun if (pipe == NFC_HCI_INVALID_PIPE)
121*4882a593Smuzhiyun return -EADDRNOTAVAIL;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun return nfc_hci_execute_cmd(hdev, pipe, cmd, param, param_len, skb);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun EXPORT_SYMBOL(nfc_hci_send_cmd);
126*4882a593Smuzhiyun
nfc_hci_send_cmd_async(struct nfc_hci_dev * hdev,u8 gate,u8 cmd,const u8 * param,size_t param_len,data_exchange_cb_t cb,void * cb_context)127*4882a593Smuzhiyun int nfc_hci_send_cmd_async(struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
128*4882a593Smuzhiyun const u8 *param, size_t param_len,
129*4882a593Smuzhiyun data_exchange_cb_t cb, void *cb_context)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun u8 pipe;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun pr_debug("\n");
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun pipe = hdev->gate2pipe[gate];
136*4882a593Smuzhiyun if (pipe == NFC_HCI_INVALID_PIPE)
137*4882a593Smuzhiyun return -EADDRNOTAVAIL;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun return nfc_hci_execute_cmd_async(hdev, pipe, cmd, param, param_len,
140*4882a593Smuzhiyun cb, cb_context);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun EXPORT_SYMBOL(nfc_hci_send_cmd_async);
143*4882a593Smuzhiyun
nfc_hci_set_param(struct nfc_hci_dev * hdev,u8 gate,u8 idx,const u8 * param,size_t param_len)144*4882a593Smuzhiyun int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx,
145*4882a593Smuzhiyun const u8 *param, size_t param_len)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun int r;
148*4882a593Smuzhiyun u8 *tmp;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /* TODO ELa: reg idx must be inserted before param, but we don't want
151*4882a593Smuzhiyun * to ask the caller to do it to keep a simpler API.
152*4882a593Smuzhiyun * For now, just create a new temporary param buffer. This is far from
153*4882a593Smuzhiyun * optimal though, and the plan is to modify APIs to pass idx down to
154*4882a593Smuzhiyun * nfc_hci_hcp_message_tx where the frame is actually built, thereby
155*4882a593Smuzhiyun * eliminating the need for the temp allocation-copy here.
156*4882a593Smuzhiyun */
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun pr_debug("idx=%d to gate %d\n", idx, gate);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun tmp = kmalloc(1 + param_len, GFP_KERNEL);
161*4882a593Smuzhiyun if (tmp == NULL)
162*4882a593Smuzhiyun return -ENOMEM;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun *tmp = idx;
165*4882a593Smuzhiyun memcpy(tmp + 1, param, param_len);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun r = nfc_hci_send_cmd(hdev, gate, NFC_HCI_ANY_SET_PARAMETER,
168*4882a593Smuzhiyun tmp, param_len + 1, NULL);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun kfree(tmp);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun return r;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun EXPORT_SYMBOL(nfc_hci_set_param);
175*4882a593Smuzhiyun
nfc_hci_get_param(struct nfc_hci_dev * hdev,u8 gate,u8 idx,struct sk_buff ** skb)176*4882a593Smuzhiyun int nfc_hci_get_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx,
177*4882a593Smuzhiyun struct sk_buff **skb)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun pr_debug("gate=%d regidx=%d\n", gate, idx);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun return nfc_hci_send_cmd(hdev, gate, NFC_HCI_ANY_GET_PARAMETER,
182*4882a593Smuzhiyun &idx, 1, skb);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun EXPORT_SYMBOL(nfc_hci_get_param);
185*4882a593Smuzhiyun
nfc_hci_open_pipe(struct nfc_hci_dev * hdev,u8 pipe)186*4882a593Smuzhiyun static int nfc_hci_open_pipe(struct nfc_hci_dev *hdev, u8 pipe)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun struct sk_buff *skb;
189*4882a593Smuzhiyun int r;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun pr_debug("pipe=%d\n", pipe);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun r = nfc_hci_execute_cmd(hdev, pipe, NFC_HCI_ANY_OPEN_PIPE,
194*4882a593Smuzhiyun NULL, 0, &skb);
195*4882a593Smuzhiyun if (r == 0) {
196*4882a593Smuzhiyun /* dest host other than host controller will send
197*4882a593Smuzhiyun * number of pipes already open on this gate before
198*4882a593Smuzhiyun * execution. The number can be found in skb->data[0]
199*4882a593Smuzhiyun */
200*4882a593Smuzhiyun kfree_skb(skb);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun return r;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
nfc_hci_close_pipe(struct nfc_hci_dev * hdev,u8 pipe)206*4882a593Smuzhiyun static int nfc_hci_close_pipe(struct nfc_hci_dev *hdev, u8 pipe)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun pr_debug("\n");
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun return nfc_hci_execute_cmd(hdev, pipe, NFC_HCI_ANY_CLOSE_PIPE,
211*4882a593Smuzhiyun NULL, 0, NULL);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
nfc_hci_create_pipe(struct nfc_hci_dev * hdev,u8 dest_host,u8 dest_gate,int * result)214*4882a593Smuzhiyun static u8 nfc_hci_create_pipe(struct nfc_hci_dev *hdev, u8 dest_host,
215*4882a593Smuzhiyun u8 dest_gate, int *result)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun struct sk_buff *skb;
218*4882a593Smuzhiyun struct hci_create_pipe_params params;
219*4882a593Smuzhiyun struct hci_create_pipe_resp *resp;
220*4882a593Smuzhiyun u8 pipe;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun pr_debug("gate=%d\n", dest_gate);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun params.src_gate = NFC_HCI_ADMIN_GATE;
225*4882a593Smuzhiyun params.dest_host = dest_host;
226*4882a593Smuzhiyun params.dest_gate = dest_gate;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun *result = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
229*4882a593Smuzhiyun NFC_HCI_ADM_CREATE_PIPE,
230*4882a593Smuzhiyun (u8 *) ¶ms, sizeof(params), &skb);
231*4882a593Smuzhiyun if (*result < 0)
232*4882a593Smuzhiyun return NFC_HCI_INVALID_PIPE;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun resp = (struct hci_create_pipe_resp *)skb->data;
235*4882a593Smuzhiyun pipe = resp->pipe;
236*4882a593Smuzhiyun kfree_skb(skb);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun pr_debug("pipe created=%d\n", pipe);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun return pipe;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
nfc_hci_delete_pipe(struct nfc_hci_dev * hdev,u8 pipe)243*4882a593Smuzhiyun static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun pr_debug("\n");
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
248*4882a593Smuzhiyun NFC_HCI_ADM_DELETE_PIPE, &pipe, 1, NULL);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
nfc_hci_clear_all_pipes(struct nfc_hci_dev * hdev)251*4882a593Smuzhiyun static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun u8 param[2];
254*4882a593Smuzhiyun size_t param_len = 2;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun /* TODO: Find out what the identity reference data is
257*4882a593Smuzhiyun * and fill param with it. HCI spec 6.1.3.5 */
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun pr_debug("\n");
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun if (test_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &hdev->quirks))
262*4882a593Smuzhiyun param_len = 0;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
265*4882a593Smuzhiyun NFC_HCI_ADM_CLEAR_ALL_PIPE, param, param_len,
266*4882a593Smuzhiyun NULL);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
nfc_hci_disconnect_gate(struct nfc_hci_dev * hdev,u8 gate)269*4882a593Smuzhiyun int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun int r;
272*4882a593Smuzhiyun u8 pipe = hdev->gate2pipe[gate];
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun pr_debug("\n");
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun if (pipe == NFC_HCI_INVALID_PIPE)
277*4882a593Smuzhiyun return -EADDRNOTAVAIL;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun r = nfc_hci_close_pipe(hdev, pipe);
280*4882a593Smuzhiyun if (r < 0)
281*4882a593Smuzhiyun return r;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun if (pipe != NFC_HCI_LINK_MGMT_PIPE && pipe != NFC_HCI_ADMIN_PIPE) {
284*4882a593Smuzhiyun r = nfc_hci_delete_pipe(hdev, pipe);
285*4882a593Smuzhiyun if (r < 0)
286*4882a593Smuzhiyun return r;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun hdev->gate2pipe[gate] = NFC_HCI_INVALID_PIPE;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun return 0;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun EXPORT_SYMBOL(nfc_hci_disconnect_gate);
294*4882a593Smuzhiyun
nfc_hci_disconnect_all_gates(struct nfc_hci_dev * hdev)295*4882a593Smuzhiyun int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun int r;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun pr_debug("\n");
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun r = nfc_hci_clear_all_pipes(hdev);
302*4882a593Smuzhiyun if (r < 0)
303*4882a593Smuzhiyun return r;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun nfc_hci_reset_pipes(hdev);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun return 0;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun EXPORT_SYMBOL(nfc_hci_disconnect_all_gates);
310*4882a593Smuzhiyun
nfc_hci_connect_gate(struct nfc_hci_dev * hdev,u8 dest_host,u8 dest_gate,u8 pipe)311*4882a593Smuzhiyun int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate,
312*4882a593Smuzhiyun u8 pipe)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun bool pipe_created = false;
315*4882a593Smuzhiyun int r;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun pr_debug("\n");
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (pipe == NFC_HCI_DO_NOT_CREATE_PIPE)
320*4882a593Smuzhiyun return 0;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE)
323*4882a593Smuzhiyun return -EADDRINUSE;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if (pipe != NFC_HCI_INVALID_PIPE)
326*4882a593Smuzhiyun goto open_pipe;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun switch (dest_gate) {
329*4882a593Smuzhiyun case NFC_HCI_LINK_MGMT_GATE:
330*4882a593Smuzhiyun pipe = NFC_HCI_LINK_MGMT_PIPE;
331*4882a593Smuzhiyun break;
332*4882a593Smuzhiyun case NFC_HCI_ADMIN_GATE:
333*4882a593Smuzhiyun pipe = NFC_HCI_ADMIN_PIPE;
334*4882a593Smuzhiyun break;
335*4882a593Smuzhiyun default:
336*4882a593Smuzhiyun pipe = nfc_hci_create_pipe(hdev, dest_host, dest_gate, &r);
337*4882a593Smuzhiyun if (pipe == NFC_HCI_INVALID_PIPE)
338*4882a593Smuzhiyun return r;
339*4882a593Smuzhiyun pipe_created = true;
340*4882a593Smuzhiyun break;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun open_pipe:
344*4882a593Smuzhiyun r = nfc_hci_open_pipe(hdev, pipe);
345*4882a593Smuzhiyun if (r < 0) {
346*4882a593Smuzhiyun if (pipe_created)
347*4882a593Smuzhiyun if (nfc_hci_delete_pipe(hdev, pipe) < 0) {
348*4882a593Smuzhiyun /* TODO: Cannot clean by deleting pipe...
349*4882a593Smuzhiyun * -> inconsistent state */
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun return r;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun hdev->pipes[pipe].gate = dest_gate;
355*4882a593Smuzhiyun hdev->pipes[pipe].dest_host = dest_host;
356*4882a593Smuzhiyun hdev->gate2pipe[dest_gate] = pipe;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun return 0;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun EXPORT_SYMBOL(nfc_hci_connect_gate);
361