1 /* $NetBSD: bthci.c,v 1.15 2004/01/04 05:39:35 dsainty Exp $ */
2
3 /*
4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) and
9 * David Sainty (David.Sainty@dtsp.co.nz).
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: bthci.c,v 1.15 2004/01/04 05:39:35 dsainty Exp $");
42
43 #include "bthcidrv.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/ioctl.h>
48 #include <sys/kernel.h>
49 #include <sys/device.h>
50 #include <sys/conf.h>
51 #include <sys/malloc.h>
52 #include <sys/poll.h>
53 #include <sys/select.h>
54 #include <sys/vnode.h>
55
56 #include <dev/bluetooth/bluetooth.h>
57 #include <dev/bluetooth/bthci_util.h>
58 #include <dev/bluetooth/bthcivar.h>
59
60 #ifdef BTHCI_DEBUG
61 #define DPRINTF(x) if (bthcidebug) printf x
62 #define DPRINTFN(n,x) if (bthcidebug>(n)) printf x
63 #define Static
64 int bthcidebug = 99;
65 #else
66 #define DPRINTF(x)
67 #define DPRINTFN(n,x)
68 #define Static static
69 #endif
70
71 struct bthci_softc {
72 struct device sc_dev;
73 struct btframe_methods const *sc_methods;
74 void *sc_handle;
75
76 u_int8_t *sc_rd_buf;
77 size_t sc_rd_len;
78 struct selinfo sc_rd_sel;
79
80 int sc_refcnt;
81 int sc_outputready;
82 char sc_open;
83 char sc_dying;
84 };
85
86 int bthci_match(struct device *parent, struct cfdata *match, void *aux);
87 void bthci_attach(struct device *parent, struct device *self, void *aux);
88 int bthci_activate(struct device *self, enum devact act);
89 int bthci_detach(struct device *self, int flags);
90
91 #if NBTHCIDRV == 0
92 /* In case we just have tty attachment. */
93 struct cfdriver bthci_cd = {
94 NULL, "bthci", DV_DULL
95 };
96 #endif
97
98 CFATTACH_DECL(bthci, sizeof(struct bthci_softc),
99 bthci_match, bthci_attach, bthci_detach, bthci_activate);
100
101 extern struct cfdriver bthci_cd;
102
103 dev_type_open(bthciopen);
104 dev_type_close(bthciclose);
105 dev_type_poll(bthcipoll);
106 dev_type_kqfilter(bthcikqfilter);
107
108 static int bthciread(dev_t dev, struct uio *uio, int flag);
109 static int bthciwrite(dev_t dev, struct uio *uio, int flag);
110
111 static void bthci_recveventdata(void *h, u_int8_t *data, size_t len);
112 static void bthci_recvacldata(void *h, u_int8_t *data, size_t len);
113 static void bthci_recvscodata(void *h, u_int8_t *data, size_t len);
114
115 const struct cdevsw bthci_cdevsw = {
116 bthciopen, bthciclose, bthciread, bthciwrite, noioctl,
117 nostop, notty, bthcipoll, nommap, bthcikqfilter,
118 };
119
120 #define BTHCIUNIT(dev) (minor(dev))
121
122 struct btframe_callback_methods const bthci_callbacks = {
123 bthci_recveventdata, bthci_recvacldata, bthci_recvscodata
124 };
125
126 int
127 bthci_match(struct device *parent, struct cfdata *match, void *aux)
128 {
129 /*struct bt_attach_args *bt = aux;*/
130
131 return (1);
132 }
133
134 void
135 bthci_attach(struct device *parent, struct device *self, void *aux)
136 {
137 struct bthci_softc *sc = (struct bthci_softc *)self;
138 struct bt_attach_args *bt = aux;
139
140 sc->sc_methods = bt->bt_methods;
141 sc->sc_handle = bt->bt_handle;
142
143 *bt->bt_cb = &bthci_callbacks;
144
145 #ifdef DIAGNOSTIC
146 if (sc->sc_methods->bt_open == NULL ||
147 sc->sc_methods->bt_close == NULL ||
148
149 sc->sc_methods->bt_control.bt_alloc == NULL ||
150 sc->sc_methods->bt_control.bt_send == NULL ||
151
152 sc->sc_methods->bt_acldata.bt_alloc == NULL ||
153 sc->sc_methods->bt_acldata.bt_send == NULL ||
154
155 sc->sc_methods->bt_scodata.bt_alloc == NULL ||
156 sc->sc_methods->bt_scodata.bt_send == NULL)
157 panic("%s: missing methods", sc->sc_dev.dv_xname);
158 #endif
159
160 printf("\n");
161 }
162
163 int
164 bthci_activate(struct device *self, enum devact act)
165 {
166 /*struct bthci_softc *sc = (struct bthci_softc *)self;*/
167
168 switch (act) {
169 case DVACT_ACTIVATE:
170 return (EOPNOTSUPP);
171 break;
172
173 case DVACT_DEACTIVATE:
174 break;
175 }
176 return (0);
177 }
178
179 static void
180 bthci_abortdealloc(struct bthci_softc *sc)
181 {
182 DPRINTFN(0, ("%s: sc=%p\n", __func__, sc));
183
184 if (sc->sc_rd_buf != NULL) {
185 free(sc->sc_rd_buf, M_TEMP);
186 sc->sc_rd_buf = NULL;
187 }
188 }
189
190 int
191 bthci_detach(struct device *self, int flags)
192 {
193 struct bthci_softc *sc = (struct bthci_softc *)self;
194 int maj, mn;
195
196 sc->sc_dying = 1;
197 wakeup(&sc->sc_outputready);
198
199 DPRINTFN(1, ("%s: waiting for refcount (%d)\n",
200 __func__, sc->sc_refcnt));
201
202 if (--sc->sc_refcnt >= 0)
203 tsleep(&sc->sc_refcnt, PZERO, "bthcdt", 0);
204
205 DPRINTFN(1, ("%s: refcount complete\n", __func__));
206
207 bthci_abortdealloc(sc);
208
209 /* locate the major number */
210 maj = cdevsw_lookup_major(&bthci_cdevsw);
211
212 /* Nuke the vnodes for any open instances (calls close). */
213 mn = self->dv_unit;
214 vdevgone(maj, mn, mn, VCHR);
215
216 DPRINTFN(1, ("%s: driver detached\n", __func__));
217
218 return (0);
219 }
220
221 int
222 bthciopen(dev_t dev, int flag, int mode, struct proc *p)
223 {
224 struct bthci_softc *sc;
225 int error;
226
227 sc = device_lookup(&bthci_cd, BTHCIUNIT(dev));
228 if (sc == NULL)
229 return (ENXIO);
230 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
231 return (EIO);
232 if (sc->sc_open)
233 return (EBUSY);
234
235 sc->sc_rd_buf = malloc(BTHCI_ACL_DATA_MAX_LEN + 1, M_TEMP, M_NOWAIT);
236 if (sc->sc_rd_buf == NULL)
237 return (ENOMEM);
238
239 sc->sc_refcnt++;
240
241 if (sc->sc_methods->bt_open != NULL) {
242 error = sc->sc_methods->bt_open(sc->sc_handle, flag, mode, p);
243 if (error)
244 goto bad;
245 }
246
247 if (--sc->sc_refcnt < 0)
248 wakeup(&sc->sc_refcnt);
249
250 sc->sc_open = 1;
251 return (0);
252
253 bad:
254 free(sc->sc_rd_buf, M_TEMP);
255 sc->sc_rd_buf = NULL;
256
257 return error;
258 }
259
260 int
261 bthciclose(dev_t dev, int flag, int mode, struct proc *p)
262 {
263 struct bthci_softc *sc;
264 int error;
265
266 sc = device_lookup(&bthci_cd, BTHCIUNIT(dev));
267 if (sc == NULL)
268 return (ENXIO);
269
270 if (!sc->sc_open)
271 return (0);
272
273 sc->sc_refcnt++;
274
275 sc->sc_open = 0;
276
277 if (sc->sc_methods->bt_close != NULL)
278 error = sc->sc_methods->bt_close(sc->sc_handle, flag, mode, p);
279 else
280 error = 0;
281
282 bthci_abortdealloc(sc);
283
284 if (--sc->sc_refcnt < 0)
285 wakeup(&sc->sc_refcnt);
286
287 return (error);
288 }
289
290 static int
291 bthciread(dev_t dev, struct uio *uio, int flag)
292 {
293 struct bthci_softc *sc;
294 int error;
295 int s;
296
297 sc = device_lookup(&bthci_cd, BTHCIUNIT(dev));
298 if (sc == NULL)
299 return (ENXIO);
300
301 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
302 !sc->sc_open || sc->sc_dying)
303 return (EIO);
304
305 DPRINTFN(1, ("%s: length=%lu\n", __func__,
306 (unsigned long)uio->uio_resid));
307
308 sc->sc_refcnt++;
309
310 s = sc->sc_methods->bt_splraise();
311 while (!sc->sc_outputready) {
312 DPRINTFN(5,("%s: calling tsleep()\n", __func__));
313 error = tsleep(&sc->sc_outputready, PZERO | PCATCH,
314 "bthcrd", 0);
315 if (sc->sc_dying)
316 error = EIO;
317 if (error) {
318 splx(s);
319 DPRINTFN(0, ("%s: tsleep() = %d\n",
320 __func__, error));
321 goto ret;
322 }
323 }
324 splx(s);
325
326 if (uio->uio_resid < sc->sc_rd_len) {
327 #ifdef DIAGNOSTIC
328 printf("bthciread: short read %ld < %ld\n",
329 (long)uio->uio_resid, (long)sc->sc_rd_len);
330 #endif
331 error = EINVAL;
332 goto ret;
333 }
334
335 error = uiomove(sc->sc_rd_buf, sc->sc_rd_len, uio);
336
337 if (!error) {
338 sc->sc_outputready = 0;
339 sc->sc_rd_len = 0;
340 }
341
342 ret:
343 if (--sc->sc_refcnt < 0)
344 wakeup(&sc->sc_refcnt);
345
346 return error;
347 }
348
349 static int
350 bthcichanwrite(struct bthci_softc *sc,
351 struct btframe_channel const *btchannel, struct uio *uio)
352 {
353 struct btframe_buffer *btframebuf;
354 u_int8_t *btbuf;
355 int error;
356 size_t uiolen;
357
358 sc->sc_refcnt++;
359
360 uiolen = uio->uio_resid;
361
362 btbuf = btchannel->bt_alloc(sc->sc_handle, uiolen, &btframebuf);
363 if (btbuf == NULL) {
364 error = ENOMEM;
365 goto ret;
366 }
367
368 error = uiomove(btbuf, uiolen, uio);
369 if (error)
370 goto ret;
371
372 error = btchannel->bt_send(sc->sc_handle, btframebuf, uiolen);
373
374 ret:
375 if (--sc->sc_refcnt < 0)
376 wakeup(&sc->sc_refcnt);
377
378 return error;
379 }
380
381 static int
382 bthciwrite(dev_t dev, struct uio *uio, int flag)
383 {
384 struct bthci_softc *sc;
385 struct btframe_channel const *btchannel;
386 int error;
387 size_t uiolen;
388 u_int8_t bthcitype;
389
390 sc = device_lookup(&bthci_cd, BTHCIUNIT(dev));
391 if (sc == NULL)
392 return (ENXIO);
393
394 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 || !sc->sc_open)
395 return (EIO);
396
397 uiolen = uio->uio_resid;
398
399 DPRINTFN(1, ("%s: length=%lu\n", __func__, (unsigned long)uiolen));
400
401 if (uiolen > BTHCI_ACL_DATA_MAX_LEN + 1) {
402 #ifdef DIAGNOSTIC
403 printf("bthciread: long write %ld\n", (long)uio->uio_resid);
404 #endif
405 return (EINVAL);
406 }
407
408 if (uiolen <= 1) {
409 #ifdef DIAGNOSTIC
410 printf("bthciread: short write %ld\n", (long)uio->uio_resid);
411 #endif
412 return (EINVAL);
413 }
414
415 error = uiomove(&bthcitype, 1, uio);
416 if (error)
417 return (error);
418
419 if (bthcitype == BTHCI_PKTID_COMMAND) {
420 /* Command */
421 btchannel = &sc->sc_methods->bt_control;
422 } else if (bthcitype == BTHCI_PKTID_ACL_DATA) {
423 /* ACL data */
424 btchannel = &sc->sc_methods->bt_acldata;
425 } else if (bthcitype == BTHCI_PKTID_SCO_DATA) {
426 /* SCO data */
427 btchannel = &sc->sc_methods->bt_scodata;
428 } else {
429 /* Bad packet type */
430 return (EINVAL);
431 }
432
433 return (bthcichanwrite(sc, btchannel, uio));
434 }
435
436 #if 0
437 int
438 bthciioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
439 {
440 struct bthci_softc *sc;
441 void *vaddr = addr;
442 int error;
443
444 sc = device_lookup(&bthci_cd, BTHCIUNIT(dev));
445 if (sc == NULL)
446 return (ENXIO);
447 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 || !sc->sc_open)
448 return (EIO);
449
450 switch (cmd) {
451 case FIONBIO:
452 /* All handled in the upper FS layer. */
453 error = 0;
454 break;
455
456 default:
457 error = EINVAL;
458 break;
459 }
460 return (error);
461 }
462 #endif
463
464 int
465 bthcipoll(dev_t dev, int events, struct proc *p)
466 {
467 struct bthci_softc *sc;
468 int revents;
469 int s;
470
471 sc = device_lookup(&bthci_cd, BTHCIUNIT(dev));
472 if (sc == NULL)
473 return (ENXIO);
474 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 || !sc->sc_open)
475 return (EIO);
476
477 revents = events & (POLLOUT | POLLWRNORM);
478
479 if (events & (POLLIN | POLLRDNORM)) {
480 s = sc->sc_methods->bt_splraise();
481 if (sc->sc_outputready) {
482 DPRINTFN(2,("%s: have data\n", __func__));
483 revents |= events & (POLLIN | POLLRDNORM);
484 } else {
485 DPRINTFN(2,("%s: recording read select\n",
486 __func__));
487 selrecord(p, &sc->sc_rd_sel);
488 }
489 splx(s);
490 }
491
492 return revents;
493 }
494
495 static void
496 filt_bthcirdetach(struct knote *kn)
497 {
498 struct bthci_softc *sc = kn->kn_hook;
499 int s;
500
501 s = sc->sc_methods->bt_splraise();
502 SLIST_REMOVE(&sc->sc_rd_sel.sel_klist, kn, knote, kn_selnext);
503 splx(s);
504 }
505
506 /* ARGSUSED */
507 static int
508 filt_bthciread(struct knote *kn, long hint)
509 {
510 struct bthci_softc *sc = kn->kn_hook;
511
512 kn->kn_data = sc->sc_rd_len;
513 return (kn->kn_data > 0);
514 }
515
516 static const struct filterops bthciread_filtops =
517 { 1, NULL, filt_bthcirdetach, filt_bthciread };
518
519 int
520 bthcikqfilter(dev_t dev, struct knote *kn)
521 {
522 struct bthci_softc *sc;
523 struct klist *klist;
524 int s;
525
526 sc = device_lookup(&bthci_cd, BTHCIUNIT(dev));
527 if (sc == NULL)
528 return (ENXIO);
529 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 || !sc->sc_open)
530 return (EIO);
531
532 switch (kn->kn_filter) {
533 case EVFILT_READ:
534 klist = &sc->sc_rd_sel.sel_klist;
535 kn->kn_fop = &bthciread_filtops;
536 break;
537 default:
538 return (1);
539 }
540
541 kn->kn_hook = sc;
542
543 s = sc->sc_methods->bt_splraise();
544 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
545 splx(s);
546
547 return (0);
548 }
549
550 static void
551 bthci_recveventdata(void *h, u_int8_t *data, size_t len)
552 {
553 struct bthci_softc *sc = h;
554 size_t pktlength;
555 unsigned int ecode;
556
557 if (len < BTHCI_EVENT_MIN_LEN || len > BTHCI_EVENT_MAX_LEN) {
558 DPRINTFN(1,("%s: invalid sized event, size=%u\n",
559 __func__, (unsigned int)len));
560 return;
561 }
562
563 ecode = data[0];
564 DPRINTFN(1,("%s: received event: %02x (%s)\n", __func__,
565 ecode, bthci_eventstr(ecode)));
566
567 pktlength = data[BTHCI_EVENT_LEN_OFFT] + BTHCI_EVENT_LEN_OFFT +
568 BTHCI_EVENT_LEN_LENGTH;
569 if (pktlength != len) {
570 DPRINTFN(1,("%s: event length didn't match, "
571 "pktlen=%u size=%u\n",
572 __func__, (unsigned int)pktlength,
573 (unsigned int)len));
574 return;
575 }
576
577 if (!sc->sc_open)
578 return;
579
580 if (sc->sc_rd_len != 0) {
581 DPRINTFN(1,("%s: dropping an event, size=%u\n",
582 __func__, (unsigned int)len));
583 return;
584 }
585
586 sc->sc_rd_buf[0] = BTHCI_PKTID_EVENT;
587 memcpy(&sc->sc_rd_buf[1], data, len);
588 sc->sc_rd_len = len + 1;
589 sc->sc_outputready = 1;
590
591 wakeup(&sc->sc_outputready);
592 selnotify(&sc->sc_rd_sel, 0);
593 }
594
595 static void
596 bthci_recvacldata(void *h, u_int8_t *data, size_t len)
597 {
598 struct bthci_softc *sc = h;
599 size_t pktlength;
600
601 if (!sc->sc_open)
602 return;
603
604 if (len < BTHCI_ACL_DATA_MIN_LEN || len > BTHCI_ACL_DATA_MAX_LEN) {
605 DPRINTFN(1,("%s: invalid acl packet, size=%u\n",
606 __func__, (unsigned int)len));
607 return;
608 }
609
610 pktlength = BTGETW(&data[BTHCI_ACL_DATA_LEN_OFFT]) +
611 BTHCI_ACL_DATA_LEN_OFFT +
612 BTHCI_ACL_DATA_LEN_LENGTH;
613
614 if (pktlength != len) {
615 DPRINTFN(1,("%s: acl packet length didn't match, "
616 "pktlen=%u size=%u\n",
617 __func__, (unsigned int)pktlength,
618 (unsigned int)len));
619 return;
620 }
621
622 if (sc->sc_rd_len != 0) {
623 DPRINTFN(1,("%s: dropping an acl packet, size=%u\n",
624 __func__, (unsigned int)len));
625 return;
626 }
627
628 sc->sc_rd_buf[0] = BTHCI_PKTID_ACL_DATA;
629 memcpy(&sc->sc_rd_buf[1], data, len);
630 sc->sc_rd_len = len + 1;
631 sc->sc_outputready = 1;
632
633 wakeup(&sc->sc_outputready);
634 selnotify(&sc->sc_rd_sel, 0);
635 }
636
637 static void
638 bthci_recvscodata(void *h, u_int8_t *data, size_t len)
639 {
640 struct bthci_softc *sc = h;
641
642 if (!sc->sc_open)
643 return;
644 }
Cache object: 28743c86c17ce8d183bb7e95d145bfec
|