1 1.43 rin /* $NetBSD: btsco.c,v 1.43 2024/07/05 04:31:50 rin Exp $ */ 2 1.1 tron 3 1.1 tron /*- 4 1.1 tron * Copyright (c) 2006 Itronix Inc. 5 1.1 tron * All rights reserved. 6 1.1 tron * 7 1.1 tron * Written by Iain Hibbert for Itronix Inc. 8 1.1 tron * 9 1.1 tron * Redistribution and use in source and binary forms, with or without 10 1.1 tron * modification, are permitted provided that the following conditions 11 1.1 tron * are met: 12 1.1 tron * 1. Redistributions of source code must retain the above copyright 13 1.1 tron * notice, this list of conditions and the following disclaimer. 14 1.1 tron * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 tron * notice, this list of conditions and the following disclaimer in the 16 1.1 tron * documentation and/or other materials provided with the distribution. 17 1.1 tron * 3. The name of Itronix Inc. may not be used to endorse 18 1.1 tron * or promote products derived from this software without specific 19 1.1 tron * prior written permission. 20 1.1 tron * 21 1.1 tron * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 22 1.1 tron * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 1.1 tron * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.1 tron * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 25 1.1 tron * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 1.1 tron * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 1.1 tron * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 1.1 tron * ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 tron * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 tron * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.1 tron * POSSIBILITY OF SUCH DAMAGE. 32 1.1 tron */ 33 1.1 tron 34 1.1 tron #include <sys/cdefs.h> 35 1.43 rin __KERNEL_RCSID(0, "$NetBSD: btsco.c,v 1.43 2024/07/05 04:31:50 rin Exp $"); 36 1.1 tron 37 1.1 tron #include <sys/param.h> 38 1.1 tron #include <sys/audioio.h> 39 1.1 tron #include <sys/conf.h> 40 1.1 tron #include <sys/device.h> 41 1.1 tron #include <sys/fcntl.h> 42 1.1 tron #include <sys/kernel.h> 43 1.1 tron #include <sys/queue.h> 44 1.25 jmcneill #include <sys/kmem.h> 45 1.1 tron #include <sys/mbuf.h> 46 1.1 tron #include <sys/proc.h> 47 1.22 plunky #include <sys/socketvar.h> 48 1.1 tron #include <sys/systm.h> 49 1.15 ad #include <sys/intr.h> 50 1.1 tron 51 1.1 tron #include <prop/proplib.h> 52 1.1 tron 53 1.1 tron #include <netbt/bluetooth.h> 54 1.1 tron #include <netbt/rfcomm.h> 55 1.1 tron #include <netbt/sco.h> 56 1.1 tron 57 1.39 isaki #include <dev/audio/audio_if.h> 58 1.1 tron 59 1.1 tron #include <dev/bluetooth/btdev.h> 60 1.1 tron #include <dev/bluetooth/btsco.h> 61 1.1 tron 62 1.1 tron #undef DPRINTF 63 1.1 tron #undef DPRINTFN 64 1.1 tron 65 1.1 tron #ifdef BTSCO_DEBUG 66 1.1 tron int btsco_debug = BTSCO_DEBUG; 67 1.24 plunky #define DPRINTF(...) do { \ 68 1.24 plunky if (btsco_debug) { \ 69 1.24 plunky printf("%s: ", __func__); \ 70 1.24 plunky printf(__VA_ARGS__); \ 71 1.24 plunky } \ 72 1.1 tron } while (/* CONSTCOND */0) 73 1.1 tron 74 1.24 plunky #define DPRINTFN(n, ...) do { \ 75 1.24 plunky if (btsco_debug > (n)) { \ 76 1.24 plunky printf("%s: ", __func__); \ 77 1.24 plunky printf(__VA_ARGS__); \ 78 1.24 plunky } \ 79 1.1 tron } while (/* CONSTCOND */0) 80 1.1 tron #else 81 1.1 tron #define DPRINTF(...) 82 1.1 tron #define DPRINTFN(...) 83 1.1 tron #endif 84 1.1 tron 85 1.1 tron /***************************************************************************** 86 1.1 tron * 87 1.1 tron * Bluetooth SCO Audio device 88 1.1 tron */ 89 1.1 tron 90 1.1 tron /* btsco softc */ 91 1.1 tron struct btsco_softc { 92 1.1 tron uint16_t sc_flags; 93 1.16 plunky const char *sc_name; /* our device_xname */ 94 1.1 tron 95 1.16 plunky device_t sc_audio; /* MI audio device */ 96 1.1 tron void *sc_intr; /* interrupt cookie */ 97 1.20 ad kcondvar_t sc_connect; /* connect wait */ 98 1.35 nat kmutex_t sc_lock; /* for audio */ 99 1.1 tron 100 1.1 tron /* Bluetooth */ 101 1.1 tron bdaddr_t sc_laddr; /* local address */ 102 1.1 tron bdaddr_t sc_raddr; /* remote address */ 103 1.1 tron uint16_t sc_state; /* link state */ 104 1.1 tron struct sco_pcb *sc_sco; /* SCO handle */ 105 1.1 tron struct sco_pcb *sc_sco_l; /* SCO listen handle */ 106 1.4 plunky uint16_t sc_mtu; /* SCO mtu */ 107 1.1 tron uint8_t sc_channel; /* RFCOMM channel */ 108 1.1 tron int sc_err; /* stored error */ 109 1.1 tron 110 1.1 tron /* Receive */ 111 1.1 tron int sc_rx_want; /* bytes wanted */ 112 1.1 tron uint8_t *sc_rx_block; /* receive block */ 113 1.1 tron void (*sc_rx_intr)(void *); /* callback */ 114 1.1 tron void *sc_rx_intrarg; /* callback arg */ 115 1.1 tron struct mbuf *sc_rx_mbuf; /* leftover mbuf */ 116 1.1 tron 117 1.1 tron /* Transmit */ 118 1.1 tron int sc_tx_size; /* bytes to send */ 119 1.1 tron int sc_tx_pending; /* packets pending */ 120 1.1 tron uint8_t *sc_tx_block; /* transmit block */ 121 1.1 tron void (*sc_tx_intr)(void *); /* callback */ 122 1.1 tron void *sc_tx_intrarg; /* callback arg */ 123 1.1 tron void *sc_tx_buf; /* transmit buffer */ 124 1.1 tron int sc_tx_refcnt; /* buffer refcnt */ 125 1.1 tron 126 1.1 tron /* mixer data */ 127 1.1 tron int sc_vgs; /* speaker volume */ 128 1.1 tron int sc_vgm; /* mic volume */ 129 1.1 tron }; 130 1.1 tron 131 1.1 tron /* sc_state */ 132 1.1 tron #define BTSCO_CLOSED 0 133 1.1 tron #define BTSCO_WAIT_CONNECT 1 134 1.1 tron #define BTSCO_OPEN 2 135 1.1 tron 136 1.1 tron /* sc_flags */ 137 1.1 tron #define BTSCO_LISTEN (1 << 1) 138 1.1 tron 139 1.1 tron /* autoconf(9) glue */ 140 1.23 cegger static int btsco_match(device_t, cfdata_t, void *); 141 1.16 plunky static void btsco_attach(device_t, device_t, void *); 142 1.16 plunky static int btsco_detach(device_t, int); 143 1.1 tron 144 1.16 plunky CFATTACH_DECL_NEW(btsco, sizeof(struct btsco_softc), 145 1.1 tron btsco_match, btsco_attach, btsco_detach, NULL); 146 1.1 tron 147 1.1 tron /* audio(9) glue */ 148 1.1 tron static int btsco_open(void *, int); 149 1.1 tron static void btsco_close(void *); 150 1.39 isaki static int btsco_query_format(void *, audio_format_query_t *); 151 1.39 isaki static int btsco_set_format(void *, int, 152 1.39 isaki const audio_params_t *, const audio_params_t *, 153 1.39 isaki audio_filter_reg_t *, audio_filter_reg_t *); 154 1.1 tron static int btsco_round_blocksize(void *, int, int, const audio_params_t *); 155 1.1 tron static int btsco_start_output(void *, void *, int, void (*)(void *), void *); 156 1.1 tron static int btsco_start_input(void *, void *, int, void (*)(void *), void *); 157 1.1 tron static int btsco_halt_output(void *); 158 1.1 tron static int btsco_halt_input(void *); 159 1.1 tron static int btsco_getdev(void *, struct audio_device *); 160 1.1 tron static int btsco_set_port(void *, mixer_ctrl_t *); 161 1.1 tron static int btsco_get_port(void *, mixer_ctrl_t *); 162 1.1 tron static int btsco_query_devinfo(void *, mixer_devinfo_t *); 163 1.25 jmcneill static void *btsco_allocm(void *, int, size_t); 164 1.25 jmcneill static void btsco_freem(void *, void *, size_t); 165 1.1 tron static int btsco_get_props(void *); 166 1.12 christos static int btsco_dev_ioctl(void *, u_long, void *, int, struct lwp *); 167 1.25 jmcneill static void btsco_get_locks(void *, kmutex_t **, kmutex_t **); 168 1.1 tron 169 1.1 tron static const struct audio_hw_if btsco_if = { 170 1.38 isaki .open = btsco_open, 171 1.38 isaki .close = btsco_close, 172 1.39 isaki .query_format = btsco_query_format, 173 1.39 isaki .set_format = btsco_set_format, 174 1.38 isaki .round_blocksize = btsco_round_blocksize, 175 1.38 isaki .start_output = btsco_start_output, 176 1.38 isaki .start_input = btsco_start_input, 177 1.38 isaki .halt_output = btsco_halt_output, 178 1.38 isaki .halt_input = btsco_halt_input, 179 1.38 isaki .getdev = btsco_getdev, 180 1.38 isaki .set_port = btsco_set_port, 181 1.38 isaki .get_port = btsco_get_port, 182 1.38 isaki .query_devinfo = btsco_query_devinfo, 183 1.38 isaki .allocm = btsco_allocm, 184 1.38 isaki .freem = btsco_freem, 185 1.38 isaki .get_props = btsco_get_props, 186 1.38 isaki .dev_ioctl = btsco_dev_ioctl, 187 1.38 isaki .get_locks = btsco_get_locks, 188 1.1 tron }; 189 1.1 tron 190 1.1 tron static const struct audio_device btsco_device = { 191 1.1 tron "Bluetooth Audio", 192 1.1 tron "", 193 1.1 tron "btsco" 194 1.1 tron }; 195 1.1 tron 196 1.8 plunky /* Voice_Setting == 0x0060: 8000Hz, mono, 16-bit, slinear_le */ 197 1.8 plunky static const struct audio_format btsco_format = { 198 1.39 isaki .mode = AUMODE_PLAY | AUMODE_RECORD, 199 1.39 isaki .encoding = AUDIO_ENCODING_SLINEAR_LE, 200 1.39 isaki .validbits = 16, 201 1.39 isaki .precision = 16, 202 1.39 isaki .channels = 1, 203 1.39 isaki .channel_mask = AUFMT_MONAURAL, 204 1.39 isaki .frequency_type = 1, 205 1.39 isaki .frequency = { 8000 }, 206 1.8 plunky }; 207 1.8 plunky 208 1.1 tron /* bluetooth(9) glue for SCO */ 209 1.1 tron static void btsco_sco_connecting(void *); 210 1.1 tron static void btsco_sco_connected(void *); 211 1.1 tron static void btsco_sco_disconnected(void *, int); 212 1.1 tron static void *btsco_sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 213 1.1 tron static void btsco_sco_complete(void *, int); 214 1.14 plunky static void btsco_sco_linkmode(void *, int); 215 1.1 tron static void btsco_sco_input(void *, struct mbuf *); 216 1.1 tron 217 1.1 tron static const struct btproto btsco_sco_proto = { 218 1.1 tron btsco_sco_connecting, 219 1.1 tron btsco_sco_connected, 220 1.1 tron btsco_sco_disconnected, 221 1.1 tron btsco_sco_newconn, 222 1.1 tron btsco_sco_complete, 223 1.14 plunky btsco_sco_linkmode, 224 1.1 tron btsco_sco_input, 225 1.1 tron }; 226 1.1 tron 227 1.1 tron 228 1.1 tron /***************************************************************************** 229 1.1 tron * 230 1.1 tron * btsco definitions 231 1.1 tron */ 232 1.1 tron 233 1.1 tron /* 234 1.1 tron * btsco mixer class 235 1.1 tron */ 236 1.1 tron #define BTSCO_VGS 0 237 1.1 tron #define BTSCO_VGM 1 238 1.1 tron #define BTSCO_INPUT_CLASS 2 239 1.1 tron #define BTSCO_OUTPUT_CLASS 3 240 1.1 tron 241 1.1 tron /* connect timeout */ 242 1.1 tron #define BTSCO_TIMEOUT (30 * hz) 243 1.1 tron 244 1.1 tron /* misc btsco functions */ 245 1.12 christos static void btsco_extfree(struct mbuf *, void *, size_t, void *); 246 1.1 tron static void btsco_intr(void *); 247 1.1 tron 248 1.1 tron 249 1.1 tron /***************************************************************************** 250 1.1 tron * 251 1.1 tron * btsco autoconf(9) routines 252 1.1 tron */ 253 1.1 tron 254 1.1 tron static int 255 1.23 cegger btsco_match(device_t self, cfdata_t cfdata, void *aux) 256 1.1 tron { 257 1.1 tron prop_dictionary_t dict = aux; 258 1.1 tron prop_object_t obj; 259 1.1 tron 260 1.9 plunky obj = prop_dictionary_get(dict, BTDEVservice); 261 1.42 thorpej if (prop_string_equals_string(obj, "HSET")) 262 1.9 plunky return 1; 263 1.9 plunky 264 1.42 thorpej if (prop_string_equals_string(obj, "HF")) 265 1.9 plunky return 1; 266 1.9 plunky 267 1.9 plunky return 0; 268 1.1 tron } 269 1.1 tron 270 1.1 tron static void 271 1.16 plunky btsco_attach(device_t parent, device_t self, void *aux) 272 1.1 tron { 273 1.16 plunky struct btsco_softc *sc = device_private(self); 274 1.1 tron prop_dictionary_t dict = aux; 275 1.1 tron prop_object_t obj; 276 1.1 tron 277 1.1 tron /* 278 1.1 tron * Init softc 279 1.1 tron */ 280 1.1 tron sc->sc_vgs = 200; 281 1.1 tron sc->sc_vgm = 200; 282 1.1 tron sc->sc_state = BTSCO_CLOSED; 283 1.16 plunky sc->sc_name = device_xname(self); 284 1.20 ad cv_init(&sc->sc_connect, "connect"); 285 1.35 nat mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 286 1.1 tron 287 1.1 tron /* 288 1.1 tron * copy in our configuration info 289 1.1 tron */ 290 1.3 plunky obj = prop_dictionary_get(dict, BTDEVladdr); 291 1.42 thorpej bdaddr_copy(&sc->sc_laddr, prop_data_value(obj)); 292 1.1 tron 293 1.3 plunky obj = prop_dictionary_get(dict, BTDEVraddr); 294 1.42 thorpej bdaddr_copy(&sc->sc_raddr, prop_data_value(obj)); 295 1.1 tron 296 1.9 plunky obj = prop_dictionary_get(dict, BTDEVservice); 297 1.42 thorpej if (prop_string_equals_string(obj, "HF")) { 298 1.1 tron sc->sc_flags |= BTSCO_LISTEN; 299 1.2 plunky aprint_verbose(" listen mode"); 300 1.1 tron } 301 1.1 tron 302 1.3 plunky obj = prop_dictionary_get(dict, BTSCOchannel); 303 1.3 plunky if (prop_object_type(obj) != PROP_TYPE_NUMBER 304 1.42 thorpej || prop_number_signed_value(obj) < RFCOMM_CHANNEL_MIN 305 1.42 thorpej || prop_number_signed_value(obj) > RFCOMM_CHANNEL_MAX) { 306 1.3 plunky aprint_error(" invalid %s", BTSCOchannel); 307 1.1 tron return; 308 1.1 tron } 309 1.42 thorpej sc->sc_channel = prop_number_signed_value(obj); 310 1.1 tron 311 1.1 tron aprint_verbose(" channel %d", sc->sc_channel); 312 1.1 tron aprint_normal("\n"); 313 1.1 tron 314 1.1 tron DPRINTF("sc=%p\n", sc); 315 1.1 tron 316 1.1 tron /* 317 1.1 tron * set up transmit interrupt 318 1.1 tron */ 319 1.15 ad sc->sc_intr = softint_establish(SOFTINT_NET, btsco_intr, sc); 320 1.1 tron if (sc->sc_intr == NULL) { 321 1.16 plunky aprint_error_dev(self, "softint_establish failed\n"); 322 1.1 tron return; 323 1.1 tron } 324 1.1 tron 325 1.1 tron /* 326 1.1 tron * attach audio device 327 1.1 tron */ 328 1.16 plunky sc->sc_audio = audio_attach_mi(&btsco_if, sc, self); 329 1.1 tron if (sc->sc_audio == NULL) { 330 1.16 plunky aprint_error_dev(self, "audio_attach_mi failed\n"); 331 1.1 tron return; 332 1.1 tron } 333 1.28 plunky 334 1.28 plunky pmf_device_register(self, NULL, NULL); 335 1.1 tron } 336 1.1 tron 337 1.1 tron static int 338 1.16 plunky btsco_detach(device_t self, int flags) 339 1.1 tron { 340 1.16 plunky struct btsco_softc *sc = device_private(self); 341 1.1 tron 342 1.1 tron DPRINTF("sc=%p\n", sc); 343 1.1 tron 344 1.28 plunky pmf_device_deregister(self); 345 1.28 plunky 346 1.20 ad mutex_enter(bt_lock); 347 1.1 tron if (sc->sc_sco != NULL) { 348 1.1 tron DPRINTF("sc_sco=%p\n", sc->sc_sco); 349 1.32 rtr sco_disconnect_pcb(sc->sc_sco, 0); 350 1.29 rmind sco_detach_pcb(&sc->sc_sco); 351 1.1 tron sc->sc_sco = NULL; 352 1.1 tron } 353 1.1 tron 354 1.1 tron if (sc->sc_sco_l != NULL) { 355 1.1 tron DPRINTF("sc_sco_l=%p\n", sc->sc_sco_l); 356 1.29 rmind sco_detach_pcb(&sc->sc_sco_l); 357 1.1 tron sc->sc_sco_l = NULL; 358 1.1 tron } 359 1.20 ad mutex_exit(bt_lock); 360 1.1 tron 361 1.1 tron if (sc->sc_audio != NULL) { 362 1.1 tron DPRINTF("sc_audio=%p\n", sc->sc_audio); 363 1.1 tron config_detach(sc->sc_audio, flags); 364 1.1 tron sc->sc_audio = NULL; 365 1.1 tron } 366 1.1 tron 367 1.1 tron if (sc->sc_intr != NULL) { 368 1.15 ad softint_disestablish(sc->sc_intr); 369 1.1 tron sc->sc_intr = NULL; 370 1.1 tron } 371 1.1 tron 372 1.35 nat mutex_enter(bt_lock); 373 1.43 rin m_freem(sc->sc_rx_mbuf); 374 1.43 rin sc->sc_rx_mbuf = NULL; 375 1.35 nat mutex_exit(bt_lock); 376 1.1 tron 377 1.1 tron if (sc->sc_tx_refcnt > 0) { 378 1.16 plunky aprint_error_dev(self, "tx_refcnt=%d!\n", sc->sc_tx_refcnt); 379 1.1 tron 380 1.1 tron if ((flags & DETACH_FORCE) == 0) 381 1.1 tron return EAGAIN; 382 1.1 tron } 383 1.1 tron 384 1.20 ad cv_destroy(&sc->sc_connect); 385 1.35 nat mutex_destroy(&sc->sc_lock); 386 1.20 ad 387 1.1 tron return 0; 388 1.1 tron } 389 1.1 tron 390 1.1 tron /***************************************************************************** 391 1.1 tron * 392 1.1 tron * bluetooth(9) methods for SCO 393 1.1 tron * 394 1.1 tron * All these are called from Bluetooth Protocol code, in a soft 395 1.1 tron * interrupt context at IPL_SOFTNET. 396 1.1 tron */ 397 1.1 tron 398 1.1 tron static void 399 1.11 christos btsco_sco_connecting(void *arg) 400 1.1 tron { 401 1.1 tron /* struct btsco_softc *sc = arg; */ 402 1.1 tron 403 1.1 tron /* dont care */ 404 1.1 tron } 405 1.1 tron 406 1.1 tron static void 407 1.1 tron btsco_sco_connected(void *arg) 408 1.1 tron { 409 1.1 tron struct btsco_softc *sc = arg; 410 1.1 tron 411 1.16 plunky DPRINTF("%s\n", sc->sc_name); 412 1.1 tron 413 1.1 tron KASSERT(sc->sc_sco != NULL); 414 1.1 tron KASSERT(sc->sc_state == BTSCO_WAIT_CONNECT); 415 1.1 tron 416 1.2 plunky /* 417 1.2 plunky * If we are listening, no more need 418 1.2 plunky */ 419 1.2 plunky if (sc->sc_sco_l != NULL) 420 1.29 rmind sco_detach_pcb(&sc->sc_sco_l); 421 1.2 plunky 422 1.1 tron sc->sc_state = BTSCO_OPEN; 423 1.20 ad cv_broadcast(&sc->sc_connect); 424 1.1 tron } 425 1.1 tron 426 1.1 tron static void 427 1.1 tron btsco_sco_disconnected(void *arg, int err) 428 1.1 tron { 429 1.1 tron struct btsco_softc *sc = arg; 430 1.1 tron 431 1.16 plunky DPRINTF("%s sc_state %d\n", sc->sc_name, sc->sc_state); 432 1.1 tron 433 1.1 tron KASSERT(sc->sc_sco != NULL); 434 1.1 tron 435 1.1 tron sc->sc_err = err; 436 1.29 rmind sco_detach_pcb(&sc->sc_sco); 437 1.1 tron 438 1.1 tron switch (sc->sc_state) { 439 1.1 tron case BTSCO_CLOSED: /* dont think this can happen */ 440 1.1 tron break; 441 1.1 tron 442 1.1 tron case BTSCO_WAIT_CONNECT: /* connect failed */ 443 1.20 ad cv_broadcast(&sc->sc_connect); 444 1.1 tron break; 445 1.1 tron 446 1.1 tron case BTSCO_OPEN: /* link lost */ 447 1.2 plunky /* 448 1.2 plunky * If IO is in progress, tell the audio driver that it 449 1.2 plunky * has completed so that when it tries to send more, we 450 1.2 plunky * can indicate an error. 451 1.2 plunky */ 452 1.35 nat mutex_enter(bt_lock); 453 1.2 plunky if (sc->sc_tx_pending > 0) { 454 1.2 plunky sc->sc_tx_pending = 0; 455 1.2 plunky (*sc->sc_tx_intr)(sc->sc_tx_intrarg); 456 1.2 plunky } 457 1.2 plunky if (sc->sc_rx_want > 0) { 458 1.2 plunky sc->sc_rx_want = 0; 459 1.2 plunky (*sc->sc_rx_intr)(sc->sc_rx_intrarg); 460 1.2 plunky } 461 1.35 nat mutex_exit(bt_lock); 462 1.1 tron break; 463 1.1 tron 464 1.1 tron default: 465 1.1 tron UNKNOWN(sc->sc_state); 466 1.1 tron } 467 1.1 tron 468 1.1 tron sc->sc_state = BTSCO_CLOSED; 469 1.1 tron } 470 1.1 tron 471 1.1 tron static void * 472 1.11 christos btsco_sco_newconn(void *arg, struct sockaddr_bt *laddr, 473 1.10 christos struct sockaddr_bt *raddr) 474 1.1 tron { 475 1.1 tron struct btsco_softc *sc = arg; 476 1.1 tron 477 1.16 plunky DPRINTF("%s\n", sc->sc_name); 478 1.16 plunky 479 1.1 tron if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0 480 1.1 tron || sc->sc_state != BTSCO_WAIT_CONNECT 481 1.1 tron || sc->sc_sco != NULL) 482 1.1 tron return NULL; 483 1.1 tron 484 1.29 rmind sco_attach_pcb(&sc->sc_sco, &btsco_sco_proto, sc); 485 1.1 tron return sc->sc_sco; 486 1.1 tron } 487 1.1 tron 488 1.1 tron static void 489 1.1 tron btsco_sco_complete(void *arg, int count) 490 1.1 tron { 491 1.1 tron struct btsco_softc *sc = arg; 492 1.1 tron 493 1.16 plunky DPRINTFN(10, "%s count %d\n", sc->sc_name, count); 494 1.1 tron 495 1.1 tron if (sc->sc_tx_pending > 0) { 496 1.1 tron sc->sc_tx_pending -= count; 497 1.1 tron if (sc->sc_tx_pending == 0) 498 1.1 tron (*sc->sc_tx_intr)(sc->sc_tx_intrarg); 499 1.1 tron } 500 1.1 tron } 501 1.1 tron 502 1.1 tron static void 503 1.14 plunky btsco_sco_linkmode(void *arg, int new) 504 1.14 plunky { 505 1.14 plunky /* struct btsco_softc *sc = arg; */ 506 1.14 plunky 507 1.14 plunky /* dont care */ 508 1.14 plunky } 509 1.14 plunky 510 1.14 plunky static void 511 1.1 tron btsco_sco_input(void *arg, struct mbuf *m) 512 1.1 tron { 513 1.1 tron struct btsco_softc *sc = arg; 514 1.25 jmcneill int len; 515 1.1 tron 516 1.16 plunky DPRINTFN(10, "%s len=%d\n", sc->sc_name, m->m_pkthdr.len); 517 1.1 tron 518 1.1 tron if (sc->sc_rx_want == 0) { 519 1.1 tron m_freem(m); 520 1.1 tron } else { 521 1.1 tron KASSERT(sc->sc_rx_intr != NULL); 522 1.1 tron KASSERT(sc->sc_rx_block != NULL); 523 1.1 tron 524 1.1 tron len = MIN(sc->sc_rx_want, m->m_pkthdr.len); 525 1.1 tron m_copydata(m, 0, len, sc->sc_rx_block); 526 1.1 tron 527 1.1 tron sc->sc_rx_want -= len; 528 1.1 tron sc->sc_rx_block += len; 529 1.1 tron 530 1.1 tron if (len > m->m_pkthdr.len) { 531 1.43 rin m_freem(sc->sc_rx_mbuf); 532 1.1 tron 533 1.1 tron m_adj(m, len); 534 1.1 tron sc->sc_rx_mbuf = m; 535 1.1 tron } else { 536 1.1 tron m_freem(m); 537 1.1 tron } 538 1.1 tron 539 1.1 tron if (sc->sc_rx_want == 0) 540 1.1 tron (*sc->sc_rx_intr)(sc->sc_rx_intrarg); 541 1.1 tron } 542 1.1 tron } 543 1.1 tron 544 1.1 tron 545 1.1 tron /***************************************************************************** 546 1.1 tron * 547 1.1 tron * audio(9) methods 548 1.1 tron * 549 1.1 tron */ 550 1.1 tron 551 1.1 tron static int 552 1.11 christos btsco_open(void *hdl, int flags) 553 1.1 tron { 554 1.1 tron struct sockaddr_bt sa; 555 1.1 tron struct btsco_softc *sc = hdl; 556 1.22 plunky struct sockopt sopt; 557 1.20 ad int err, timo; 558 1.1 tron 559 1.16 plunky DPRINTF("%s flags 0x%x\n", sc->sc_name, flags); 560 1.1 tron /* flags FREAD & FWRITE? */ 561 1.1 tron 562 1.1 tron if (sc->sc_sco != NULL || sc->sc_sco_l != NULL) 563 1.1 tron return EIO; 564 1.1 tron 565 1.26 jmcneill KASSERT(mutex_owned(bt_lock)); 566 1.1 tron 567 1.1 tron memset(&sa, 0, sizeof(sa)); 568 1.1 tron sa.bt_len = sizeof(sa); 569 1.1 tron sa.bt_family = AF_BLUETOOTH; 570 1.1 tron bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); 571 1.1 tron 572 1.1 tron if (sc->sc_flags & BTSCO_LISTEN) { 573 1.29 rmind err = sco_attach_pcb(&sc->sc_sco_l, &btsco_sco_proto, sc); 574 1.1 tron if (err) 575 1.1 tron goto done; 576 1.1 tron 577 1.30 rtr err = sco_bind_pcb(sc->sc_sco_l, &sa); 578 1.1 tron if (err) { 579 1.29 rmind sco_detach_pcb(&sc->sc_sco_l); 580 1.1 tron goto done; 581 1.1 tron } 582 1.1 tron 583 1.30 rtr err = sco_listen_pcb(sc->sc_sco_l); 584 1.1 tron if (err) { 585 1.29 rmind sco_detach_pcb(&sc->sc_sco_l); 586 1.1 tron goto done; 587 1.1 tron } 588 1.2 plunky 589 1.2 plunky timo = 0; /* no timeout */ 590 1.1 tron } else { 591 1.29 rmind err = sco_attach_pcb(&sc->sc_sco, &btsco_sco_proto, sc); 592 1.1 tron if (err) 593 1.1 tron goto done; 594 1.1 tron 595 1.30 rtr err = sco_bind_pcb(sc->sc_sco, &sa); 596 1.1 tron if (err) { 597 1.29 rmind sco_detach_pcb(&sc->sc_sco); 598 1.1 tron goto done; 599 1.1 tron } 600 1.1 tron 601 1.1 tron bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); 602 1.31 rtr err = sco_connect_pcb(sc->sc_sco, &sa); 603 1.1 tron if (err) { 604 1.29 rmind sco_detach_pcb(&sc->sc_sco); 605 1.1 tron goto done; 606 1.1 tron } 607 1.2 plunky 608 1.2 plunky timo = BTSCO_TIMEOUT; 609 1.1 tron } 610 1.1 tron 611 1.1 tron sc->sc_state = BTSCO_WAIT_CONNECT; 612 1.1 tron while (err == 0 && sc->sc_state == BTSCO_WAIT_CONNECT) 613 1.20 ad err = cv_timedwait_sig(&sc->sc_connect, bt_lock, timo); 614 1.1 tron 615 1.1 tron switch (sc->sc_state) { 616 1.1 tron case BTSCO_CLOSED: /* disconnected */ 617 1.1 tron err = sc->sc_err; 618 1.1 tron 619 1.37 mrg /* FALLTHROUGH */ 620 1.1 tron case BTSCO_WAIT_CONNECT: /* error */ 621 1.1 tron if (sc->sc_sco != NULL) 622 1.29 rmind sco_detach_pcb(&sc->sc_sco); 623 1.1 tron 624 1.1 tron if (sc->sc_sco_l != NULL) 625 1.29 rmind sco_detach_pcb(&sc->sc_sco_l); 626 1.1 tron 627 1.1 tron break; 628 1.1 tron 629 1.1 tron case BTSCO_OPEN: /* hurrah */ 630 1.22 plunky sockopt_init(&sopt, BTPROTO_SCO, SO_SCO_MTU, 0); 631 1.22 plunky (void)sco_getopt(sc->sc_sco, &sopt); 632 1.22 plunky (void)sockopt_get(&sopt, &sc->sc_mtu, sizeof(sc->sc_mtu)); 633 1.22 plunky sockopt_destroy(&sopt); 634 1.1 tron break; 635 1.1 tron 636 1.1 tron default: 637 1.1 tron UNKNOWN(sc->sc_state); 638 1.1 tron break; 639 1.1 tron } 640 1.1 tron 641 1.1 tron done: 642 1.1 tron DPRINTF("done err=%d, sc_state=%d, sc_mtu=%d\n", 643 1.1 tron err, sc->sc_state, sc->sc_mtu); 644 1.1 tron return err; 645 1.1 tron } 646 1.1 tron 647 1.1 tron static void 648 1.1 tron btsco_close(void *hdl) 649 1.1 tron { 650 1.1 tron struct btsco_softc *sc = hdl; 651 1.1 tron 652 1.16 plunky DPRINTF("%s\n", sc->sc_name); 653 1.1 tron 654 1.26 jmcneill KASSERT(mutex_owned(bt_lock)); 655 1.26 jmcneill 656 1.1 tron if (sc->sc_sco != NULL) { 657 1.32 rtr sco_disconnect_pcb(sc->sc_sco, 0); 658 1.29 rmind sco_detach_pcb(&sc->sc_sco); 659 1.1 tron } 660 1.1 tron 661 1.1 tron if (sc->sc_sco_l != NULL) { 662 1.29 rmind sco_detach_pcb(&sc->sc_sco_l); 663 1.1 tron } 664 1.1 tron 665 1.43 rin m_freem(sc->sc_rx_mbuf); 666 1.43 rin sc->sc_rx_mbuf = NULL; 667 1.1 tron 668 1.1 tron sc->sc_rx_want = 0; 669 1.1 tron sc->sc_rx_block = NULL; 670 1.1 tron sc->sc_rx_intr = NULL; 671 1.1 tron sc->sc_rx_intrarg = NULL; 672 1.1 tron 673 1.1 tron sc->sc_tx_size = 0; 674 1.1 tron sc->sc_tx_block = NULL; 675 1.1 tron sc->sc_tx_pending = 0; 676 1.1 tron sc->sc_tx_intr = NULL; 677 1.1 tron sc->sc_tx_intrarg = NULL; 678 1.1 tron } 679 1.1 tron 680 1.1 tron static int 681 1.39 isaki btsco_query_format(void *hdl, audio_format_query_t *afp) 682 1.1 tron { 683 1.1 tron 684 1.39 isaki return audio_query_format(&btsco_format, 1, afp); 685 1.1 tron } 686 1.1 tron 687 1.1 tron static int 688 1.39 isaki btsco_set_format(void *hdl, int setmode, 689 1.39 isaki const audio_params_t *play, const audio_params_t *rec, 690 1.39 isaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 691 1.1 tron { 692 1.1 tron 693 1.39 isaki /* We have only one format so nothing to do here. */ 694 1.8 plunky return 0; 695 1.1 tron } 696 1.1 tron 697 1.1 tron /* 698 1.1 tron * If we have an MTU value to use, round the blocksize to that. 699 1.1 tron */ 700 1.1 tron static int 701 1.11 christos btsco_round_blocksize(void *hdl, int bs, int mode, 702 1.11 christos const audio_params_t *param) 703 1.1 tron { 704 1.1 tron struct btsco_softc *sc = hdl; 705 1.1 tron 706 1.4 plunky if (sc->sc_mtu > 0) { 707 1.1 tron bs = (bs / sc->sc_mtu) * sc->sc_mtu; 708 1.4 plunky if (bs == 0) 709 1.4 plunky bs = sc->sc_mtu; 710 1.4 plunky } 711 1.13 plunky 712 1.1 tron DPRINTF("%s mode=0x%x, bs=%d, sc_mtu=%d\n", 713 1.16 plunky sc->sc_name, mode, bs, sc->sc_mtu); 714 1.1 tron 715 1.1 tron return bs; 716 1.1 tron } 717 1.1 tron 718 1.1 tron /* 719 1.1 tron * Start Output 720 1.1 tron * 721 1.35 nat * We dont want to be calling the network stack with bt_lock held 722 1.25 jmcneill * so make a note of what is to be sent, and schedule an interrupt to 723 1.25 jmcneill * bundle it up and queue it. 724 1.1 tron */ 725 1.1 tron static int 726 1.1 tron btsco_start_output(void *hdl, void *block, int blksize, 727 1.1 tron void (*intr)(void *), void *intrarg) 728 1.1 tron { 729 1.1 tron struct btsco_softc *sc = hdl; 730 1.1 tron 731 1.16 plunky DPRINTFN(5, "%s blksize %d\n", sc->sc_name, blksize); 732 1.1 tron 733 1.1 tron if (sc->sc_sco == NULL) 734 1.1 tron return ENOTCONN; /* connection lost */ 735 1.1 tron 736 1.1 tron sc->sc_tx_block = block; 737 1.1 tron sc->sc_tx_pending = 0; 738 1.1 tron sc->sc_tx_size = blksize; 739 1.1 tron sc->sc_tx_intr = intr; 740 1.1 tron sc->sc_tx_intrarg = intrarg; 741 1.1 tron 742 1.34 nat kpreempt_disable(); 743 1.15 ad softint_schedule(sc->sc_intr); 744 1.34 nat kpreempt_enable(); 745 1.1 tron return 0; 746 1.1 tron } 747 1.1 tron 748 1.1 tron /* 749 1.1 tron * Start Input 750 1.1 tron * 751 1.1 tron * When the SCO link is up, we are getting data in any case, so all we do 752 1.1 tron * is note what we want and where to put it and let the sco_input routine 753 1.1 tron * fill in the data. 754 1.1 tron * 755 1.1 tron * If there was any leftover data that didnt fit in the last block, retry 756 1.1 tron * it now. 757 1.1 tron */ 758 1.1 tron static int 759 1.1 tron btsco_start_input(void *hdl, void *block, int blksize, 760 1.1 tron void (*intr)(void *), void *intrarg) 761 1.1 tron { 762 1.1 tron struct btsco_softc *sc = hdl; 763 1.1 tron struct mbuf *m; 764 1.1 tron 765 1.16 plunky DPRINTFN(5, "%s blksize %d\n", sc->sc_name, blksize); 766 1.1 tron 767 1.1 tron if (sc->sc_sco == NULL) 768 1.5 plunky return ENOTCONN; 769 1.1 tron 770 1.1 tron sc->sc_rx_want = blksize; 771 1.1 tron sc->sc_rx_block = block; 772 1.1 tron sc->sc_rx_intr = intr; 773 1.1 tron sc->sc_rx_intrarg = intrarg; 774 1.1 tron 775 1.1 tron if (sc->sc_rx_mbuf != NULL) { 776 1.1 tron m = sc->sc_rx_mbuf; 777 1.1 tron sc->sc_rx_mbuf = NULL; 778 1.1 tron btsco_sco_input(sc, m); 779 1.1 tron } 780 1.1 tron 781 1.1 tron return 0; 782 1.1 tron } 783 1.1 tron 784 1.1 tron /* 785 1.1 tron * Halt Output 786 1.1 tron * 787 1.1 tron * This doesnt really halt the output, but it will look 788 1.1 tron * that way to the audio driver. The current block will 789 1.1 tron * still be transmitted. 790 1.1 tron */ 791 1.1 tron static int 792 1.1 tron btsco_halt_output(void *hdl) 793 1.1 tron { 794 1.1 tron struct btsco_softc *sc = hdl; 795 1.1 tron 796 1.16 plunky DPRINTFN(5, "%s\n", sc->sc_name); 797 1.1 tron 798 1.1 tron sc->sc_tx_size = 0; 799 1.1 tron sc->sc_tx_block = NULL; 800 1.1 tron sc->sc_tx_pending = 0; 801 1.1 tron sc->sc_tx_intr = NULL; 802 1.1 tron sc->sc_tx_intrarg = NULL; 803 1.1 tron 804 1.1 tron return 0; 805 1.1 tron } 806 1.1 tron 807 1.1 tron /* 808 1.1 tron * Halt Input 809 1.1 tron * 810 1.1 tron * This doesnt really halt the input, but it will look 811 1.1 tron * that way to the audio driver. Incoming data will be 812 1.1 tron * discarded. 813 1.1 tron */ 814 1.1 tron static int 815 1.1 tron btsco_halt_input(void *hdl) 816 1.1 tron { 817 1.1 tron struct btsco_softc *sc = hdl; 818 1.1 tron 819 1.16 plunky DPRINTFN(5, "%s\n", sc->sc_name); 820 1.1 tron 821 1.1 tron sc->sc_rx_want = 0; 822 1.1 tron sc->sc_rx_block = NULL; 823 1.1 tron sc->sc_rx_intr = NULL; 824 1.1 tron sc->sc_rx_intrarg = NULL; 825 1.1 tron 826 1.43 rin m_freem(sc->sc_rx_mbuf); 827 1.43 rin sc->sc_rx_mbuf = NULL; 828 1.1 tron 829 1.1 tron return 0; 830 1.1 tron } 831 1.1 tron 832 1.1 tron static int 833 1.11 christos btsco_getdev(void *hdl, struct audio_device *ret) 834 1.1 tron { 835 1.1 tron 836 1.1 tron *ret = btsco_device; 837 1.1 tron return 0; 838 1.1 tron } 839 1.1 tron 840 1.1 tron static int 841 1.1 tron btsco_set_port(void *hdl, mixer_ctrl_t *mc) 842 1.1 tron { 843 1.1 tron struct btsco_softc *sc = hdl; 844 1.1 tron int err = 0; 845 1.1 tron 846 1.16 plunky DPRINTF("%s dev %d type %d\n", sc->sc_name, mc->dev, mc->type); 847 1.1 tron 848 1.1 tron switch (mc->dev) { 849 1.1 tron case BTSCO_VGS: 850 1.1 tron if (mc->type != AUDIO_MIXER_VALUE || 851 1.1 tron mc->un.value.num_channels != 1) { 852 1.1 tron err = EINVAL; 853 1.1 tron break; 854 1.1 tron } 855 1.1 tron 856 1.1 tron sc->sc_vgs = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 857 1.1 tron break; 858 1.1 tron 859 1.1 tron case BTSCO_VGM: 860 1.1 tron if (mc->type != AUDIO_MIXER_VALUE || 861 1.1 tron mc->un.value.num_channels != 1) { 862 1.1 tron err = EINVAL; 863 1.1 tron break; 864 1.1 tron } 865 1.1 tron 866 1.1 tron sc->sc_vgm = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 867 1.1 tron break; 868 1.1 tron 869 1.1 tron default: 870 1.1 tron err = EINVAL; 871 1.1 tron break; 872 1.1 tron } 873 1.1 tron 874 1.1 tron return err; 875 1.1 tron } 876 1.1 tron 877 1.1 tron static int 878 1.1 tron btsco_get_port(void *hdl, mixer_ctrl_t *mc) 879 1.1 tron { 880 1.1 tron struct btsco_softc *sc = hdl; 881 1.1 tron int err = 0; 882 1.1 tron 883 1.16 plunky DPRINTF("%s dev %d\n", sc->sc_name, mc->dev); 884 1.1 tron 885 1.1 tron switch (mc->dev) { 886 1.1 tron case BTSCO_VGS: 887 1.1 tron mc->type = AUDIO_MIXER_VALUE; 888 1.1 tron mc->un.value.num_channels = 1; 889 1.1 tron mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_vgs; 890 1.1 tron break; 891 1.1 tron 892 1.1 tron case BTSCO_VGM: 893 1.1 tron mc->type = AUDIO_MIXER_VALUE; 894 1.1 tron mc->un.value.num_channels = 1; 895 1.1 tron mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_vgm; 896 1.1 tron break; 897 1.1 tron 898 1.1 tron default: 899 1.1 tron err = EINVAL; 900 1.1 tron break; 901 1.1 tron } 902 1.1 tron 903 1.1 tron return err; 904 1.1 tron } 905 1.1 tron 906 1.1 tron static int 907 1.11 christos btsco_query_devinfo(void *hdl, mixer_devinfo_t *di) 908 1.1 tron { 909 1.1 tron /* struct btsco_softc *sc = hdl; */ 910 1.1 tron int err = 0; 911 1.1 tron 912 1.1 tron switch(di->index) { 913 1.1 tron case BTSCO_VGS: 914 1.1 tron di->mixer_class = BTSCO_INPUT_CLASS; 915 1.1 tron di->next = di->prev = AUDIO_MIXER_LAST; 916 1.1 tron strcpy(di->label.name, AudioNspeaker); 917 1.1 tron di->type = AUDIO_MIXER_VALUE; 918 1.1 tron strcpy(di->un.v.units.name, AudioNvolume); 919 1.1 tron di->un.v.num_channels = 1; 920 1.1 tron di->un.v.delta = BTSCO_DELTA; 921 1.1 tron break; 922 1.1 tron 923 1.1 tron case BTSCO_VGM: 924 1.1 tron di->mixer_class = BTSCO_INPUT_CLASS; 925 1.1 tron di->next = di->prev = AUDIO_MIXER_LAST; 926 1.1 tron strcpy(di->label.name, AudioNmicrophone); 927 1.1 tron di->type = AUDIO_MIXER_VALUE; 928 1.1 tron strcpy(di->un.v.units.name, AudioNvolume); 929 1.1 tron di->un.v.num_channels = 1; 930 1.1 tron di->un.v.delta = BTSCO_DELTA; 931 1.1 tron break; 932 1.1 tron 933 1.1 tron case BTSCO_INPUT_CLASS: 934 1.1 tron di->mixer_class = BTSCO_INPUT_CLASS; 935 1.1 tron di->next = di->prev = AUDIO_MIXER_LAST; 936 1.1 tron strcpy(di->label.name, AudioCinputs); 937 1.1 tron di->type = AUDIO_MIXER_CLASS; 938 1.1 tron break; 939 1.1 tron 940 1.1 tron default: 941 1.1 tron err = ENXIO; 942 1.1 tron break; 943 1.1 tron } 944 1.1 tron 945 1.1 tron return err; 946 1.1 tron } 947 1.1 tron 948 1.1 tron /* 949 1.1 tron * Allocate Ring Buffers. 950 1.1 tron */ 951 1.1 tron static void * 952 1.25 jmcneill btsco_allocm(void *hdl, int direction, size_t size) 953 1.1 tron { 954 1.1 tron struct btsco_softc *sc = hdl; 955 1.1 tron void *addr; 956 1.1 tron 957 1.40 isaki DPRINTF("%s: size %zd direction %d\n", sc->sc_name, size, direction); 958 1.1 tron 959 1.25 jmcneill addr = kmem_alloc(size, KM_SLEEP); 960 1.1 tron 961 1.36 chs if (direction == AUMODE_PLAY) { 962 1.1 tron sc->sc_tx_buf = addr; 963 1.1 tron sc->sc_tx_refcnt = 0; 964 1.1 tron } 965 1.1 tron 966 1.1 tron return addr; 967 1.1 tron } 968 1.1 tron 969 1.1 tron /* 970 1.1 tron * Free Ring Buffers. 971 1.1 tron * 972 1.1 tron * Because we used external memory for the tx mbufs, we dont 973 1.1 tron * want to free the memory until all the mbufs are done with 974 1.1 tron * 975 1.1 tron * Just to be sure, dont free if something is still pending. 976 1.1 tron * This would be a memory leak but at least there is a warning.. 977 1.1 tron */ 978 1.1 tron static void 979 1.25 jmcneill btsco_freem(void *hdl, void *addr, size_t size) 980 1.1 tron { 981 1.1 tron struct btsco_softc *sc = hdl; 982 1.1 tron int count = hz / 2; 983 1.1 tron 984 1.1 tron if (addr == sc->sc_tx_buf) { 985 1.16 plunky DPRINTF("%s: tx_refcnt=%d\n", sc->sc_name, sc->sc_tx_refcnt); 986 1.1 tron 987 1.1 tron sc->sc_tx_buf = NULL; 988 1.1 tron 989 1.1 tron while (sc->sc_tx_refcnt> 0 && count-- > 0) 990 1.25 jmcneill kpause("drain", false, 1, NULL); 991 1.1 tron 992 1.1 tron if (sc->sc_tx_refcnt > 0) { 993 1.18 plunky aprint_error("%s: ring buffer unreleased!\n", sc->sc_name); 994 1.1 tron return; 995 1.1 tron } 996 1.1 tron } 997 1.1 tron 998 1.25 jmcneill kmem_free(addr, size); 999 1.1 tron } 1000 1.1 tron 1001 1.1 tron static int 1002 1.11 christos btsco_get_props(void *hdl) 1003 1.1 tron { 1004 1.1 tron 1005 1.41 isaki return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 1006 1.41 isaki AUDIO_PROP_FULLDUPLEX; 1007 1.1 tron } 1008 1.1 tron 1009 1.25 jmcneill static void 1010 1.25 jmcneill btsco_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread) 1011 1.25 jmcneill { 1012 1.25 jmcneill struct btsco_softc *sc = hdl; 1013 1.25 jmcneill 1014 1.35 nat *thread = &sc->sc_lock; 1015 1.35 nat *intr = bt_lock; 1016 1.25 jmcneill } 1017 1.25 jmcneill 1018 1.1 tron /* 1019 1.1 tron * Handle private ioctl. We pass information out about how to talk 1020 1.1 tron * to the device and mixer. 1021 1.1 tron */ 1022 1.1 tron static int 1023 1.12 christos btsco_dev_ioctl(void *hdl, u_long cmd, void *addr, int flag, 1024 1.11 christos struct lwp *l) 1025 1.1 tron { 1026 1.1 tron struct btsco_softc *sc = hdl; 1027 1.1 tron struct btsco_info *bi = (struct btsco_info *)addr; 1028 1.1 tron int err = 0; 1029 1.1 tron 1030 1.16 plunky DPRINTF("%s cmd 0x%lx flag %d\n", sc->sc_name, cmd, flag); 1031 1.1 tron 1032 1.1 tron switch (cmd) { 1033 1.1 tron case BTSCO_GETINFO: 1034 1.1 tron memset(bi, 0, sizeof(*bi)); 1035 1.1 tron bdaddr_copy(&bi->laddr, &sc->sc_laddr); 1036 1.1 tron bdaddr_copy(&bi->raddr, &sc->sc_raddr); 1037 1.1 tron bi->channel = sc->sc_channel; 1038 1.1 tron bi->vgs = BTSCO_VGS; 1039 1.1 tron bi->vgm = BTSCO_VGM; 1040 1.1 tron break; 1041 1.1 tron 1042 1.1 tron default: 1043 1.1 tron err = EPASSTHROUGH; 1044 1.1 tron break; 1045 1.1 tron } 1046 1.1 tron 1047 1.1 tron return err; 1048 1.1 tron } 1049 1.1 tron 1050 1.1 tron 1051 1.1 tron /***************************************************************************** 1052 1.1 tron * 1053 1.1 tron * misc btsco functions 1054 1.1 tron * 1055 1.1 tron */ 1056 1.1 tron 1057 1.1 tron /* 1058 1.1 tron * Our transmit interrupt. This is triggered when a new block is to be 1059 1.1 tron * sent. We send mtu sized chunks of the block as mbufs with external 1060 1.33 rtr * storage to sco_send_pcb() 1061 1.1 tron */ 1062 1.1 tron static void 1063 1.1 tron btsco_intr(void *arg) 1064 1.1 tron { 1065 1.1 tron struct btsco_softc *sc = arg; 1066 1.1 tron struct mbuf *m; 1067 1.1 tron uint8_t *block; 1068 1.1 tron int mlen, size; 1069 1.1 tron 1070 1.1 tron DPRINTFN(10, "%s block %p size %d\n", 1071 1.16 plunky sc->sc_name, sc->sc_tx_block, sc->sc_tx_size); 1072 1.1 tron 1073 1.1 tron if (sc->sc_sco == NULL) 1074 1.1 tron return; /* connection is lost */ 1075 1.1 tron 1076 1.35 nat mutex_enter(bt_lock); 1077 1.1 tron block = sc->sc_tx_block; 1078 1.1 tron size = sc->sc_tx_size; 1079 1.1 tron sc->sc_tx_block = NULL; 1080 1.1 tron sc->sc_tx_size = 0; 1081 1.1 tron 1082 1.1 tron while (size > 0) { 1083 1.1 tron MGETHDR(m, M_DONTWAIT, MT_DATA); 1084 1.1 tron if (m == NULL) 1085 1.1 tron break; 1086 1.1 tron 1087 1.1 tron mlen = MIN(sc->sc_mtu, size); 1088 1.1 tron 1089 1.1 tron /* I think M_DEVBUF is true but not relevant */ 1090 1.1 tron MEXTADD(m, block, mlen, M_DEVBUF, btsco_extfree, sc); 1091 1.1 tron if ((m->m_flags & M_EXT) == 0) { 1092 1.1 tron m_free(m); 1093 1.1 tron break; 1094 1.1 tron } 1095 1.1 tron sc->sc_tx_refcnt++; 1096 1.1 tron 1097 1.1 tron m->m_pkthdr.len = m->m_len = mlen; 1098 1.1 tron sc->sc_tx_pending++; 1099 1.1 tron 1100 1.33 rtr if (sco_send_pcb(sc->sc_sco, m) > 0) { 1101 1.1 tron sc->sc_tx_pending--; 1102 1.1 tron break; 1103 1.1 tron } 1104 1.1 tron 1105 1.1 tron block += mlen; 1106 1.1 tron size -= mlen; 1107 1.1 tron } 1108 1.21 plunky mutex_exit(bt_lock); 1109 1.1 tron } 1110 1.1 tron 1111 1.1 tron /* 1112 1.1 tron * Release the mbuf, we keep a reference count on the tx buffer so 1113 1.1 tron * that we dont release it before its free. 1114 1.1 tron */ 1115 1.1 tron static void 1116 1.12 christos btsco_extfree(struct mbuf *m, void *addr, size_t size, 1117 1.10 christos void *arg) 1118 1.1 tron { 1119 1.1 tron struct btsco_softc *sc = arg; 1120 1.1 tron 1121 1.1 tron if (m != NULL) 1122 1.17 ad pool_cache_put(mb_cache, m); 1123 1.1 tron 1124 1.1 tron sc->sc_tx_refcnt--; 1125 1.1 tron } 1126