This source file includes following definitions.
- hci_attach
- hci_detach
- hci_enable
- hci_disable
- hci_unit_lookup
- hci_send_cmd
- hci_intr
- hci_input_event
- hci_input_acl
- hci_input_sco
- hci_output_cmd
- hci_output_acl
- hci_output_sco
- hci_complete_sco
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include <sys/cdefs.h>
35
36 #include <sys/param.h>
37 #include <sys/conf.h>
38 #include <sys/device.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/proc.h>
43 #include <sys/queue.h>
44 #include <sys/systm.h>
45
46 #include <net/netisr.h>
47
48 #include <netbt/bluetooth.h>
49 #include <netbt/hci.h>
50
51 struct hci_unit_list hci_unit_list = TAILQ_HEAD_INITIALIZER(hci_unit_list);
52
53
54
55
56 int hci_eventq_max = 20;
57 int hci_aclrxq_max = 50;
58 int hci_scorxq_max = 50;
59
60
61
62
63
64 void
65 hci_attach(struct hci_unit *unit)
66 {
67 KASSERT(unit->hci_softc != NULL);
68 KASSERT(unit->hci_devname != NULL);
69 KASSERT(unit->hci_enable != NULL);
70 KASSERT(unit->hci_disable != NULL);
71 KASSERT(unit->hci_start_cmd != NULL);
72 KASSERT(unit->hci_start_acl != NULL);
73 KASSERT(unit->hci_start_sco != NULL);
74
75 unit->hci_eventq.ifq_maxlen = hci_eventq_max;
76 unit->hci_aclrxq.ifq_maxlen = hci_aclrxq_max;
77 unit->hci_scorxq.ifq_maxlen = hci_scorxq_max;
78
79 TAILQ_INIT(&unit->hci_links);
80 LIST_INIT(&unit->hci_memos);
81
82 TAILQ_INSERT_TAIL(&hci_unit_list, unit, hci_next);
83 }
84
85 void
86 hci_detach(struct hci_unit *unit)
87 {
88 hci_disable(unit);
89
90 TAILQ_REMOVE(&hci_unit_list, unit, hci_next);
91 }
92
93 int
94 hci_enable(struct hci_unit *unit)
95 {
96 int s, err;
97
98
99
100
101
102
103
104
105
106
107 unit->hci_num_cmd_pkts = 1;
108 unit->hci_num_acl_pkts = 0;
109 unit->hci_num_sco_pkts = 0;
110
111
112
113
114
115 unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
116 unit->hci_packet_type = unit->hci_acl_mask;
117
118 s = splraiseipl(unit->hci_ipl);
119 err = (*unit->hci_enable)(unit);
120 splx(s);
121 if (err)
122 goto bad1;
123
124
125
126
127
128 unit->hci_flags |= BTF_INIT;
129
130 err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0);
131 if (err)
132 goto bad2;
133
134 while (unit->hci_flags & BTF_INIT) {
135 err = tsleep(unit, PWAIT | PCATCH, __func__, 5 * hz);
136 if (err)
137 goto bad2;
138
139
140
141
142
143 }
144
145
146
147
148 unit->hci_bthub = config_found(unit->hci_softc,
149 &unit->hci_bdaddr, NULL);
150
151 return 0;
152
153 bad2:
154 s = splraiseipl(unit->hci_ipl);
155 (*unit->hci_disable)(unit);
156 splx(s);
157
158 bad1:
159 return err;
160 }
161
162 void
163 hci_disable(struct hci_unit *unit)
164 {
165 struct hci_link *link, *next;
166 struct hci_memo *memo;
167 int s, acl;
168
169 if (unit->hci_bthub) {
170 config_detach(unit->hci_bthub, DETACH_FORCE);
171 unit->hci_bthub = NULL;
172 }
173
174 s = splraiseipl(unit->hci_ipl);
175 (*unit->hci_disable)(unit);
176 splx(s);
177
178
179
180
181
182 for (acl = 0 ; acl < 2 ; acl++) {
183 next = TAILQ_FIRST(&unit->hci_links);
184 while ((link = next) != NULL) {
185 next = TAILQ_NEXT(link, hl_next);
186 if (acl || link->hl_type != HCI_LINK_ACL)
187 hci_link_free(link, ECONNABORTED);
188 }
189 }
190
191 while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
192 hci_memo_free(memo);
193
194 IF_PURGE(&unit->hci_eventq);
195 unit->hci_eventqlen = 0;
196
197 IF_PURGE(&unit->hci_aclrxq);
198 unit->hci_aclrxqlen = 0;
199
200 IF_PURGE(&unit->hci_scorxq);
201 unit->hci_scorxqlen = 0;
202
203 IF_PURGE(&unit->hci_cmdq);
204 IF_PURGE(&unit->hci_cmdwait);
205 IF_PURGE(&unit->hci_acltxq);
206 IF_PURGE(&unit->hci_scotxq);
207 IF_PURGE(&unit->hci_scodone);
208 }
209
210 struct hci_unit *
211 hci_unit_lookup(bdaddr_t *addr)
212 {
213 struct hci_unit *unit;
214
215 TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
216 if ((unit->hci_flags & BTF_UP) == 0)
217 continue;
218
219 if (bdaddr_same(&unit->hci_bdaddr, addr))
220 break;
221 }
222
223 return unit;
224 }
225
226
227
228
229 int
230 hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
231 {
232 struct mbuf *m;
233 hci_cmd_hdr_t *p;
234
235 KASSERT(unit != NULL);
236
237 m = m_gethdr(M_DONTWAIT, MT_DATA);
238 if (m == NULL)
239 return ENOMEM;
240
241 p = mtod(m, hci_cmd_hdr_t *);
242 p->type = HCI_CMD_PKT;
243 p->opcode = htole16(opcode);
244 p->length = len;
245 m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
246 M_SETCTX(m, NULL);
247
248 if (len) {
249 KASSERT(buf != NULL);
250
251 m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
252 if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
253 m_freem(m);
254 return ENOMEM;
255 }
256 }
257
258 DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", unit->hci_devname,
259 HCI_OGF(opcode), HCI_OCF(opcode));
260
261
262 if (unit->hci_num_cmd_pkts == 0)
263 IF_ENQUEUE(&unit->hci_cmdwait, m);
264 else
265 hci_output_cmd(unit, m);
266
267 return 0;
268 }
269
270
271
272
273
274
275
276 void
277 hci_intr(void *arg)
278 {
279 struct hci_unit *unit = arg;
280 struct mbuf *m;
281 int s;
282
283 another:
284 s = splraiseipl(unit->hci_ipl);
285
286 if (unit->hci_eventqlen > 0) {
287 IF_DEQUEUE(&unit->hci_eventq, m);
288 unit->hci_eventqlen--;
289 KASSERT(m != NULL);
290 splx(s);
291
292 DPRINTFN(10, "(%s) recv event, len = %d\n",
293 unit->hci_devname, m->m_pkthdr.len);
294
295 m->m_flags |= M_LINK0;
296 hci_mtap(m, unit);
297 hci_event(m, unit);
298
299 goto another;
300 }
301
302 if (unit->hci_scorxqlen > 0) {
303 IF_DEQUEUE(&unit->hci_scorxq, m);
304 unit->hci_scorxqlen--;
305 KASSERT(m != NULL);
306 splx(s);
307
308 DPRINTFN(10, "(%s) recv SCO, len = %d\n",
309 unit->hci_devname, m->m_pkthdr.len);
310
311 m->m_flags |= M_LINK0;
312 hci_mtap(m, unit);
313 hci_sco_recv(m, unit);
314
315 goto another;
316 }
317
318 if (unit->hci_aclrxqlen > 0) {
319 IF_DEQUEUE(&unit->hci_aclrxq, m);
320 unit->hci_aclrxqlen--;
321 KASSERT(m != NULL);
322 splx(s);
323
324 DPRINTFN(10, "(%s) recv ACL, len = %d\n",
325 unit->hci_devname, m->m_pkthdr.len);
326
327 m->m_flags |= M_LINK0;
328 hci_mtap(m, unit);
329 hci_acl_recv(m, unit);
330
331 goto another;
332 }
333
334 IF_DEQUEUE(&unit->hci_scodone, m);
335 if (m != NULL) {
336 struct hci_link *link;
337 splx(s);
338
339 DPRINTFN(11, "(%s) complete SCO\n",
340 unit->hci_devname);
341
342 TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
343 if (link == M_GETCTX(m, struct hci_link *)) {
344 hci_sco_complete(link, 1);
345 break;
346 }
347 }
348
349 unit->hci_num_sco_pkts++;
350 m_freem(m);
351
352 goto another;
353 }
354
355 splx(s);
356
357 DPRINTFN(10, "done\n");
358 }
359
360
361
362
363
364
365
366
367
368 void
369 hci_input_event(struct hci_unit *unit, struct mbuf *m)
370 {
371 if (unit->hci_eventqlen > hci_eventq_max) {
372 DPRINTF("(%s) dropped event packet.\n", unit->hci_devname);
373 unit->hci_stats.err_rx++;
374 m_freem(m);
375 } else {
376 unit->hci_eventqlen++;
377 IF_ENQUEUE(&unit->hci_eventq, m);
378 schednetisr(NETISR_BT);
379 }
380 }
381
382 void
383 hci_input_acl(struct hci_unit *unit, struct mbuf *m)
384 {
385 if (unit->hci_aclrxqlen > hci_aclrxq_max) {
386 DPRINTF("(%s) dropped ACL packet.\n", unit->hci_devname);
387 unit->hci_stats.err_rx++;
388 m_freem(m);
389 } else {
390 unit->hci_aclrxqlen++;
391 IF_ENQUEUE(&unit->hci_aclrxq, m);
392 schednetisr(NETISR_BT);
393 }
394 }
395
396 void
397 hci_input_sco(struct hci_unit *unit, struct mbuf *m)
398 {
399 if (unit->hci_scorxqlen > hci_scorxq_max) {
400 DPRINTF("(%s) dropped SCO packet.\n", unit->hci_devname);
401 unit->hci_stats.err_rx++;
402 m_freem(m);
403 } else {
404 unit->hci_scorxqlen++;
405 IF_ENQUEUE(&unit->hci_scorxq, m);
406 schednetisr(NETISR_BT);
407 }
408 }
409
410 void
411 hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
412 {
413 void *arg;
414 int s;
415
416 hci_mtap(m, unit);
417
418 DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", unit->hci_devname,
419 unit->hci_num_cmd_pkts);
420
421 unit->hci_num_cmd_pkts--;
422
423
424
425
426
427 arg = M_GETCTX(m, void *);
428 if (arg != NULL)
429 hci_drop(arg);
430
431 s = splraiseipl(unit->hci_ipl);
432 IF_ENQUEUE(&unit->hci_cmdq, m);
433 if ((unit->hci_flags & BTF_XMIT_CMD) == 0)
434 (*unit->hci_start_cmd)(unit);
435
436 splx(s);
437 }
438
439 void
440 hci_output_acl(struct hci_unit *unit, struct mbuf *m)
441 {
442 int s;
443
444 hci_mtap(m, unit);
445
446 DPRINTFN(10, "(%s) num_acl_pkts=%d\n", unit->hci_devname,
447 unit->hci_num_acl_pkts);
448
449 unit->hci_num_acl_pkts--;
450
451 s = splraiseipl(unit->hci_ipl);
452 IF_ENQUEUE(&unit->hci_acltxq, m);
453 if ((unit->hci_flags & BTF_XMIT_ACL) == 0)
454 (*unit->hci_start_acl)(unit);
455
456 splx(s);
457 }
458
459 void
460 hci_output_sco(struct hci_unit *unit, struct mbuf *m)
461 {
462 int s;
463
464 hci_mtap(m, unit);
465
466 DPRINTFN(10, "(%s) num_sco_pkts=%d\n", unit->hci_devname,
467 unit->hci_num_sco_pkts);
468
469 unit->hci_num_sco_pkts--;
470
471 s = splraiseipl(unit->hci_ipl);
472 IF_ENQUEUE(&unit->hci_scotxq, m);
473 if ((unit->hci_flags & BTF_XMIT_SCO) == 0)
474 (*unit->hci_start_sco)(unit);
475
476 splx(s);
477 }
478
479 void
480 hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
481 {
482 IF_ENQUEUE(&unit->hci_scodone, m);
483 schednetisr(NETISR_BT);
484 }