btuart.c revision 1.19.10.2 1 1.19.10.2 christos /* $NetBSD: btuart.c,v 1.19.10.2 2008/12/30 19:32:51 christos Exp $ */
2 1.19.10.2 christos
3 1.19.10.2 christos /*-
4 1.19.10.2 christos * Copyright (c) 2006, 2007 KIYOHARA Takashi
5 1.19.10.2 christos * All rights reserved.
6 1.19.10.2 christos *
7 1.19.10.2 christos * Redistribution and use in source and binary forms, with or without
8 1.19.10.2 christos * modification, are permitted provided that the following conditions
9 1.19.10.2 christos * are met:
10 1.19.10.2 christos * 1. Redistributions of source code must retain the above copyright
11 1.19.10.2 christos * notice, this list of conditions and the following disclaimer.
12 1.19.10.2 christos * 2. Redistributions in binary form must reproduce the above copyright
13 1.19.10.2 christos * notice, this list of conditions and the following disclaimer in the
14 1.19.10.2 christos * documentation and/or other materials provided with the distribution.
15 1.19.10.2 christos *
16 1.19.10.2 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.19.10.2 christos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 1.19.10.2 christos * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 1.19.10.2 christos * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 1.19.10.2 christos * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 1.19.10.2 christos * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 1.19.10.2 christos * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.19.10.2 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 1.19.10.2 christos * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 1.19.10.2 christos * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.19.10.2 christos * POSSIBILITY OF SUCH DAMAGE.
27 1.19.10.2 christos */
28 1.19.10.2 christos
29 1.19.10.2 christos #include <sys/cdefs.h>
30 1.19.10.2 christos __KERNEL_RCSID(0, "$NetBSD: btuart.c,v 1.19.10.2 2008/12/30 19:32:51 christos Exp $");
31 1.19.10.2 christos
32 1.19.10.2 christos #include <sys/param.h>
33 1.19.10.2 christos #include <sys/conf.h>
34 1.19.10.2 christos #include <sys/device.h>
35 1.19.10.2 christos #include <sys/errno.h>
36 1.19.10.2 christos #include <sys/fcntl.h>
37 1.19.10.2 christos #include <sys/kauth.h>
38 1.19.10.2 christos #include <sys/kernel.h>
39 1.19.10.2 christos #include <sys/malloc.h>
40 1.19.10.2 christos #include <sys/mbuf.h>
41 1.19.10.2 christos #include <sys/proc.h>
42 1.19.10.2 christos #include <sys/syslimits.h>
43 1.19.10.2 christos #include <sys/systm.h>
44 1.19.10.2 christos #include <sys/tty.h>
45 1.19.10.2 christos
46 1.19.10.2 christos #include <sys/bus.h>
47 1.19.10.2 christos #include <sys/intr.h>
48 1.19.10.2 christos
49 1.19.10.2 christos #include <netbt/bluetooth.h>
50 1.19.10.2 christos #include <netbt/hci.h>
51 1.19.10.2 christos
52 1.19.10.2 christos #include "ioconf.h"
53 1.19.10.2 christos
54 1.19.10.2 christos struct btuart_softc {
55 1.19.10.2 christos device_t sc_dev;
56 1.19.10.2 christos struct tty * sc_tp; /* tty pointer */
57 1.19.10.2 christos
58 1.19.10.2 christos bool sc_enabled; /* device is enabled */
59 1.19.10.2 christos struct hci_unit *sc_unit; /* Bluetooth HCI handle */
60 1.19.10.2 christos struct bt_stats sc_stats;
61 1.19.10.2 christos
62 1.19.10.2 christos int sc_state; /* receive state */
63 1.19.10.2 christos int sc_want; /* how much we want */
64 1.19.10.2 christos struct mbuf * sc_rxp; /* incoming packet */
65 1.19.10.2 christos
66 1.19.10.2 christos bool sc_xmit; /* transmit is active */
67 1.19.10.2 christos struct mbuf * sc_txp; /* outgoing packet */
68 1.19.10.2 christos
69 1.19.10.2 christos /* transmit queues */
70 1.19.10.2 christos MBUFQ_HEAD() sc_cmdq;
71 1.19.10.2 christos MBUFQ_HEAD() sc_aclq;
72 1.19.10.2 christos MBUFQ_HEAD() sc_scoq;
73 1.19.10.2 christos };
74 1.19.10.2 christos
75 1.19.10.2 christos /* sc_state */
76 1.19.10.2 christos #define BTUART_RECV_PKT_TYPE 0 /* packet type */
77 1.19.10.2 christos #define BTUART_RECV_ACL_HDR 1 /* acl header */
78 1.19.10.2 christos #define BTUART_RECV_SCO_HDR 2 /* sco header */
79 1.19.10.2 christos #define BTUART_RECV_EVENT_HDR 3 /* event header */
80 1.19.10.2 christos #define BTUART_RECV_ACL_DATA 4 /* acl packet data */
81 1.19.10.2 christos #define BTUART_RECV_SCO_DATA 5 /* sco packet data */
82 1.19.10.2 christos #define BTUART_RECV_EVENT_DATA 6 /* event packet data */
83 1.19.10.2 christos
84 1.19.10.2 christos void btuartattach(int);
85 1.19.10.2 christos static int btuart_match(device_t, struct cfdata *, void *);
86 1.19.10.2 christos static void btuart_attach(device_t, device_t, void *);
87 1.19.10.2 christos static int btuart_detach(device_t, int);
88 1.19.10.2 christos
89 1.19.10.2 christos static int btuartopen(dev_t, struct tty *);
90 1.19.10.2 christos static int btuartclose(struct tty *, int);
91 1.19.10.2 christos static int btuartioctl(struct tty *, u_long, void *, int, struct lwp *);
92 1.19.10.2 christos static int btuartinput(int, struct tty *);
93 1.19.10.2 christos static int btuartstart(struct tty *);
94 1.19.10.2 christos
95 1.19.10.2 christos static int btuart_enable(device_t);
96 1.19.10.2 christos static void btuart_disable(device_t);
97 1.19.10.2 christos static void btuart_output_cmd(device_t, struct mbuf *);
98 1.19.10.2 christos static void btuart_output_acl(device_t, struct mbuf *);
99 1.19.10.2 christos static void btuart_output_sco(device_t, struct mbuf *);
100 1.19.10.2 christos static void btuart_stats(device_t, struct bt_stats *, int);
101 1.19.10.2 christos
102 1.19.10.2 christos /*
103 1.19.10.2 christos * It doesn't need to be exported, as only btuartattach() uses it,
104 1.19.10.2 christos * but there's no "official" way to make it static.
105 1.19.10.2 christos */
106 1.19.10.2 christos CFATTACH_DECL_NEW(btuart, sizeof(struct btuart_softc),
107 1.19.10.2 christos btuart_match, btuart_attach, btuart_detach, NULL);
108 1.19.10.2 christos
109 1.19.10.2 christos static struct linesw btuart_disc = {
110 1.19.10.2 christos .l_name = "btuart",
111 1.19.10.2 christos .l_open = btuartopen,
112 1.19.10.2 christos .l_close = btuartclose,
113 1.19.10.2 christos .l_read = ttyerrio,
114 1.19.10.2 christos .l_write = ttyerrio,
115 1.19.10.2 christos .l_ioctl = btuartioctl,
116 1.19.10.2 christos .l_rint = btuartinput,
117 1.19.10.2 christos .l_start = btuartstart,
118 1.19.10.2 christos .l_modem = ttymodem,
119 1.19.10.2 christos .l_poll = ttyerrpoll,
120 1.19.10.2 christos };
121 1.19.10.2 christos
122 1.19.10.2 christos static const struct hci_if btuart_hci = {
123 1.19.10.2 christos .enable = btuart_enable,
124 1.19.10.2 christos .disable = btuart_disable,
125 1.19.10.2 christos .output_cmd = btuart_output_cmd,
126 1.19.10.2 christos .output_acl = btuart_output_acl,
127 1.19.10.2 christos .output_sco = btuart_output_sco,
128 1.19.10.2 christos .get_stats = btuart_stats,
129 1.19.10.2 christos .ipl = IPL_TTY,
130 1.19.10.2 christos };
131 1.19.10.2 christos
132 1.19.10.2 christos /*****************************************************************************
133 1.19.10.2 christos *
134 1.19.10.2 christos * autoconf(9) functions
135 1.19.10.2 christos */
136 1.19.10.2 christos
137 1.19.10.2 christos /*
138 1.19.10.2 christos * pseudo-device attach routine.
139 1.19.10.2 christos */
140 1.19.10.2 christos void
141 1.19.10.2 christos btuartattach(int num __unused)
142 1.19.10.2 christos {
143 1.19.10.2 christos int error;
144 1.19.10.2 christos
145 1.19.10.2 christos error = ttyldisc_attach(&btuart_disc);
146 1.19.10.2 christos if (error) {
147 1.19.10.2 christos aprint_error("%s: unable to register line discipline, "
148 1.19.10.2 christos "error = %d\n", btuart_cd.cd_name, error);
149 1.19.10.2 christos
150 1.19.10.2 christos return;
151 1.19.10.2 christos }
152 1.19.10.2 christos
153 1.19.10.2 christos error = config_cfattach_attach(btuart_cd.cd_name, &btuart_ca);
154 1.19.10.2 christos if (error) {
155 1.19.10.2 christos aprint_error("%s: unable to register cfattach, error = %d\n",
156 1.19.10.2 christos btuart_cd.cd_name, error);
157 1.19.10.2 christos
158 1.19.10.2 christos config_cfdriver_detach(&btuart_cd);
159 1.19.10.2 christos (void) ttyldisc_detach(&btuart_disc);
160 1.19.10.2 christos }
161 1.19.10.2 christos }
162 1.19.10.2 christos
163 1.19.10.2 christos /*
164 1.19.10.2 christos * Autoconf match routine.
165 1.19.10.2 christos */
166 1.19.10.2 christos static int
167 1.19.10.2 christos btuart_match(device_t self __unused, struct cfdata *cfdata __unused,
168 1.19.10.2 christos void *arg __unused)
169 1.19.10.2 christos {
170 1.19.10.2 christos
171 1.19.10.2 christos /* pseudo-device; always present */
172 1.19.10.2 christos return 1;
173 1.19.10.2 christos }
174 1.19.10.2 christos
175 1.19.10.2 christos /*
176 1.19.10.2 christos * Autoconf attach routine.
177 1.19.10.2 christos * Called by config_attach_pseudo(9) when we open the line discipline.
178 1.19.10.2 christos */
179 1.19.10.2 christos static void
180 1.19.10.2 christos btuart_attach(device_t parent __unused, device_t self, void *aux __unused)
181 1.19.10.2 christos {
182 1.19.10.2 christos struct btuart_softc *sc = device_private(self);
183 1.19.10.2 christos
184 1.19.10.2 christos sc->sc_dev = self;
185 1.19.10.2 christos
186 1.19.10.2 christos MBUFQ_INIT(&sc->sc_cmdq);
187 1.19.10.2 christos MBUFQ_INIT(&sc->sc_aclq);
188 1.19.10.2 christos MBUFQ_INIT(&sc->sc_scoq);
189 1.19.10.2 christos
190 1.19.10.2 christos /* Attach Bluetooth unit */
191 1.19.10.2 christos sc->sc_unit = hci_attach(&btuart_hci, self, 0);
192 1.19.10.2 christos if (sc->sc_unit == NULL)
193 1.19.10.2 christos aprint_error_dev(self, "HCI attach failed\n");
194 1.19.10.2 christos }
195 1.19.10.2 christos
196 1.19.10.2 christos /*
197 1.19.10.2 christos * Autoconf detach routine.
198 1.19.10.2 christos * Called when we close the line discipline.
199 1.19.10.2 christos */
200 1.19.10.2 christos static int
201 1.19.10.2 christos btuart_detach(device_t self, int flags __unused)
202 1.19.10.2 christos {
203 1.19.10.2 christos struct btuart_softc *sc = device_private(self);
204 1.19.10.2 christos
205 1.19.10.2 christos btuart_disable(self);
206 1.19.10.2 christos
207 1.19.10.2 christos if (sc->sc_unit) {
208 1.19.10.2 christos hci_detach(sc->sc_unit);
209 1.19.10.2 christos sc->sc_unit = NULL;
210 1.19.10.2 christos }
211 1.19.10.2 christos
212 1.19.10.2 christos return 0;
213 1.19.10.2 christos }
214 1.19.10.2 christos
215 1.19.10.2 christos /*****************************************************************************
216 1.19.10.2 christos *
217 1.19.10.2 christos * Line discipline functions.
218 1.19.10.2 christos */
219 1.19.10.2 christos
220 1.19.10.2 christos static int
221 1.19.10.2 christos btuartopen(dev_t devno __unused, struct tty *tp)
222 1.19.10.2 christos {
223 1.19.10.2 christos struct btuart_softc *sc;
224 1.19.10.2 christos device_t dev;
225 1.19.10.2 christos struct cfdata *cfdata;
226 1.19.10.2 christos struct lwp *l = curlwp; /* XXX */
227 1.19.10.2 christos int error, unit, s;
228 1.19.10.2 christos
229 1.19.10.2 christos if ((error = kauth_authorize_device_tty(l->l_cred,
230 1.19.10.2 christos KAUTH_GENERIC_ISSUSER, tp)) != 0)
231 1.19.10.2 christos return error;
232 1.19.10.2 christos
233 1.19.10.2 christos s = spltty();
234 1.19.10.2 christos
235 1.19.10.2 christos if (tp->t_linesw == &btuart_disc) {
236 1.19.10.2 christos sc = tp->t_sc;
237 1.19.10.2 christos if (sc != NULL) {
238 1.19.10.2 christos splx(s);
239 1.19.10.2 christos return EBUSY;
240 1.19.10.2 christos }
241 1.19.10.2 christos }
242 1.19.10.2 christos
243 1.19.10.2 christos KASSERT(tp->t_oproc != NULL);
244 1.19.10.2 christos
245 1.19.10.2 christos cfdata = malloc(sizeof(struct cfdata), M_DEVBUF, M_WAITOK);
246 1.19.10.2 christos for (unit = 0; unit < btuart_cd.cd_ndevs; unit++)
247 1.19.10.2 christos if (device_lookup(&btuart_cd, unit) == NULL)
248 1.19.10.2 christos break;
249 1.19.10.2 christos
250 1.19.10.2 christos cfdata->cf_name = btuart_cd.cd_name;
251 1.19.10.2 christos cfdata->cf_atname = btuart_cd.cd_name;
252 1.19.10.2 christos cfdata->cf_unit = unit;
253 1.19.10.2 christos cfdata->cf_fstate = FSTATE_STAR;
254 1.19.10.2 christos
255 1.19.10.2 christos dev = config_attach_pseudo(cfdata);
256 1.19.10.2 christos if (dev == NULL) {
257 1.19.10.2 christos free(cfdata, M_DEVBUF);
258 1.19.10.2 christos splx(s);
259 1.19.10.2 christos return EIO;
260 1.19.10.2 christos }
261 1.19.10.2 christos sc = device_private(dev);
262 1.19.10.2 christos
263 1.19.10.2 christos aprint_normal_dev(dev, "major %llu minor %llu\n",
264 1.19.10.2 christos (unsigned long long)major(tp->t_dev),
265 1.19.10.2 christos (unsigned long long)minor(tp->t_dev));
266 1.19.10.2 christos
267 1.19.10.2 christos sc->sc_tp = tp;
268 1.19.10.2 christos tp->t_sc = sc;
269 1.19.10.2 christos
270 1.19.10.2 christos mutex_spin_enter(&tty_lock);
271 1.19.10.2 christos ttyflush(tp, FREAD | FWRITE);
272 1.19.10.2 christos mutex_spin_exit(&tty_lock);
273 1.19.10.2 christos
274 1.19.10.2 christos splx(s);
275 1.19.10.2 christos
276 1.19.10.2 christos return 0;
277 1.19.10.2 christos }
278 1.19.10.2 christos
279 1.19.10.2 christos static int
280 1.19.10.2 christos btuartclose(struct tty *tp, int flag __unused)
281 1.19.10.2 christos {
282 1.19.10.2 christos struct btuart_softc *sc = tp->t_sc;
283 1.19.10.2 christos struct cfdata *cfdata;
284 1.19.10.2 christos int s;
285 1.19.10.2 christos
286 1.19.10.2 christos s = spltty();
287 1.19.10.2 christos
288 1.19.10.2 christos mutex_spin_enter(&tty_lock);
289 1.19.10.2 christos ttyflush(tp, FREAD | FWRITE);
290 1.19.10.2 christos mutex_spin_exit(&tty_lock); /* XXX */
291 1.19.10.2 christos
292 1.19.10.2 christos ttyldisc_release(tp->t_linesw);
293 1.19.10.2 christos tp->t_linesw = ttyldisc_default();
294 1.19.10.2 christos
295 1.19.10.2 christos if (sc != NULL) {
296 1.19.10.2 christos tp->t_sc = NULL;
297 1.19.10.2 christos if (sc->sc_tp == tp) {
298 1.19.10.2 christos cfdata = device_cfdata(sc->sc_dev);
299 1.19.10.2 christos config_detach(sc->sc_dev, 0);
300 1.19.10.2 christos free(cfdata, M_DEVBUF);
301 1.19.10.2 christos }
302 1.19.10.2 christos }
303 1.19.10.2 christos
304 1.19.10.2 christos splx(s);
305 1.19.10.2 christos
306 1.19.10.2 christos return 0;
307 1.19.10.2 christos }
308 1.19.10.2 christos
309 1.19.10.2 christos static int
310 1.19.10.2 christos btuartioctl(struct tty *tp, u_long cmd, void *data __unused,
311 1.19.10.2 christos int flag __unused, struct lwp *l __unused)
312 1.19.10.2 christos {
313 1.19.10.2 christos struct btuart_softc *sc = tp->t_sc;
314 1.19.10.2 christos int error;
315 1.19.10.2 christos
316 1.19.10.2 christos if (sc == NULL || tp != sc->sc_tp)
317 1.19.10.2 christos return EPASSTHROUGH;
318 1.19.10.2 christos
319 1.19.10.2 christos switch(cmd) {
320 1.19.10.2 christos default:
321 1.19.10.2 christos error = EPASSTHROUGH;
322 1.19.10.2 christos break;
323 1.19.10.2 christos }
324 1.19.10.2 christos
325 1.19.10.2 christos return error;
326 1.19.10.2 christos }
327 1.19.10.2 christos
328 1.19.10.2 christos static int
329 1.19.10.2 christos btuartinput(int c, struct tty *tp)
330 1.19.10.2 christos {
331 1.19.10.2 christos struct btuart_softc *sc = tp->t_sc;
332 1.19.10.2 christos struct mbuf *m = sc->sc_rxp;
333 1.19.10.2 christos int space = 0;
334 1.19.10.2 christos
335 1.19.10.2 christos if (!sc->sc_enabled)
336 1.19.10.2 christos return 0;
337 1.19.10.2 christos
338 1.19.10.2 christos c &= TTY_CHARMASK;
339 1.19.10.2 christos
340 1.19.10.2 christos /* If we already started a packet, find the trailing end of it. */
341 1.19.10.2 christos if (m) {
342 1.19.10.2 christos while (m->m_next)
343 1.19.10.2 christos m = m->m_next;
344 1.19.10.2 christos
345 1.19.10.2 christos space = M_TRAILINGSPACE(m);
346 1.19.10.2 christos }
347 1.19.10.2 christos
348 1.19.10.2 christos if (space == 0) {
349 1.19.10.2 christos if (m == NULL) {
350 1.19.10.2 christos /* new packet */
351 1.19.10.2 christos MGETHDR(m, M_DONTWAIT, MT_DATA);
352 1.19.10.2 christos if (m == NULL) {
353 1.19.10.2 christos aprint_error_dev(sc->sc_dev,
354 1.19.10.2 christos "out of memory\n");
355 1.19.10.2 christos sc->sc_stats.err_rx++;
356 1.19.10.2 christos return 0; /* (lost sync) */
357 1.19.10.2 christos }
358 1.19.10.2 christos
359 1.19.10.2 christos sc->sc_rxp = m;
360 1.19.10.2 christos m->m_pkthdr.len = m->m_len = 0;
361 1.19.10.2 christos space = MHLEN;
362 1.19.10.2 christos
363 1.19.10.2 christos sc->sc_state = BTUART_RECV_PKT_TYPE;
364 1.19.10.2 christos sc->sc_want = 1;
365 1.19.10.2 christos } else {
366 1.19.10.2 christos /* extend mbuf */
367 1.19.10.2 christos MGET(m->m_next, M_DONTWAIT, MT_DATA);
368 1.19.10.2 christos if (m->m_next == NULL) {
369 1.19.10.2 christos aprint_error_dev(sc->sc_dev,
370 1.19.10.2 christos "out of memory\n");
371 1.19.10.2 christos sc->sc_stats.err_rx++;
372 1.19.10.2 christos return 0; /* (lost sync) */
373 1.19.10.2 christos }
374 1.19.10.2 christos
375 1.19.10.2 christos m = m->m_next;
376 1.19.10.2 christos m->m_len = 0;
377 1.19.10.2 christos space = MLEN;
378 1.19.10.2 christos
379 1.19.10.2 christos if (sc->sc_want > MINCLSIZE) {
380 1.19.10.2 christos MCLGET(m, M_DONTWAIT);
381 1.19.10.2 christos if (m->m_flags & M_EXT)
382 1.19.10.2 christos space = MCLBYTES;
383 1.19.10.2 christos }
384 1.19.10.2 christos }
385 1.19.10.2 christos }
386 1.19.10.2 christos
387 1.19.10.2 christos mtod(m, uint8_t *)[m->m_len++] = c;
388 1.19.10.2 christos sc->sc_rxp->m_pkthdr.len++;
389 1.19.10.2 christos sc->sc_stats.byte_rx++;
390 1.19.10.2 christos
391 1.19.10.2 christos sc->sc_want--;
392 1.19.10.2 christos if (sc->sc_want > 0)
393 1.19.10.2 christos return 0; /* want more */
394 1.19.10.2 christos
395 1.19.10.2 christos switch (sc->sc_state) {
396 1.19.10.2 christos case BTUART_RECV_PKT_TYPE: /* Got packet type */
397 1.19.10.2 christos
398 1.19.10.2 christos switch (c) {
399 1.19.10.2 christos case HCI_ACL_DATA_PKT:
400 1.19.10.2 christos sc->sc_state = BTUART_RECV_ACL_HDR;
401 1.19.10.2 christos sc->sc_want = sizeof(hci_acldata_hdr_t) - 1;
402 1.19.10.2 christos break;
403 1.19.10.2 christos
404 1.19.10.2 christos case HCI_SCO_DATA_PKT:
405 1.19.10.2 christos sc->sc_state = BTUART_RECV_SCO_HDR;
406 1.19.10.2 christos sc->sc_want = sizeof(hci_scodata_hdr_t) - 1;
407 1.19.10.2 christos break;
408 1.19.10.2 christos
409 1.19.10.2 christos case HCI_EVENT_PKT:
410 1.19.10.2 christos sc->sc_state = BTUART_RECV_EVENT_HDR;
411 1.19.10.2 christos sc->sc_want = sizeof(hci_event_hdr_t) - 1;
412 1.19.10.2 christos break;
413 1.19.10.2 christos
414 1.19.10.2 christos default:
415 1.19.10.2 christos aprint_error_dev(sc->sc_dev,
416 1.19.10.2 christos "Unknown packet type=%#x!\n", c);
417 1.19.10.2 christos sc->sc_stats.err_rx++;
418 1.19.10.2 christos m_freem(sc->sc_rxp);
419 1.19.10.2 christos sc->sc_rxp = NULL;
420 1.19.10.2 christos return 0; /* (lost sync) */
421 1.19.10.2 christos }
422 1.19.10.2 christos
423 1.19.10.2 christos break;
424 1.19.10.2 christos
425 1.19.10.2 christos /*
426 1.19.10.2 christos * we assume (correctly of course :) that the packet headers all fit
427 1.19.10.2 christos * into a single pkthdr mbuf
428 1.19.10.2 christos */
429 1.19.10.2 christos case BTUART_RECV_ACL_HDR: /* Got ACL Header */
430 1.19.10.2 christos sc->sc_state = BTUART_RECV_ACL_DATA;
431 1.19.10.2 christos sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length;
432 1.19.10.2 christos sc->sc_want = le16toh(sc->sc_want);
433 1.19.10.2 christos break;
434 1.19.10.2 christos
435 1.19.10.2 christos case BTUART_RECV_SCO_HDR: /* Got SCO Header */
436 1.19.10.2 christos sc->sc_state = BTUART_RECV_SCO_DATA;
437 1.19.10.2 christos sc->sc_want = mtod(m, hci_scodata_hdr_t *)->length;
438 1.19.10.2 christos break;
439 1.19.10.2 christos
440 1.19.10.2 christos case BTUART_RECV_EVENT_HDR: /* Got Event Header */
441 1.19.10.2 christos sc->sc_state = BTUART_RECV_EVENT_DATA;
442 1.19.10.2 christos sc->sc_want = mtod(m, hci_event_hdr_t *)->length;
443 1.19.10.2 christos break;
444 1.19.10.2 christos
445 1.19.10.2 christos case BTUART_RECV_ACL_DATA: /* ACL Packet Complete */
446 1.19.10.2 christos if (!hci_input_acl(sc->sc_unit, sc->sc_rxp))
447 1.19.10.2 christos sc->sc_stats.err_rx++;
448 1.19.10.2 christos
449 1.19.10.2 christos sc->sc_stats.acl_rx++;
450 1.19.10.2 christos sc->sc_rxp = m = NULL;
451 1.19.10.2 christos break;
452 1.19.10.2 christos
453 1.19.10.2 christos case BTUART_RECV_SCO_DATA: /* SCO Packet Complete */
454 1.19.10.2 christos if (!hci_input_sco(sc->sc_unit, sc->sc_rxp))
455 1.19.10.2 christos sc->sc_stats.err_rx++;
456 1.19.10.2 christos
457 1.19.10.2 christos sc->sc_stats.sco_rx++;
458 1.19.10.2 christos sc->sc_rxp = m = NULL;
459 1.19.10.2 christos break;
460 1.19.10.2 christos
461 1.19.10.2 christos case BTUART_RECV_EVENT_DATA: /* Event Packet Complete */
462 1.19.10.2 christos if (!hci_input_event(sc->sc_unit, sc->sc_rxp))
463 1.19.10.2 christos sc->sc_stats.err_rx++;
464 1.19.10.2 christos
465 1.19.10.2 christos sc->sc_stats.evt_rx++;
466 1.19.10.2 christos sc->sc_rxp = m = NULL;
467 1.19.10.2 christos break;
468 1.19.10.2 christos
469 1.19.10.2 christos default:
470 1.19.10.2 christos panic("%s: invalid state %d!\n",
471 1.19.10.2 christos device_xname(sc->sc_dev), sc->sc_state);
472 1.19.10.2 christos }
473 1.19.10.2 christos
474 1.19.10.2 christos return 0;
475 1.19.10.2 christos }
476 1.19.10.2 christos
477 1.19.10.2 christos static int
478 1.19.10.2 christos btuartstart(struct tty *tp)
479 1.19.10.2 christos {
480 1.19.10.2 christos struct btuart_softc *sc = tp->t_sc;
481 1.19.10.2 christos struct mbuf *m;
482 1.19.10.2 christos int count, rlen;
483 1.19.10.2 christos uint8_t *rptr;
484 1.19.10.2 christos
485 1.19.10.2 christos if (!sc->sc_enabled)
486 1.19.10.2 christos return 0;
487 1.19.10.2 christos
488 1.19.10.2 christos m = sc->sc_txp;
489 1.19.10.2 christos if (m == NULL) {
490 1.19.10.2 christos if (MBUFQ_FIRST(&sc->sc_cmdq)) {
491 1.19.10.2 christos MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
492 1.19.10.2 christos sc->sc_stats.cmd_tx++;
493 1.19.10.2 christos } else if (MBUFQ_FIRST(&sc->sc_scoq)) {
494 1.19.10.2 christos MBUFQ_DEQUEUE(&sc->sc_scoq, m);
495 1.19.10.2 christos sc->sc_stats.sco_tx++;
496 1.19.10.2 christos } else if (MBUFQ_FIRST(&sc->sc_aclq)) {
497 1.19.10.2 christos MBUFQ_DEQUEUE(&sc->sc_aclq, m);
498 1.19.10.2 christos sc->sc_stats.acl_tx++;
499 1.19.10.2 christos } else {
500 1.19.10.2 christos sc->sc_xmit = false;
501 1.19.10.2 christos return 0; /* no more to send */
502 1.19.10.2 christos }
503 1.19.10.2 christos
504 1.19.10.2 christos sc->sc_txp = m;
505 1.19.10.2 christos sc->sc_xmit = true;
506 1.19.10.2 christos }
507 1.19.10.2 christos
508 1.19.10.2 christos count = 0;
509 1.19.10.2 christos rlen = 0;
510 1.19.10.2 christos rptr = mtod(m, uint8_t *);
511 1.19.10.2 christos
512 1.19.10.2 christos for(;;) {
513 1.19.10.2 christos if (rlen >= m->m_len) {
514 1.19.10.2 christos m = m->m_next;
515 1.19.10.2 christos if (m == NULL) {
516 1.19.10.2 christos m = sc->sc_txp;
517 1.19.10.2 christos sc->sc_txp = NULL;
518 1.19.10.2 christos
519 1.19.10.2 christos if (M_GETCTX(m, void *) == NULL)
520 1.19.10.2 christos m_freem(m);
521 1.19.10.2 christos else if (!hci_complete_sco(sc->sc_unit, m))
522 1.19.10.2 christos sc->sc_stats.err_tx++;
523 1.19.10.2 christos
524 1.19.10.2 christos break;
525 1.19.10.2 christos }
526 1.19.10.2 christos
527 1.19.10.2 christos rlen = 0;
528 1.19.10.2 christos rptr = mtod(m, uint8_t *);
529 1.19.10.2 christos continue;
530 1.19.10.2 christos }
531 1.19.10.2 christos
532 1.19.10.2 christos if (putc(*rptr++, &tp->t_outq) < 0) {
533 1.19.10.2 christos m_adj(m, rlen);
534 1.19.10.2 christos break;
535 1.19.10.2 christos }
536 1.19.10.2 christos rlen++;
537 1.19.10.2 christos count++;
538 1.19.10.2 christos }
539 1.19.10.2 christos
540 1.19.10.2 christos sc->sc_stats.byte_tx += count;
541 1.19.10.2 christos
542 1.19.10.2 christos if (tp->t_outq.c_cc != 0)
543 1.19.10.2 christos (*tp->t_oproc)(tp);
544 1.19.10.2 christos
545 1.19.10.2 christos return 0;
546 1.19.10.2 christos }
547 1.19.10.2 christos
548 1.19.10.2 christos /*****************************************************************************
549 1.19.10.2 christos *
550 1.19.10.2 christos * bluetooth(9) functions
551 1.19.10.2 christos */
552 1.19.10.2 christos
553 1.19.10.2 christos static int
554 1.19.10.2 christos btuart_enable(device_t self)
555 1.19.10.2 christos {
556 1.19.10.2 christos struct btuart_softc *sc = device_private(self);
557 1.19.10.2 christos int s;
558 1.19.10.2 christos
559 1.19.10.2 christos if (sc->sc_enabled)
560 1.19.10.2 christos return 0;
561 1.19.10.2 christos
562 1.19.10.2 christos s = spltty();
563 1.19.10.2 christos
564 1.19.10.2 christos sc->sc_enabled = true;
565 1.19.10.2 christos sc->sc_xmit = false;
566 1.19.10.2 christos
567 1.19.10.2 christos splx(s);
568 1.19.10.2 christos
569 1.19.10.2 christos return 0;
570 1.19.10.2 christos }
571 1.19.10.2 christos
572 1.19.10.2 christos static void
573 1.19.10.2 christos btuart_disable(device_t self)
574 1.19.10.2 christos {
575 1.19.10.2 christos struct btuart_softc *sc = device_private(self);
576 1.19.10.2 christos int s;
577 1.19.10.2 christos
578 1.19.10.2 christos if (!sc->sc_enabled)
579 1.19.10.2 christos return;
580 1.19.10.2 christos
581 1.19.10.2 christos s = spltty();
582 1.19.10.2 christos
583 1.19.10.2 christos if (sc->sc_rxp) {
584 1.19.10.2 christos m_freem(sc->sc_rxp);
585 1.19.10.2 christos sc->sc_rxp = NULL;
586 1.19.10.2 christos }
587 1.19.10.2 christos
588 1.19.10.2 christos if (sc->sc_txp) {
589 1.19.10.2 christos m_freem(sc->sc_txp);
590 1.19.10.2 christos sc->sc_txp = NULL;
591 1.19.10.2 christos }
592 1.19.10.2 christos
593 1.19.10.2 christos MBUFQ_DRAIN(&sc->sc_cmdq);
594 1.19.10.2 christos MBUFQ_DRAIN(&sc->sc_aclq);
595 1.19.10.2 christos MBUFQ_DRAIN(&sc->sc_scoq);
596 1.19.10.2 christos
597 1.19.10.2 christos sc->sc_enabled = false;
598 1.19.10.2 christos
599 1.19.10.2 christos splx(s);
600 1.19.10.2 christos }
601 1.19.10.2 christos
602 1.19.10.2 christos static void
603 1.19.10.2 christos btuart_output_cmd(device_t self, struct mbuf *m)
604 1.19.10.2 christos {
605 1.19.10.2 christos struct btuart_softc *sc = device_private(self);
606 1.19.10.2 christos int s;
607 1.19.10.2 christos
608 1.19.10.2 christos KASSERT(sc->sc_enabled);
609 1.19.10.2 christos
610 1.19.10.2 christos M_SETCTX(m, NULL);
611 1.19.10.2 christos
612 1.19.10.2 christos s = spltty();
613 1.19.10.2 christos MBUFQ_ENQUEUE(&sc->sc_cmdq, m);
614 1.19.10.2 christos if (!sc->sc_xmit)
615 1.19.10.2 christos btuartstart(sc->sc_tp);
616 1.19.10.2 christos
617 1.19.10.2 christos splx(s);
618 1.19.10.2 christos }
619 1.19.10.2 christos
620 1.19.10.2 christos static void
621 1.19.10.2 christos btuart_output_acl(device_t self, struct mbuf *m)
622 1.19.10.2 christos {
623 1.19.10.2 christos struct btuart_softc *sc = device_private(self);
624 1.19.10.2 christos int s;
625 1.19.10.2 christos
626 1.19.10.2 christos KASSERT(sc->sc_enabled);
627 1.19.10.2 christos
628 1.19.10.2 christos M_SETCTX(m, NULL);
629 1.19.10.2 christos
630 1.19.10.2 christos s = spltty();
631 1.19.10.2 christos MBUFQ_ENQUEUE(&sc->sc_aclq, m);
632 1.19.10.2 christos if (!sc->sc_xmit)
633 1.19.10.2 christos btuartstart(sc->sc_tp);
634 1.19.10.2 christos
635 1.19.10.2 christos splx(s);
636 1.19.10.2 christos }
637 1.19.10.2 christos
638 1.19.10.2 christos static void
639 1.19.10.2 christos btuart_output_sco(device_t self, struct mbuf *m)
640 1.19.10.2 christos {
641 1.19.10.2 christos struct btuart_softc *sc = device_private(self);
642 1.19.10.2 christos int s;
643 1.19.10.2 christos
644 1.19.10.2 christos KASSERT(sc->sc_enabled);
645 1.19.10.2 christos
646 1.19.10.2 christos s = spltty();
647 1.19.10.2 christos MBUFQ_ENQUEUE(&sc->sc_scoq, m);
648 1.19.10.2 christos if (!sc->sc_xmit)
649 1.19.10.2 christos btuartstart(sc->sc_tp);
650 1.19.10.2 christos
651 1.19.10.2 christos splx(s);
652 1.19.10.2 christos }
653 1.19.10.2 christos
654 1.19.10.2 christos static void
655 1.19.10.2 christos btuart_stats(device_t self, struct bt_stats *dest, int flush)
656 1.19.10.2 christos {
657 1.19.10.2 christos struct btuart_softc *sc = device_private(self);
658 1.19.10.2 christos int s;
659 1.19.10.2 christos
660 1.19.10.2 christos s = spltty();
661 1.19.10.2 christos
662 1.19.10.2 christos memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats));
663 1.19.10.2 christos
664 1.19.10.2 christos if (flush)
665 1.19.10.2 christos memset(&sc->sc_stats, 0, sizeof(struct bt_stats));
666 1.19.10.2 christos
667 1.19.10.2 christos splx(s);
668 1.19.10.2 christos }
669