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); }
/* * 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); }