diff options
author | emax <emax@FreeBSD.org> | 2008-07-11 17:13:43 +0000 |
---|---|---|
committer | emax <emax@FreeBSD.org> | 2008-07-11 17:13:43 +0000 |
commit | 797b3cb5549559076402e7ae296f5435b49123ef (patch) | |
tree | 119eb40ae44167fe8e7426b3cc617e1eaeae8e87 /sys/netgraph | |
parent | 5cc7bcb02c3a0bdaaf70bd7d4dd91b75da86a2b7 (diff) | |
download | FreeBSD-src-797b3cb5549559076402e7ae296f5435b49123ef.zip FreeBSD-src-797b3cb5549559076402e7ae296f5435b49123ef.tar.gz |
Dust off old code for support of USB isochronous transfers.
USB isochronous transfer support is required for Bluetooth SCO.
While i'm here change u_int to uint and update TODO.
This should produce no visible changes unless the device is
broken (or really old).
MFC after: 3 months
Diffstat (limited to 'sys/netgraph')
-rw-r--r-- | sys/netgraph/bluetooth/drivers/ubt/TODO | 6 | ||||
-rw-r--r-- | sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c | 517 | ||||
-rw-r--r-- | sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h | 33 |
3 files changed, 341 insertions, 215 deletions
diff --git a/sys/netgraph/bluetooth/drivers/ubt/TODO b/sys/netgraph/bluetooth/drivers/ubt/TODO index 90f9d1d..7f840c9 100644 --- a/sys/netgraph/bluetooth/drivers/ubt/TODO +++ b/sys/netgraph/bluetooth/drivers/ubt/TODO @@ -6,6 +6,8 @@ $FreeBSD$ The code makes use of ng_send_fn() whenever possible. Just need to verify and make sure i did it right + ** DONE. Seems to work ** + 2) Review USB ATTACH function It is a bit ugly now. Probably need a better way to discover @@ -25,6 +27,10 @@ $FreeBSD$ both directions and switch them on the fly. Just to ensure there at least one transfer at any time ready to run. + ** DONE. Needs more testings ** + 4) Currently interrupt transfers are done as bulk-in transfers Need to check if that is allowed. + + ** DONE. Seems to work ** diff --git a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c index c2dec1a..082eef0 100644 --- a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c +++ b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c @@ -27,7 +27,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ng_ubt.c,v 1.16 2003/10/10 19:15:06 max Exp $ + * $Id: ng_ubt.c,v 1.22 2005/10/31 17:57:44 max Exp $ * $FreeBSD$ */ @@ -108,11 +108,13 @@ static void ubt_bulk_out_complete (usbd_xfer_handle, usbd_private_handle, usbd_status); static void ubt_bulk_out_complete2 (node_p, hook_p, void *, int); +static usbd_status ubt_isoc_in_start_one (ubt_softc_p, int); static usbd_status ubt_isoc_in_start (ubt_softc_p); static void ubt_isoc_in_complete (usbd_xfer_handle, usbd_private_handle, usbd_status); static void ubt_isoc_in_complete2 (node_p, hook_p, void *, int); +static usbd_status ubt_isoc_out_start_one (ubt_softc_p, int); static usbd_status ubt_isoc_out_start (ubt_softc_p); static void ubt_isoc_out_complete (usbd_xfer_handle, usbd_private_handle, usbd_status); @@ -381,14 +383,16 @@ ubt_attach(device_t self) NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN); /* Isoc-in pipe */ + sc->sc_isoc_in_buffer = NULL; sc->sc_isoc_in_ep = -1; sc->sc_isoc_in_pipe = NULL; - sc->sc_isoc_in_xfer = NULL; + bzero(&sc->sc_isoc_in, sizeof(sc->sc_isoc_in)); /* Isoc-out pipe */ sc->sc_isoc_out_ep = -1; sc->sc_isoc_out_pipe = NULL; - sc->sc_isoc_out_xfer = NULL; + bzero(&sc->sc_isoc_out, sizeof(sc->sc_isoc_out)); + sc->sc_isoc_size = -1; NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN); @@ -588,7 +592,8 @@ ubt_attach(device_t self) error = usbd_set_interface(sc->sc_iface1, alt_no); if (error) { printf("%s: Could not set alternate configuration " \ - "%d for interface 1. %s (%d)\n", device_get_nameunit(sc->sc_dev), + "%d for interface 1. %s (%d)\n", + device_get_nameunit(sc->sc_dev), alt_no, usbd_errstr(error), error); goto bad; } @@ -640,55 +645,65 @@ ubt_attach(device_t self) * Allocate buffers for isoc. transfers */ - sc->sc_isoc_nframes = (UBT_ISOC_BUFFER_SIZE / sc->sc_isoc_size) + 1; + for (i = 0; i < NG_UBT_NXFERS; i++) { + sc->sc_isoc_in[i].xfer = usbd_alloc_xfer(sc->sc_udev); + if (sc->sc_isoc_in[i].xfer == NULL) { + printf("%s: Could not allocate isoc-in xfer handle\n", + device_get_nameunit(sc->sc_dev)); + goto bad; + } - sc->sc_isoc_in_xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_isoc_in_xfer == NULL) { - printf("%s: Could not allocate isoc-in xfer handle\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - sc->sc_isoc_in_buffer = usbd_alloc_buffer(sc->sc_isoc_in_xfer, - sc->sc_isoc_nframes * sc->sc_isoc_size); - if (sc->sc_isoc_in_buffer == NULL) { - printf("%s: Could not allocate isoc-in buffer\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - sc->sc_isoc_in_frlen = malloc(sizeof(u_int16_t) * sc->sc_isoc_nframes, - M_USBDEV, M_NOWAIT); - if (sc->sc_isoc_in_frlen == NULL) { - printf("%s: Could not allocate isoc-in frame sizes buffer\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } + sc->sc_isoc_in[i].buffer = usbd_alloc_buffer( + sc->sc_isoc_in[i].xfer, + NG_UBT_NFRAMES * sc->sc_isoc_size); + if (sc->sc_isoc_in[i].buffer == NULL) { + printf("%s: Could not allocate isoc-in buffer\n", + device_get_nameunit(sc->sc_dev)); + goto bad; + } - sc->sc_isoc_out_xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_isoc_out_xfer == NULL) { - printf("%s: Could not allocate isoc-out xfer handle\n", - device_get_nameunit(sc->sc_dev)); - goto bad; - } - sc->sc_isoc_out_buffer = usbd_alloc_buffer(sc->sc_isoc_out_xfer, - sc->sc_isoc_nframes * sc->sc_isoc_size); - if (sc->sc_isoc_out_buffer == NULL) { - printf("%s: Could not allocate isoc-out buffer\n", - device_get_nameunit(sc->sc_dev)); - goto bad; + sc->sc_isoc_in[i].frlen = malloc( + sizeof(uint16_t) * NG_UBT_NFRAMES, + M_USBDEV, M_NOWAIT); + if (sc->sc_isoc_in[i].frlen == NULL) { + printf("%s: Could not allocate isoc-in frame sizes buffer\n", + device_get_nameunit(sc->sc_dev)); + goto bad; + } } - sc->sc_isoc_out_frlen = malloc(sizeof(u_int16_t) * sc->sc_isoc_nframes, - M_USBDEV, M_NOWAIT); - if (sc->sc_isoc_out_frlen == NULL) { - printf("%s: Could not allocate isoc-out frame sizes buffer\n", - device_get_nameunit(sc->sc_dev)); - goto bad; + + for (i = 0; i < NG_UBT_NXFERS; i++) { + sc->sc_isoc_out[i].xfer = usbd_alloc_xfer(sc->sc_udev); + if (sc->sc_isoc_out[i].xfer == NULL) { + printf("%s: Could not allocate isoc-out xfer handle\n", + device_get_nameunit(sc->sc_dev)); + goto bad; + } + + sc->sc_isoc_out[i].buffer = usbd_alloc_buffer( + sc->sc_isoc_out[i].xfer, + NG_UBT_NFRAMES * sc->sc_isoc_size); + if (sc->sc_isoc_out[i].buffer == NULL) { + printf("%s: Could not allocate isoc-out buffer\n", + device_get_nameunit(sc->sc_dev)); + goto bad; + } + + sc->sc_isoc_out[i].frlen = malloc( + sizeof(uint16_t) * NG_UBT_NFRAMES, + M_USBDEV, M_NOWAIT); + if (sc->sc_isoc_out[i].frlen == NULL) { + printf("%s: Could not allocate isoc-out frame sizes buffer\n", + device_get_nameunit(sc->sc_dev)); + goto bad; + } } printf("%s: Interface 1 (alt.config %d) endpoints: isoc-in=%#x, " \ "isoc-out=%#x; wMaxPacketSize=%d; nframes=%d, buffer size=%d\n", device_get_nameunit(sc->sc_dev), alt_no, sc->sc_isoc_in_ep, - sc->sc_isoc_out_ep, sc->sc_isoc_size, sc->sc_isoc_nframes, - (sc->sc_isoc_nframes * sc->sc_isoc_size)); + sc->sc_isoc_out_ep, sc->sc_isoc_size, NG_UBT_NFRAMES, + (NG_UBT_NFRAMES * sc->sc_isoc_size)); /* * Open pipes @@ -724,7 +739,6 @@ ubt_attach(device_t self) goto bad; } -#if 0 /* XXX FIXME */ /* Isoc-in */ error = usbd_open_pipe(sc->sc_iface1, sc->sc_isoc_in_ep, USBD_EXCLUSIVE_USE, &sc->sc_isoc_in_pipe); @@ -744,7 +758,6 @@ ubt_attach(device_t self) error); goto bad; } -#endif /* Create Netgraph node */ if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) { @@ -788,6 +801,7 @@ static int ubt_detach(device_t self) { struct ubt_softc *sc = device_get_softc(self); + int i; /* Destroy Netgraph node */ if (sc->sc_node != NULL) { @@ -840,32 +854,41 @@ ubt_detach(device_t self) sc->sc_bulk_out_xfer = NULL; } - if (sc->sc_isoc_in_xfer != NULL) { - usbd_free_xfer(sc->sc_isoc_in_xfer); - sc->sc_isoc_in_xfer = NULL; - } - if (sc->sc_isoc_out_xfer != NULL) { - usbd_free_xfer(sc->sc_isoc_out_xfer); - sc->sc_isoc_out_xfer = NULL; - } + for (i = 0; i < NG_UBT_NXFERS; i++) { + if (sc->sc_isoc_in[i].xfer != NULL) { + usbd_free_xfer(sc->sc_isoc_in[i].xfer); + sc->sc_isoc_in[i].xfer = NULL; + sc->sc_isoc_in[i].buffer = NULL; + } - /* Destroy isoc. frame size buffers */ - if (sc->sc_isoc_in_frlen != NULL) { - free(sc->sc_isoc_in_frlen, M_USBDEV); - sc->sc_isoc_in_frlen = NULL; + if (sc->sc_isoc_in[i].frlen != NULL) { + free(sc->sc_isoc_in[i].frlen, M_USBDEV); + sc->sc_isoc_in[i].frlen = NULL; + } } - if (sc->sc_isoc_out_frlen != NULL) { - free(sc->sc_isoc_out_frlen, M_USBDEV); - sc->sc_isoc_out_frlen = NULL; + + for (i = 0; i < NG_UBT_NXFERS; i++) { + if (sc->sc_isoc_out[i].xfer != NULL) { + usbd_free_xfer(sc->sc_isoc_out[i].xfer); + sc->sc_isoc_out[i].xfer = NULL; + sc->sc_isoc_out[i].buffer = NULL; + } + + if (sc->sc_isoc_out[i].frlen != NULL) { + free(sc->sc_isoc_out[i].frlen, M_USBDEV); + sc->sc_isoc_out[i].frlen = NULL; + } } + NG_FREE_M(sc->sc_bulk_in_buffer); + NG_FREE_M(sc->sc_isoc_in_buffer); + /* Destroy queues */ NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq); NG_BT_MBUFQ_DRAIN(&sc->sc_aclq); NG_BT_MBUFQ_DRAIN(&sc->sc_scoq); - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, - sc->sc_dev); + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); return (0); } /* ubt_detach */ @@ -1037,7 +1060,7 @@ ubt_intr_start(ubt_softc_p sc) } if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) { - *mtod(m, u_int8_t *) = NG_HCI_EVENT_PKT; + *mtod(m, uint8_t *) = NG_HCI_EVENT_PKT; m->m_pkthdr.len = m->m_len = 1; } else m->m_pkthdr.len = m->m_len = 0; @@ -1047,7 +1070,7 @@ ubt_intr_start(ubt_softc_p sc) sc->sc_intr_xfer, sc->sc_intr_pipe, (usbd_private_handle) sc->sc_node, - (void *)(mtod(m, u_int8_t *) + m->m_len), + (void *)(mtod(m, uint8_t *) + m->m_len), MCLBYTES - m->m_len, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, @@ -1203,7 +1226,7 @@ ubt_bulk_in_start(ubt_softc_p sc) } if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) { - *mtod(m, u_int8_t *) = NG_HCI_ACL_DATA_PKT; + *mtod(m, uint8_t *) = NG_HCI_ACL_DATA_PKT; m->m_pkthdr.len = m->m_len = 1; } else m->m_pkthdr.len = m->m_len = 0; @@ -1213,7 +1236,7 @@ ubt_bulk_in_start(ubt_softc_p sc) sc->sc_bulk_in_xfer, sc->sc_bulk_in_pipe, (usbd_private_handle) sc->sc_node, - (void *)(mtod(m, u_int8_t *) + m->m_len), + (void *)(mtod(m, uint8_t *) + m->m_len), MCLBYTES - m->m_len, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, @@ -1475,35 +1498,31 @@ ubt_bulk_out_complete2(node_p node, hook_p hook, void *arg1, int arg2) } /* ubt_bulk_out_complete2 */ /* - * Start Isochronous-in USB transfer. Must be called with node locked + * Start non-active Isochronous-in USB transfer. + * Must be called with node locked */ static usbd_status -ubt_isoc_in_start(ubt_softc_p sc) +ubt_isoc_in_start_one(ubt_softc_p sc, int idx) { usbd_status status; int i; - KASSERT(!(sc->sc_flags & UBT_SCO_RECV), ( -"%s: %s - Another isoc-in request is pending\n", - __func__, device_get_nameunit(sc->sc_dev))); - - /* Initialize a isoc-in USB transfer and then schedule it */ - for (i = 0; i < sc->sc_isoc_nframes; i++) - sc->sc_isoc_in_frlen[i] = sc->sc_isoc_size; + for (i = 0; i < NG_UBT_NFRAMES; i++) + sc->sc_isoc_in[idx].frlen[i] = sc->sc_isoc_size; usbd_setup_isoc_xfer( - sc->sc_isoc_in_xfer, - sc->sc_isoc_in_pipe, - (usbd_private_handle) sc->sc_node, - sc->sc_isoc_in_frlen, - sc->sc_isoc_nframes, - USBD_NO_COPY, /* XXX flags */ - ubt_isoc_in_complete); + sc->sc_isoc_in[idx].xfer, + sc->sc_isoc_in_pipe, + (usbd_private_handle) sc->sc_node, + sc->sc_isoc_in[idx].frlen, + NG_UBT_NFRAMES, + USBD_NO_COPY | USBD_SHORT_XFER_OK, + ubt_isoc_in_complete); NG_NODE_REF(sc->sc_node); - status = usbd_transfer(sc->sc_isoc_in_xfer); + status = usbd_transfer(sc->sc_isoc_in[idx].xfer); if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { NG_UBT_ERR( "%s: %s - Failed to start isoc-in transfer. %s (%d)\n", @@ -1511,11 +1530,25 @@ ubt_isoc_in_start(ubt_softc_p sc) usbd_errstr(status), status); NG_NODE_UNREF(sc->sc_node); + } else + sc->sc_isoc_in[idx].active = 1; - return (status); - } + return (status); +} - sc->sc_flags |= UBT_SCO_RECV; +/* + * (Re)Start all non-active Isochronous-in USB transfers. + * Must be called with node locked. + */ + +static usbd_status +ubt_isoc_in_start(ubt_softc_p sc) +{ + int i; + + for (i = 0; i < NG_UBT_NXFERS; i++) + if (!sc->sc_isoc_in[i].active) + ubt_isoc_in_start_one(sc, i); return (USBD_NORMAL_COMPLETION); } /* ubt_isoc_in_start */ @@ -1537,18 +1570,28 @@ ubt_isoc_in_complete2(node_p node, hook_p hook, void *arg1, int arg2) ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); usbd_xfer_handle h = (usbd_xfer_handle) arg1; usbd_status s = (usbd_status) arg2; - struct mbuf *m = NULL; - ng_hci_scodata_pkt_t *hdr = NULL; - u_int8_t *b = NULL; - int i; + int i, idx, want, got, got_header; + struct mbuf *m; if (sc == NULL) return; - KASSERT((sc->sc_flags & UBT_SCO_RECV), ( -"%s: %s - No isoc-in request is pending\n", __func__, device_get_nameunit(sc->sc_dev))); + /* Find xfer */ + idx = -1; + for (i = 0; i < NG_UBT_NXFERS; i++) { + if (sc->sc_isoc_in[i].xfer == h) { + idx = i; + break; + } + } + KASSERT(idx != -1, ( +"%s:%s - Could not find isoc-in request\n", + __func__, device_get_nameunit(sc->sc_dev))); + KASSERT(sc->sc_isoc_in[idx].active, ( +"%s: %s - Isoc-in request is not active\n", + __func__, device_get_nameunit(sc->sc_dev))); - sc->sc_flags &= ~UBT_SCO_RECV; + sc->sc_isoc_in[idx].active = 0; if (sc->sc_hook == NULL || NG_HOOK_NOT_VALID(sc->sc_hook)) { NG_UBT_INFO( @@ -1557,6 +1600,7 @@ ubt_isoc_in_complete2(node_p node, hook_p hook, void *arg1, int arg2) return; } + /* Process xfer */ if (s == USBD_CANCELLED) { NG_UBT_INFO( "%s: %s - Isoc-in xfer cancelled, pipe=%p\n", @@ -1578,160 +1622,221 @@ ubt_isoc_in_complete2(node_p node, hook_p hook, void *arg1, int arg2) return; /* XXX FIXME we should restart after some delay */ } - NG_UBT_STAT_BYTES_RECV(sc->sc_stat, h->actlen); + if (h->actlen <= 0) + goto done; NG_UBT_INFO( "%s: %s - Got %d bytes from isoc-in pipe\n", __func__, device_get_nameunit(sc->sc_dev), h->actlen); - /* Copy SCO data frame to mbuf */ - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) { - NG_UBT_ALERT( -"%s: %s - Could not allocate mbuf\n", - __func__, device_get_nameunit(sc->sc_dev)); + /* + * Re-assemble SCO HCI frame + */ - NG_UBT_STAT_IERROR(sc->sc_stat); - goto done; - } + got_header = 0; /* shut up compiler */ + got = 0; + want = 0; - /* Fix SCO data frame header if required */ - if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) { - *mtod(m, u_int8_t *) = NG_HCI_SCO_DATA_PKT; - m->m_pkthdr.len = 1; - m->m_len = min(MHLEN, h->actlen + 1); /* XXX m_copyback */ - } else { - m->m_pkthdr.len = 0; - m->m_len = min(MHLEN, h->actlen); /* XXX m_copyback */ + m = sc->sc_isoc_in_buffer; + if (m != NULL) { + sc->sc_isoc_in_buffer = NULL; + + got = m->m_pkthdr.len; + + if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) + want = sizeof(ng_hci_scodata_pkt_t) - 1; + else + want = sizeof(ng_hci_scodata_pkt_t); + + if (got >= sizeof(ng_hci_scodata_pkt_t)) { + got_header = 1; + want += mtod(m, ng_hci_scodata_pkt_t *)->length; + } } - /* - * XXX FIXME how do we know how many frames we have received? - * XXX use frlen for now. is that correct? - */ + for (i = 0; i < NG_UBT_NFRAMES; i ++) { + uint8_t *frame = (uint8_t *) sc->sc_isoc_in[idx].buffer + + (i * sc->sc_isoc_size); - b = (u_int8_t *) sc->sc_isoc_in_buffer; + while (sc->sc_isoc_in[idx].frlen[i] > 0) { + int error, frlen = sc->sc_isoc_in[idx].frlen[i]; - for (i = 0; i < sc->sc_isoc_nframes; i++) { - b += (i * sc->sc_isoc_size); + if (m == NULL) { + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + goto done; /* XXX out of sync! */ - if (sc->sc_isoc_in_frlen[i] > 0) - m_copyback(m, m->m_pkthdr.len, - sc->sc_isoc_in_frlen[i], b); - } + got = 0; + got_header = 0; - if (m->m_pkthdr.len < sizeof(*hdr)) - goto done; + if (!(sc->sc_flags & UBT_HAVE_FRAME_TYPE)) { + *mtod(m, uint8_t *) = NG_HCI_SCO_DATA_PKT; + m->m_pkthdr.len = m->m_len = got = 1; + want = sizeof(ng_hci_scodata_pkt_t) - 1; + } else { + m->m_pkthdr.len = m->m_len = got = 0; + want = sizeof(ng_hci_scodata_pkt_t); + } + } - hdr = mtod(m, ng_hci_scodata_pkt_t *); + if (got + frlen > want) + frlen = want - got; - if (hdr->length == m->m_pkthdr.len - sizeof(*hdr)) { - NG_UBT_INFO( -"%s: %s - Got complete SCO data frame, pktlen=%d, length=%d\n", - __func__, device_get_nameunit(sc->sc_dev), m->m_pkthdr.len, - hdr->length); + if (!m_append(m, frlen, frame)) { + NG_FREE_M(m); + goto done; /* XXX out of sync! */ + } - NG_UBT_STAT_PCKTS_RECV(sc->sc_stat); + got += frlen; + frame += frlen; + sc->sc_isoc_in[idx].frlen[i] -= frlen; - NG_SEND_DATA_ONLY(i, sc->sc_hook, m); - if (i != 0) - NG_UBT_STAT_IERROR(sc->sc_stat); - } else { - NG_UBT_ERR( -"%s: %s - Invalid SCO frame size, length=%d, pktlen=%d\n", - __func__, device_get_nameunit(sc->sc_dev), hdr->length, - m->m_pkthdr.len); + if (got != want) + continue; - NG_UBT_STAT_IERROR(sc->sc_stat); - NG_FREE_M(m); + if (!got_header) { + got_header = 1; + want += mtod(m, ng_hci_scodata_pkt_t *)->length; + } + + if (got != want) + continue; + + NG_UBT_INFO( +"%s: %s - Got complete SCO data frame, pktlen=%d, length=%d\n", + __func__, device_get_nameunit(sc->sc_dev), + m->m_pkthdr.len, + mtod(m, ng_hci_scodata_pkt_t *)->length); + + NG_UBT_STAT_PCKTS_RECV(sc->sc_stat); + NG_UBT_STAT_BYTES_RECV(sc->sc_stat, m->m_pkthdr.len); + + NG_SEND_DATA_ONLY(error, sc->sc_hook, m); + if (error != 0) + NG_UBT_STAT_IERROR(sc->sc_stat); + } } + + sc->sc_isoc_in_buffer = m; done: - ubt_isoc_in_start(sc); + ubt_isoc_in_start_one(sc, idx); } /* ubt_isoc_in_complete2 */ /* - * Start isochronous-out USB transfer. Must be called with node locked + * Start non-active isochronous-out USB transfer. + * Must be called with node locked */ static usbd_status -ubt_isoc_out_start(ubt_softc_p sc) +ubt_isoc_out_start_one(ubt_softc_p sc, int idx) { - struct mbuf *m = NULL; - u_int8_t *b = NULL; - int i, len, nframes; + int len, maxlen, size, nframes; + struct mbuf *m; + uint8_t *buffer; usbd_status status; - KASSERT(!(sc->sc_flags & UBT_SCO_XMIT), ( -"%s: %s - Another isoc-out request is pending\n", - __func__, device_get_nameunit(sc->sc_dev))); + /* + * Fill the transfer buffer with data from the queue, + * putting any leftover back on the queue + */ - NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m); - if (m == NULL) { - NG_UBT_INFO( -"%s: %s - SCO data queue is empty\n", __func__, device_get_nameunit(sc->sc_dev)); + len = 0; + maxlen = NG_UBT_NFRAMES * sc->sc_isoc_size; + m = NULL; + buffer = sc->sc_isoc_out[idx].buffer; - return (USBD_NORMAL_COMPLETION); - } + while (maxlen > 0) { + if (m == NULL) { + NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m); + if (m == NULL) + break; + } - /* Copy entire SCO frame into USB transfer buffer and start transfer */ - b = (u_int8_t *) sc->sc_isoc_out_buffer; - nframes = 0; + if (m->m_pkthdr.len > 0) { + size = MIN(m->m_pkthdr.len, maxlen); - for (i = 0; i < sc->sc_isoc_nframes; i++) { - b += (i * sc->sc_isoc_size); + m_copydata(m, 0, size, buffer); + m_adj(m, size); - len = min(m->m_pkthdr.len, sc->sc_isoc_size); - if (len > 0) { - m_copydata(m, 0, len, b); - m_adj(m, len); - nframes ++; + buffer += size; + len += size; + maxlen -= size; } - sc->sc_isoc_out_frlen[i] = len; + if (m->m_pkthdr.len == 0) { + NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); + NG_FREE_M(m); + } } - if (m->m_pkthdr.len > 0) - panic( -"%s: %s - SCO data frame is too big, nframes=%d, size=%d, len=%d\n", - __func__, device_get_nameunit(sc->sc_dev), sc->sc_isoc_nframes, - sc->sc_isoc_size, m->m_pkthdr.len); + if (m != NULL) + NG_BT_MBUFQ_PREPEND(&sc->sc_scoq, m); - NG_FREE_M(m); + if (len == 0) + return (USBD_NORMAL_COMPLETION); /* nothing to send */ + + NG_UBT_STAT_BYTES_SENT(sc->sc_stat, len); + + /* Calculate number of isoc frames and sizes */ + for (nframes = 0; len > 0; nframes ++) { + size = MIN(sc->sc_isoc_size, len); + sc->sc_isoc_out[idx].frlen[nframes] = size; + len -= size; + } /* Initialize a isoc-out USB transfer and then schedule it */ usbd_setup_isoc_xfer( - sc->sc_isoc_out_xfer, - sc->sc_isoc_out_pipe, - (usbd_private_handle) sc->sc_node, - sc->sc_isoc_out_frlen, - nframes, - USBD_NO_COPY, - ubt_isoc_out_complete); + sc->sc_isoc_out[idx].xfer, + sc->sc_isoc_out_pipe, + (usbd_private_handle) sc->sc_node, + sc->sc_isoc_out[idx].frlen, + nframes, + USBD_NO_COPY | USBD_FORCE_SHORT_XFER, + ubt_isoc_out_complete); NG_NODE_REF(sc->sc_node); + sc->sc_isoc_out[idx].active = 1; - status = usbd_transfer(sc->sc_isoc_out_xfer); + status = usbd_transfer(sc->sc_isoc_out[idx].xfer); if (status != USBD_NORMAL_COMPLETION && status != USBD_IN_PROGRESS) { NG_UBT_ERR( "%s: %s - Could not start isoc-out transfer. %s (%d)\n", - __func__, device_get_nameunit(sc->sc_dev), usbd_errstr(status), - status); + __func__, device_get_nameunit(sc->sc_dev), + usbd_errstr(status), status); + sc->sc_isoc_out[idx].active = 0; NG_NODE_UNREF(sc->sc_node); - NG_BT_MBUFQ_DROP(&sc->sc_scoq); NG_UBT_STAT_OERROR(sc->sc_stat); } else { NG_UBT_INFO( "%s: %s - Isoc-out transfer has been started, nframes=%d, size=%d\n", __func__, device_get_nameunit(sc->sc_dev), nframes, sc->sc_isoc_size); - - sc->sc_flags |= UBT_SCO_XMIT; status = USBD_NORMAL_COMPLETION; } return (status); +} + +/* + * Start all non-active isochronous-out USB transfer. + * Must be called with node locked + */ + +static usbd_status +ubt_isoc_out_start(ubt_softc_p sc) +{ + int i; + + for (i = 0; i < NG_UBT_NXFERS; i++) { + if (sc->sc_isoc_out[i].active) + continue; + + ubt_isoc_out_start_one(sc, i); + } + + return (USBD_NORMAL_COMPLETION); } /* ubt_isoc_out_start */ /* @@ -1751,15 +1856,29 @@ ubt_isoc_out_complete2(node_p node, hook_p hook, void *arg1, int arg2) ubt_softc_p sc = (ubt_softc_p) NG_NODE_PRIVATE(node); usbd_xfer_handle h = (usbd_xfer_handle) arg1; usbd_status s = (usbd_status) arg2; + int i, idx; if (sc == NULL) return; - KASSERT((sc->sc_flags & UBT_SCO_XMIT), ( -"%s: %s - No isoc-out request is pending\n", __func__, device_get_nameunit(sc->sc_dev))); + /* Find xfer */ + idx = -1; + for (i = 0; i < NG_UBT_NXFERS; i++) { + if (sc->sc_isoc_out[i].xfer == h) { + idx = i; + break; + } + } + KASSERT(idx != -1, ( +"%s:%s - Could not find isoc-out request\n", + __func__, device_get_nameunit(sc->sc_dev))); + KASSERT(sc->sc_isoc_out[idx].active, ( +"%s: %s - Isoc-out request is not active\n", + __func__, device_get_nameunit(sc->sc_dev))); - sc->sc_flags &= ~UBT_SCO_XMIT; + sc->sc_isoc_out[idx].active = 0; + /* Process xfer */ if (s == USBD_CANCELLED) { NG_UBT_INFO( "%s: %s - Isoc-out xfer cancelled, pipe=%p\n", @@ -1783,8 +1902,8 @@ ubt_isoc_out_complete2(node_p node, hook_p hook, void *arg1, int arg2) "%s: %s - Sent %d bytes to isoc-out pipe\n", __func__, device_get_nameunit(sc->sc_dev), h->actlen); - NG_UBT_STAT_BYTES_SENT(sc->sc_stat, h->actlen); - NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); +/* XXX FIXME NG_UBT_STAT_BYTES_SENT(sc->sc_stat, h->actlen); + NG_UBT_STAT_PCKTS_SENT(sc->sc_stat); */ } if (NG_BT_MBUFQ_LEN(&sc->sc_scoq) > 0) @@ -1927,7 +2046,6 @@ ng_ubt_connect(hook_p hook) goto fail; } -#if 0 /* XXX FIXME */ /* Start isoc-in transfer */ status = ubt_isoc_in_start(sc); if (status != USBD_NORMAL_COMPLETION) { @@ -1937,7 +2055,6 @@ ng_ubt_connect(hook_p hook) status); goto fail; } -#endif return (0); fail: @@ -2175,7 +2292,7 @@ ng_ubt_rcvdata(hook_p hook, item_p item) NGI_GET_M(item, m); /* Process HCI frame */ - switch (*mtod(m, u_int8_t *)) { /* XXX call m_pullup ? */ + switch (*mtod(m, uint8_t *)) { /* XXX call m_pullup ? */ case NG_HCI_CMD_PKT: f = ubt_request_start; q = &sc->sc_cmdq; @@ -2188,18 +2305,16 @@ ng_ubt_rcvdata(hook_p hook, item_p item) b = UBT_ACL_XMIT; break; -#if 0 /* XXX FIXME */ case NG_HCI_SCO_DATA_PKT: f = ubt_isoc_out_start; q = &sc->sc_scoq; b = UBT_SCO_XMIT; break; -#endif default: NG_UBT_ERR( "%s: %s - Dropping unknown/unsupported HCI frame, type=%d, pktlen=%d\n", - __func__, device_get_nameunit(sc->sc_dev), *mtod(m, u_int8_t *), + __func__, device_get_nameunit(sc->sc_dev), *mtod(m, uint8_t *), m->m_pkthdr.len); NG_FREE_M(m); @@ -2211,13 +2326,13 @@ ng_ubt_rcvdata(hook_p hook, item_p item) /* Loose frame type, if required */ if (!(sc->sc_flags & UBT_NEED_FRAME_TYPE)) - m_adj(m, sizeof(u_int8_t)); + m_adj(m, sizeof(uint8_t)); if (NG_BT_MBUFQ_FULL(q)) { NG_UBT_ERR( "%s: %s - Dropping HCI frame %#x, len=%d. Queue full\n", __func__, device_get_nameunit(sc->sc_dev), - *mtod(m, u_int8_t *), m->m_pkthdr.len); + *mtod(m, uint8_t *), m->m_pkthdr.len); NG_FREE_M(m); } else diff --git a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h index a7e8532..6fdce0e 100644 --- a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h +++ b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt_var.h @@ -27,7 +27,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ng_ubt_var.h,v 1.2 2003/03/22 23:44:36 max Exp $ + * $Id: ng_ubt_var.h,v 1.5 2005/10/31 17:57:44 max Exp $ * $FreeBSD$ */ @@ -54,11 +54,24 @@ #define UBT_HCI_REQUEST 0x20 #define UBT_DEFAULT_QLEN 12 +/* Isoc transfers */ +#define NG_UBT_NXFERS 3 /* max xfers to queue */ +#define NG_UBT_NFRAMES 10 /* frames per xfer */ + +struct ubt_isoc_xfer { + usbd_xfer_handle xfer; /* isoc xfer */ + void *buffer; /* isoc buffer */ + uint16_t *frlen; /* isoc frame length */ + int active; /* is xfer active */ +}; +typedef struct ubt_isoc_xfer ubt_isoc_xfer_t; +typedef struct ubt_isoc_xfer * ubt_isoc_xfer_p; + /* USB device softc structure */ struct ubt_softc { /* State */ ng_ubt_node_debug_ep sc_debug; /* debug level */ - u_int32_t sc_flags; /* device flags */ + uint32_t sc_flags; /* device flags */ #define UBT_NEED_FRAME_TYPE (1 << 0) /* device required frame type */ #define UBT_HAVE_FRAME_TYPE UBT_NEED_FRAME_TYPE #define UBT_CMD_XMIT (1 << 1) /* CMD xmit in progress */ @@ -67,10 +80,6 @@ struct ubt_softc { #define UBT_EVT_RECV (1 << 4) /* EVN recv in progress */ #define UBT_ACL_RECV (1 << 5) /* ACL recv in progress */ #define UBT_SCO_RECV (1 << 6) /* SCO recv in progress */ -#define UBT_CTRL_DEV (1 << 7) /* ctrl device is open */ -#define UBT_INTR_DEV (1 << 8) /* intr device is open */ -#define UBT_BULK_DEV (1 << 9) /* bulk device is open */ -#define UBT_ANY_DEV (UBT_CTRL_DEV|UBT_INTR_DEV|UBT_BULK_DEV) ng_ubt_node_stat_ep sc_stat; /* statistic */ #define NG_UBT_STAT_PCKTS_SENT(s) (s).pckts_sent ++ @@ -117,22 +126,18 @@ struct ubt_softc { MCLBYTES /* XXX should be big enough to hold one frame */ /* Isoc. in pipe (SCO data) */ + struct mbuf *sc_isoc_in_buffer; int sc_isoc_in_ep; /* isoc-in endpoint */ usbd_pipe_handle sc_isoc_in_pipe; /* isoc-in pipe */ - usbd_xfer_handle sc_isoc_in_xfer; /* isoc-in xfer */ - void *sc_isoc_in_buffer; /* isoc-in buffer */ - u_int16_t *sc_isoc_in_frlen; /* isoc-in. frame length */ + ubt_isoc_xfer_t sc_isoc_in[NG_UBT_NXFERS]; /* isoc-in xfers */ - /* Isoc. out pipe (ACL data) */ + /* Isoc. out pipe (SCO data) */ int sc_isoc_out_ep; /* isoc-out endpoint */ usbd_pipe_handle sc_isoc_out_pipe; /* isoc-out pipe */ - usbd_xfer_handle sc_isoc_out_xfer; /* isoc-out xfer */ - void *sc_isoc_out_buffer; /* isoc-in buffer */ - u_int16_t *sc_isoc_out_frlen; /* isoc-out. frame length */ + ubt_isoc_xfer_t sc_isoc_out[NG_UBT_NXFERS]; /* isoc-out xfers */ struct ng_bt_mbufq sc_scoq; /* SCO data queue */ int sc_isoc_size; /* max. size of isoc. packet */ - u_int32_t sc_isoc_nframes; /* num. isoc. frames */ #define UBT_ISOC_BUFFER_SIZE \ (sizeof(ng_hci_scodata_pkt_t) + NG_HCI_SCO_PKT_SIZE) |