Exemple #1
0
void
ubt_recv_acl_complete(usbd_xfer_handle xfer,
		usbd_private_handle h, usbd_status status)
{
	struct ubt_softc *sc = h;
	struct mbuf *m;
	uint32_t count;
	void *buf;

	DPRINTFN(15, "sc=%p status=%s (%d)\n",
			sc, usbd_errstr(status), status);

	sc->sc_aclrd_busy = 0;

	if (--sc->sc_refcnt < 0) {
		DPRINTF("refcnt = %d\n", sc->sc_refcnt);
		usb_detach_wakeup(sc->sc_dev);
		return;
	}

	if (sc->sc_dying) {
		DPRINTF("sc_dying\n");
		return;
	}

	if (status != USBD_NORMAL_COMPLETION) {
		DPRINTF("status=%s (%d)\n",
			usbd_errstr(status), status);

		sc->sc_stats.err_rx++;

		if (status == USBD_STALLED)
			usbd_clear_endpoint_stall_async(sc->sc_aclrd_pipe);
		else
			return;
	} else {
		usbd_get_xfer_status(xfer, NULL, &buf, &count, NULL);

		if (count < sizeof(hci_acldata_hdr_t) - 1) {
			DPRINTF("dumped undersized packet (%d)\n", count);
			sc->sc_stats.err_rx++;
		} else {
			sc->sc_stats.acl_rx++;
			sc->sc_stats.byte_rx += count;

			m = ubt_mbufload(buf, count, HCI_ACL_DATA_PKT);
			if (m == NULL || !hci_input_acl(sc->sc_unit, m))
				sc->sc_stats.err_rx++;
		}
	}

	/* and restart */
	ubt_recv_acl_start(sc);
}
Exemple #2
0
/*
 * receive incoming data from device, store in mbuf chain and
 * pass on complete packets to bt device
 */
static void
bt3c_receive(struct bt3c_softc *sc)
{
	struct mbuf *m = sc->sc_rxp;
	int space = 0;
	uint16_t count;
	uint8_t b;

	/*
	 * If we already started a packet, find the
	 * trailing end of it.
	 */
	if (m) {
		while (m->m_next)
			m = m->m_next;

		space = M_TRAILINGSPACE(m);
	}

	count = bt3c_read(sc, BT3C_RX_COUNT);
	bt3c_set_address(sc, BT3C_RX_FIFO);

	while (count > 0) {
		if (space == 0) {
			if (m == NULL) {
				/* new packet */
				MGETHDR(m, M_DONTWAIT, MT_DATA);
				if (m == NULL) {
					aprint_error_dev(sc->sc_dev,
					    "out of memory\n");
					sc->sc_stats.err_rx++;
					goto out;	/* (lost sync) */
				}

				sc->sc_rxp = m;
				m->m_pkthdr.len = m->m_len = 0;
				space = MHLEN;

				sc->sc_state = BT3C_RECV_PKT_TYPE;
				sc->sc_want = 1;
			} else {
				/* extend mbuf */
				MGET(m->m_next, M_DONTWAIT, MT_DATA);
				if (m->m_next == NULL) {
					aprint_error_dev(sc->sc_dev,
					    "out of memory\n");
					sc->sc_stats.err_rx++;
					goto out;	/* (lost sync) */
				}

				m = m->m_next;
				m->m_len = 0;
				space = MLEN;

				if (sc->sc_want > MINCLSIZE) {
					MCLGET(m, M_DONTWAIT);
					if (m->m_flags & M_EXT)
						space = MCLBYTES;
				}
			}
		}

		b = bt3c_get(sc);
		mtod(m, uint8_t *)[m->m_len++] = b;
		count--;
		space--;
		sc->sc_rxp->m_pkthdr.len++;
		sc->sc_stats.byte_rx++;

		sc->sc_want--;
		if (sc->sc_want > 0)
			continue; /* want more */

		switch (sc->sc_state) {
		case BT3C_RECV_PKT_TYPE:		/* Got packet type */

			switch (b) {
			case HCI_ACL_DATA_PKT:
				sc->sc_state = BT3C_RECV_ACL_HDR;
				sc->sc_want = sizeof(hci_acldata_hdr_t) - 1;
				break;

			case HCI_SCO_DATA_PKT:
				sc->sc_state = BT3C_RECV_SCO_HDR;
				sc->sc_want = sizeof(hci_scodata_hdr_t) - 1;
				break;

			case HCI_EVENT_PKT:
				sc->sc_state = BT3C_RECV_EVENT_HDR;
				sc->sc_want = sizeof(hci_event_hdr_t) - 1;
				break;

			default:
				aprint_error_dev(sc->sc_dev,
				    "Unknown packet type=%#x!\n", b);
				sc->sc_stats.err_rx++;
				m_freem(sc->sc_rxp);
				sc->sc_rxp = NULL;
				goto out;	/* (lost sync) */
			}

			break;

		/*
		 * we assume (correctly of course :) that the packet headers
		 * all fit into a single pkthdr mbuf
		 */
		case BT3C_RECV_ACL_HDR:		/* Got ACL Header */
			sc->sc_state = BT3C_RECV_ACL_DATA;
			sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length;
			sc->sc_want = le16toh(sc->sc_want);
			break;

		case BT3C_RECV_SCO_HDR:		/* Got SCO Header */
			sc->sc_state = BT3C_RECV_SCO_DATA;
			sc->sc_want =  mtod(m, hci_scodata_hdr_t *)->length;
			break;

		case BT3C_RECV_EVENT_HDR:	/* Got Event Header */
			sc->sc_state = BT3C_RECV_EVENT_DATA;
			sc->sc_want =  mtod(m, hci_event_hdr_t *)->length;
			break;

		case BT3C_RECV_ACL_DATA:	/* ACL Packet Complete */
			if (!hci_input_acl(sc->sc_unit, sc->sc_rxp))
				sc->sc_stats.err_rx++;

			sc->sc_stats.acl_rx++;
			sc->sc_rxp = m = NULL;
			space = 0;
			break;

		case BT3C_RECV_SCO_DATA:	/* SCO Packet Complete */
			if (!hci_input_sco(sc->sc_unit, sc->sc_rxp))
				sc->sc_stats.err_rx++;

			sc->sc_stats.sco_rx++;
			sc->sc_rxp = m = NULL;
			space = 0;
			break;

		case BT3C_RECV_EVENT_DATA:	/* Event Packet Complete */
			if (!hci_input_event(sc->sc_unit, sc->sc_rxp))
				sc->sc_stats.err_rx++;

			sc->sc_stats.evt_rx++;
			sc->sc_rxp = m = NULL;
			space = 0;
			break;

		default:
			panic("%s: invalid state %d!\n",
				device_xname(sc->sc_dev), sc->sc_state);
		}
	}

out:
	bt3c_write(sc, BT3C_RX_COUNT, 0x0000);
}