static void btsco_close(void *hdl) { struct btsco_softc *sc = hdl; DPRINTF("%s\n", sc->sc_name); KASSERT(mutex_owned(bt_lock)); if (sc->sc_sco != NULL) { sco_disconnect_pcb(sc->sc_sco, 0); sco_detach_pcb(&sc->sc_sco); } if (sc->sc_sco_l != NULL) { sco_detach_pcb(&sc->sc_sco_l); } if (sc->sc_rx_mbuf != NULL) { m_freem(sc->sc_rx_mbuf); sc->sc_rx_mbuf = NULL; } sc->sc_rx_want = 0; sc->sc_rx_block = NULL; sc->sc_rx_intr = NULL; sc->sc_rx_intrarg = NULL; sc->sc_tx_size = 0; sc->sc_tx_block = NULL; sc->sc_tx_pending = 0; sc->sc_tx_intr = NULL; sc->sc_tx_intrarg = NULL; }
static int btsco_detach(device_t self, int flags) { struct btsco_softc *sc = device_private(self); DPRINTF("sc=%p\n", sc); pmf_device_deregister(self); mutex_enter(bt_lock); if (sc->sc_sco != NULL) { DPRINTF("sc_sco=%p\n", sc->sc_sco); sco_disconnect_pcb(sc->sc_sco, 0); sco_detach_pcb(&sc->sc_sco); sc->sc_sco = NULL; } if (sc->sc_sco_l != NULL) { DPRINTF("sc_sco_l=%p\n", sc->sc_sco_l); sco_detach_pcb(&sc->sc_sco_l); sc->sc_sco_l = NULL; } mutex_exit(bt_lock); if (sc->sc_audio != NULL) { DPRINTF("sc_audio=%p\n", sc->sc_audio); config_detach(sc->sc_audio, flags); sc->sc_audio = NULL; } if (sc->sc_intr != NULL) { softint_disestablish(sc->sc_intr); sc->sc_intr = NULL; } if (sc->sc_rx_mbuf != NULL) { m_freem(sc->sc_rx_mbuf); sc->sc_rx_mbuf = NULL; } if (sc->sc_tx_refcnt > 0) { aprint_error_dev(self, "tx_refcnt=%d!\n", sc->sc_tx_refcnt); if ((flags & DETACH_FORCE) == 0) return EAGAIN; } cv_destroy(&sc->sc_connect); mutex_destroy(&sc->sc_intr_lock); return 0; }
static void sco_detach(struct socket *so) { KASSERT(so->so_pcb != NULL); sco_detach_pcb((struct sco_pcb **)&so->so_pcb); KASSERT(so->so_pcb == NULL); }
static void btsco_sco_disconnected(void *arg, int err) { struct btsco_softc *sc = arg; DPRINTF("%s sc_state %d\n", sc->sc_name, sc->sc_state); KASSERT(sc->sc_sco != NULL); sc->sc_err = err; sco_detach_pcb(&sc->sc_sco); switch (sc->sc_state) { case BTSCO_CLOSED: /* dont think this can happen */ break; case BTSCO_WAIT_CONNECT: /* connect failed */ cv_broadcast(&sc->sc_connect); break; case BTSCO_OPEN: /* link lost */ /* * If IO is in progress, tell the audio driver that it * has completed so that when it tries to send more, we * can indicate an error. */ mutex_enter(&sc->sc_intr_lock); if (sc->sc_tx_pending > 0) { sc->sc_tx_pending = 0; (*sc->sc_tx_intr)(sc->sc_tx_intrarg); } if (sc->sc_rx_want > 0) { sc->sc_rx_want = 0; (*sc->sc_rx_intr)(sc->sc_rx_intrarg); } mutex_exit(&sc->sc_intr_lock); break; default: UNKNOWN(sc->sc_state); } sc->sc_state = BTSCO_CLOSED; }
static void btsco_sco_connected(void *arg) { struct btsco_softc *sc = arg; DPRINTF("%s\n", sc->sc_name); KASSERT(sc->sc_sco != NULL); KASSERT(sc->sc_state == BTSCO_WAIT_CONNECT); /* * If we are listening, no more need */ if (sc->sc_sco_l != NULL) sco_detach_pcb(&sc->sc_sco_l); sc->sc_state = BTSCO_OPEN; cv_broadcast(&sc->sc_connect); }
static int btsco_open(void *hdl, int flags) { struct sockaddr_bt sa; struct btsco_softc *sc = hdl; struct sockopt sopt; int err, timo; DPRINTF("%s flags 0x%x\n", sc->sc_name, flags); /* flags FREAD & FWRITE? */ if (sc->sc_sco != NULL || sc->sc_sco_l != NULL) return EIO; KASSERT(mutex_owned(bt_lock)); memset(&sa, 0, sizeof(sa)); sa.bt_len = sizeof(sa); sa.bt_family = AF_BLUETOOTH; bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); if (sc->sc_flags & BTSCO_LISTEN) { err = sco_attach_pcb(&sc->sc_sco_l, &btsco_sco_proto, sc); if (err) goto done; err = sco_bind_pcb(sc->sc_sco_l, &sa); if (err) { sco_detach_pcb(&sc->sc_sco_l); goto done; } err = sco_listen_pcb(sc->sc_sco_l); if (err) { sco_detach_pcb(&sc->sc_sco_l); goto done; } timo = 0; /* no timeout */ } else { err = sco_attach_pcb(&sc->sc_sco, &btsco_sco_proto, sc); if (err) goto done; err = sco_bind_pcb(sc->sc_sco, &sa); if (err) { sco_detach_pcb(&sc->sc_sco); goto done; } bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); err = sco_connect_pcb(sc->sc_sco, &sa); if (err) { sco_detach_pcb(&sc->sc_sco); goto done; } timo = BTSCO_TIMEOUT; } sc->sc_state = BTSCO_WAIT_CONNECT; while (err == 0 && sc->sc_state == BTSCO_WAIT_CONNECT) err = cv_timedwait_sig(&sc->sc_connect, bt_lock, timo); switch (sc->sc_state) { case BTSCO_CLOSED: /* disconnected */ err = sc->sc_err; /* fall through to */ case BTSCO_WAIT_CONNECT: /* error */ if (sc->sc_sco != NULL) sco_detach_pcb(&sc->sc_sco); if (sc->sc_sco_l != NULL) sco_detach_pcb(&sc->sc_sco_l); break; case BTSCO_OPEN: /* hurrah */ sockopt_init(&sopt, BTPROTO_SCO, SO_SCO_MTU, 0); (void)sco_getopt(sc->sc_sco, &sopt); (void)sockopt_get(&sopt, &sc->sc_mtu, sizeof(sc->sc_mtu)); sockopt_destroy(&sopt); break; default: UNKNOWN(sc->sc_state); break; } done: DPRINTF("done err=%d, sc_state=%d, sc_mtu=%d\n", err, sc->sc_state, sc->sc_mtu); return err; }