示例#1
0
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;
}
示例#2
0
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;
}
示例#3
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);
}
示例#4
0
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;
}
示例#5
0
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);
}
示例#6
0
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;
}