| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ohci.c,v 1.254.2.41 2016/01/09 21:45:20 skrll Exp $ */ | | 1 | /* $NetBSD: ohci.c,v 1.254.2.42 2016/01/10 10:16:00 skrll Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | | 8 | * by Lennart Augustsson (lennart@augustsson.net) at |
9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) | | 9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) |
10 | * and Matthew R. Green (mrg@eterna.com.au). | | 10 | * and Matthew R. Green (mrg@eterna.com.au). |
11 | * This code is derived from software contributed to The NetBSD Foundation | | 11 | * This code is derived from software contributed to The NetBSD Foundation |
12 | * by Charles M. Hannum. | | 12 | * by Charles M. Hannum. |
13 | * | | 13 | * |
14 | * Redistribution and use in source and binary forms, with or without | | 14 | * Redistribution and use in source and binary forms, with or without |
| @@ -31,27 +31,27 @@ | | | @@ -31,27 +31,27 @@ |
31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
33 | * POSSIBILITY OF SUCH DAMAGE. | | 33 | * POSSIBILITY OF SUCH DAMAGE. |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | /* | | 36 | /* |
37 | * USB Open Host Controller driver. | | 37 | * USB Open Host Controller driver. |
38 | * | | 38 | * |
39 | * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html | | 39 | * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html |
40 | * USB spec: http://www.usb.org/developers/docs/ | | 40 | * USB spec: http://www.usb.org/developers/docs/ |
41 | */ | | 41 | */ |
42 | | | 42 | |
43 | #include <sys/cdefs.h> | | 43 | #include <sys/cdefs.h> |
44 | __KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.41 2016/01/09 21:45:20 skrll Exp $"); | | 44 | __KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.42 2016/01/10 10:16:00 skrll Exp $"); |
45 | | | 45 | |
46 | #include "opt_usb.h" | | 46 | #include "opt_usb.h" |
47 | | | 47 | |
48 | #include <sys/param.h> | | 48 | #include <sys/param.h> |
49 | | | 49 | |
50 | #include <sys/cpu.h> | | 50 | #include <sys/cpu.h> |
51 | #include <sys/device.h> | | 51 | #include <sys/device.h> |
52 | #include <sys/kernel.h> | | 52 | #include <sys/kernel.h> |
53 | #include <sys/kmem.h> | | 53 | #include <sys/kmem.h> |
54 | #include <sys/proc.h> | | 54 | #include <sys/proc.h> |
55 | #include <sys/queue.h> | | 55 | #include <sys/queue.h> |
56 | #include <sys/select.h> | | 56 | #include <sys/select.h> |
57 | #include <sys/sysctl.h> | | 57 | #include <sys/sysctl.h> |
| @@ -1517,31 +1517,31 @@ ohci_softintr(void *v) | | | @@ -1517,31 +1517,31 @@ ohci_softintr(void *v) |
1517 | } | | 1517 | } |
1518 | callout_stop(&xfer->ux_callout); | | 1518 | callout_stop(&xfer->ux_callout); |
1519 | | | 1519 | |
1520 | len = std->len; | | 1520 | len = std->len; |
1521 | if (std->td.td_cbp != 0) | | 1521 | if (std->td.td_cbp != 0) |
1522 | len -= O32TOH(std->td.td_be) - | | 1522 | len -= O32TOH(std->td.td_be) - |
1523 | O32TOH(std->td.td_cbp) + 1; | | 1523 | O32TOH(std->td.td_cbp) + 1; |
1524 | DPRINTFN(10, "len=%d, flags=0x%x", len, std->flags, 0, 0); | | 1524 | DPRINTFN(10, "len=%d, flags=0x%x", len, std->flags, 0, 0); |
1525 | if (std->flags & OHCI_ADD_LEN) | | 1525 | if (std->flags & OHCI_ADD_LEN) |
1526 | xfer->ux_actlen += len; | | 1526 | xfer->ux_actlen += len; |
1527 | | | 1527 | |
1528 | cc = OHCI_TD_GET_CC(O32TOH(std->td.td_flags)); | | 1528 | cc = OHCI_TD_GET_CC(O32TOH(std->td.td_flags)); |
1529 | if (cc == OHCI_CC_NO_ERROR) { | | 1529 | if (cc == OHCI_CC_NO_ERROR) { |
| | | 1530 | ohci_hash_rem_td(sc, std); |
1530 | if (std->flags & OHCI_CALL_DONE) { | | 1531 | if (std->flags & OHCI_CALL_DONE) { |
1531 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 1532 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
1532 | usb_transfer_complete(xfer); | | 1533 | usb_transfer_complete(xfer); |
1533 | } | | 1534 | } |
1534 | ohci_hash_rem_td(sc, std); | | | |
1535 | } else { | | 1535 | } else { |
1536 | /* | | 1536 | /* |
1537 | * Endpoint is halted. First unlink all the TDs | | 1537 | * Endpoint is halted. First unlink all the TDs |
1538 | * belonging to the failed transfer, and then restart | | 1538 | * belonging to the failed transfer, and then restart |
1539 | * the endpoint. | | 1539 | * the endpoint. |
1540 | */ | | 1540 | */ |
1541 | ohci_soft_td_t *p, *n; | | 1541 | ohci_soft_td_t *p, *n; |
1542 | opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 1542 | opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
1543 | | | 1543 | |
1544 | DPRINTFN(15, "error cc=%d", | | 1544 | DPRINTFN(15, "error cc=%d", |
1545 | OHCI_TD_GET_CC(O32TOH(std->td.td_flags)), 0, 0, 0); | | 1545 | OHCI_TD_GET_CC(O32TOH(std->td.td_flags)), 0, 0, 0); |
1546 | | | 1546 | |
1547 | /* remove xfer's TDs from the hash */ | | 1547 | /* remove xfer's TDs from the hash */ |
| @@ -1676,27 +1676,30 @@ ohci_device_intr_done(struct usbd_xfer * | | | @@ -1676,27 +1676,30 @@ ohci_device_intr_done(struct usbd_xfer * |
1676 | (UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN); | | 1676 | (UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN); |
1677 | | | 1677 | |
1678 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1678 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1679 | DPRINTFN(10, "xfer=%p, actlen=%d", xfer, xfer->ux_actlen, 0, 0); | | 1679 | DPRINTFN(10, "xfer=%p, actlen=%d", xfer, xfer->ux_actlen, 0, 0); |
1680 | | | 1680 | |
1681 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 1681 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
1682 | | | 1682 | |
1683 | usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length, | | 1683 | usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length, |
1684 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | | 1684 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
1685 | if (xfer->ux_pipe->up_repeat) { | | 1685 | if (xfer->ux_pipe->up_repeat) { |
1686 | ohci_soft_td_t *data, *last, *tail; | | 1686 | ohci_soft_td_t *data, *last, *tail; |
1687 | int len = xfer->ux_length; | | 1687 | int len = xfer->ux_length; |
1688 | | | 1688 | |
1689 | /* Use "tail" TD and loan our first TD to next transfer */ | | 1689 | /* |
| | | 1690 | * Use the pipe "tail" TD as our first and loan our first TD |
| | | 1691 | * to the next transfer. |
| | | 1692 | */ |
1690 | data = opipe->tail.td; | | 1693 | data = opipe->tail.td; |
1691 | opipe->tail.td = ox->ox_stds[0]; | | 1694 | opipe->tail.td = ox->ox_stds[0]; |
1692 | ox->ox_stds[0] = data; | | 1695 | ox->ox_stds[0] = data; |
1693 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); | | 1696 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); |
1694 | | | 1697 | |
1695 | tail = opipe->tail.td; /* point at sentinel */ | | 1698 | tail = opipe->tail.td; /* point at sentinel */ |
1696 | memset(&tail->td, 0, sizeof(tail->td)); | | 1699 | memset(&tail->td, 0, sizeof(tail->td)); |
1697 | tail->nexttd = NULL; | | 1700 | tail->nexttd = NULL; |
1698 | tail->xfer = NULL; | | 1701 | tail->xfer = NULL; |
1699 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), | | 1702 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), |
1700 | BUS_DMASYNC_PREWRITE); | | 1703 | BUS_DMASYNC_PREWRITE); |
1701 | | | 1704 | |
1702 | /* We want interrupt at the end of the transfer. */ | | 1705 | /* We want interrupt at the end of the transfer. */ |
| @@ -2718,78 +2721,76 @@ ohci_root_intr_close(struct usbd_pipe *p | | | @@ -2718,78 +2721,76 @@ ohci_root_intr_close(struct usbd_pipe *p |
2718 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2721 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2719 | | | 2722 | |
2720 | sc->sc_intrxfer = NULL; | | 2723 | sc->sc_intrxfer = NULL; |
2721 | } | | 2724 | } |
2722 | | | 2725 | |
2723 | /************************/ | | 2726 | /************************/ |
2724 | | | 2727 | |
2725 | int | | 2728 | int |
2726 | ohci_device_ctrl_init(struct usbd_xfer *xfer) | | 2729 | ohci_device_ctrl_init(struct usbd_xfer *xfer) |
2727 | { | | 2730 | { |
2728 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2731 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2729 | usb_device_request_t *req = &xfer->ux_request; | | 2732 | usb_device_request_t *req = &xfer->ux_request; |
2730 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2733 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2731 | ohci_soft_td_t *stat, *tail; | | 2734 | ohci_soft_td_t *stat, *setup; |
2732 | int isread = req->bmRequestType & UT_READ; | | 2735 | int isread = req->bmRequestType & UT_READ; |
2733 | int len = xfer->ux_bufsize; | | 2736 | int len = xfer->ux_bufsize; |
2734 | int err = ENOMEM; | | 2737 | int err = ENOMEM; |
2735 | | | 2738 | |
2736 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2739 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2737 | | | 2740 | |
2738 | /* The TD for setup will be a 'tail' from elsewhere */ | | 2741 | setup = ohci_alloc_std(sc); |
2739 | stat = ohci_alloc_std(sc); | | 2742 | if (setup == NULL) { |
2740 | if (stat == NULL) { | | | |
2741 | goto bad1; | | 2743 | goto bad1; |
2742 | } | | 2744 | } |
2743 | tail = ohci_alloc_std(sc); | | 2745 | stat = ohci_alloc_std(sc); |
2744 | if (tail == NULL) { | | 2746 | if (stat == NULL) { |
2745 | goto bad2; | | 2747 | goto bad2; |
2746 | } | | 2748 | } |
2747 | tail->xfer = NULL; | | | |
2748 | | | 2749 | |
| | | 2750 | ox->ox_setup = setup; |
2749 | ox->ox_stat = stat; | | 2751 | ox->ox_stat = stat; |
2750 | ox->ox_tdtail = tail; | | | |
2751 | ox->ox_nstd = 0; | | 2752 | ox->ox_nstd = 0; |
2752 | | | 2753 | |
2753 | /* Set up data transaction */ | | 2754 | /* Set up data transaction */ |
2754 | if (len != 0) { | | 2755 | if (len != 0) { |
2755 | err = ohci_alloc_std_chain(sc, xfer, len, isread); | | 2756 | err = ohci_alloc_std_chain(sc, xfer, len, isread); |
2756 | if (err) { | | 2757 | if (err) { |
2757 | goto bad3; | | 2758 | goto bad3; |
2758 | } | | 2759 | } |
2759 | } | | 2760 | } |
2760 | return 0; | | 2761 | return 0; |
2761 | | | 2762 | |
2762 | bad3: | | 2763 | bad3: |
2763 | ohci_free_std(sc, tail); | | | |
2764 | bad2: | | | |
2765 | ohci_free_std(sc, stat); | | 2764 | ohci_free_std(sc, stat); |
| | | 2765 | bad2: |
| | | 2766 | ohci_free_std(sc, setup); |
2766 | bad1: | | 2767 | bad1: |
2767 | return err; | | 2768 | return err; |
2768 | } | | 2769 | } |
2769 | | | 2770 | |
2770 | void | | 2771 | void |
2771 | ohci_device_ctrl_fini(struct usbd_xfer *xfer) | | 2772 | ohci_device_ctrl_fini(struct usbd_xfer *xfer) |
2772 | { | | 2773 | { |
2773 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2774 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2774 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2775 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2775 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 2776 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
2776 | | | 2777 | |
2777 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2778 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2778 | DPRINTFN(8, "xfer %p nstd %d", xfer, ox->ox_nstd, 0, 0); | | 2779 | DPRINTFN(8, "xfer %p nstd %d", xfer, ox->ox_nstd, 0, 0); |
2779 | | | 2780 | |
2780 | mutex_enter(&sc->sc_lock); | | 2781 | mutex_enter(&sc->sc_lock); |
2781 | if (ox->ox_tdtail != opipe->tail.td) { | | 2782 | if (ox->ox_setup != opipe->tail.td) { |
2782 | ohci_free_std_locked(sc, ox->ox_tdtail); | | 2783 | ohci_free_std_locked(sc, ox->ox_setup); |
2783 | } | | 2784 | } |
2784 | for (size_t i = 0; i < ox->ox_nstd; i++) { | | 2785 | for (size_t i = 0; i < ox->ox_nstd; i++) { |
2785 | ohci_soft_td_t *std = ox->ox_stds[i]; | | 2786 | ohci_soft_td_t *std = ox->ox_stds[i]; |
2786 | if (std == NULL) | | 2787 | if (std == NULL) |
2787 | break; | | 2788 | break; |
2788 | ohci_free_std_locked(sc, std); | | 2789 | ohci_free_std_locked(sc, std); |
2789 | } | | 2790 | } |
2790 | ohci_free_std_locked(sc, ox->ox_stat); | | 2791 | ohci_free_std_locked(sc, ox->ox_stat); |
2791 | mutex_exit(&sc->sc_lock); | | 2792 | mutex_exit(&sc->sc_lock); |
2792 | | | 2793 | |
2793 | if (ox->ox_nstd) { | | 2794 | if (ox->ox_nstd) { |
2794 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; | | 2795 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; |
2795 | kmem_free(ox->ox_stds, sz); | | 2796 | kmem_free(ox->ox_stds, sz); |
| @@ -2835,30 +2836,36 @@ ohci_device_ctrl_start(struct usbd_xfer | | | @@ -2835,30 +2836,36 @@ ohci_device_ctrl_start(struct usbd_xfer |
2835 | | | 2836 | |
2836 | isread = req->bmRequestType & UT_READ; | | 2837 | isread = req->bmRequestType & UT_READ; |
2837 | len = UGETW(req->wLength); | | 2838 | len = UGETW(req->wLength); |
2838 | | | 2839 | |
2839 | DPRINTF("xfer=%p len=%d, addr=%d, endpt=%d", xfer, len, dev->ud_addr, | | 2840 | DPRINTF("xfer=%p len=%d, addr=%d, endpt=%d", xfer, len, dev->ud_addr, |
2840 | opipe->pipe.up_endpoint->ue_edesc->bEndpointAddress); | | 2841 | opipe->pipe.up_endpoint->ue_edesc->bEndpointAddress); |
2841 | DPRINTF("type=0x%02x, request=0x%02x, wValue=0x%04x, wIndex=0x%04x", | | 2842 | DPRINTF("type=0x%02x, request=0x%02x, wValue=0x%04x, wIndex=0x%04x", |
2842 | req->bmRequestType, req->bRequest, UGETW(req->wValue), | | 2843 | req->bmRequestType, req->bRequest, UGETW(req->wValue), |
2843 | UGETW(req->wIndex)); | | 2844 | UGETW(req->wIndex)); |
2844 | | | 2845 | |
2845 | /* Need to take lock here for pipe->tail.td */ | | 2846 | /* Need to take lock here for pipe->tail.td */ |
2846 | mutex_enter(&sc->sc_lock); | | 2847 | mutex_enter(&sc->sc_lock); |
2847 | | | 2848 | |
| | | 2849 | /* |
| | | 2850 | * Use the pipe "tail" TD as our first and loan our first TD to the |
| | | 2851 | * next transfer |
| | | 2852 | */ |
2848 | setup = opipe->tail.td; | | 2853 | setup = opipe->tail.td; |
| | | 2854 | opipe->tail.td = ox->ox_setup; |
| | | 2855 | ox->ox_setup = setup; |
| | | 2856 | |
2849 | stat = ox->ox_stat; | | 2857 | stat = ox->ox_stat; |
2850 | tail = ox->ox_tdtail; | | 2858 | tail = opipe->tail.td; /* point at sentinel */ |
2851 | opipe->tail.td = tail; | | | |
2852 | | | 2859 | |
2853 | sed = opipe->sed; | | 2860 | sed = opipe->sed; |
2854 | | | 2861 | |
2855 | KASSERTMSG(OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)) == dev->ud_addr, | | 2862 | KASSERTMSG(OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)) == dev->ud_addr, |
2856 | "address ED %d pipe %d\n", | | 2863 | "address ED %d pipe %d\n", |
2857 | OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)), dev->ud_addr); | | 2864 | OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)), dev->ud_addr); |
2858 | KASSERTMSG(OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)) == | | 2865 | KASSERTMSG(OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)) == |
2859 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize), | | 2866 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize), |
2860 | "MPL ED %d pipe %d\n", | | 2867 | "MPL ED %d pipe %d\n", |
2861 | OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)), | | 2868 | OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)), |
2862 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize)); | | 2869 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize)); |
2863 | | | 2870 | |
2864 | /* next will point to data if len != 0 */ | | 2871 | /* next will point to data if len != 0 */ |
| @@ -3115,27 +3122,30 @@ ohci_device_bulk_start(struct usbd_xfer | | | @@ -3115,27 +3122,30 @@ ohci_device_bulk_start(struct usbd_xfer |
3115 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); | | 3122 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); |
3116 | | | 3123 | |
3117 | len = xfer->ux_length; | | 3124 | len = xfer->ux_length; |
3118 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 3125 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; |
3119 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 3126 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
3120 | sed = opipe->sed; | | 3127 | sed = opipe->sed; |
3121 | | | 3128 | |
3122 | DPRINTFN(4, "xfer=%p len=%d isread=%d flags=%d", xfer, len, isread, | | 3129 | DPRINTFN(4, "xfer=%p len=%d isread=%d flags=%d", xfer, len, isread, |
3123 | xfer->ux_flags); | | 3130 | xfer->ux_flags); |
3124 | DPRINTFN(4, "endpt=%d", endpt, 0, 0, 0); | | 3131 | DPRINTFN(4, "endpt=%d", endpt, 0, 0, 0); |
3125 | | | 3132 | |
3126 | mutex_enter(&sc->sc_lock); | | 3133 | mutex_enter(&sc->sc_lock); |
3127 | | | 3134 | |
3128 | /* Use "tail" TD and loan our first TD to next transfer */ | | 3135 | /* |
| | | 3136 | * Use the pipe "tail" TD as our first and loan our first TD to the |
| | | 3137 | * next transfer |
| | | 3138 | */ |
3129 | data = opipe->tail.td; | | 3139 | data = opipe->tail.td; |
3130 | opipe->tail.td = ox->ox_stds[0]; | | 3140 | opipe->tail.td = ox->ox_stds[0]; |
3131 | ox->ox_stds[0] = data; | | 3141 | ox->ox_stds[0] = data; |
3132 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); | | 3142 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); |
3133 | | | 3143 | |
3134 | tail = opipe->tail.td; /* point at sentinel */ | | 3144 | tail = opipe->tail.td; /* point at sentinel */ |
3135 | memset(&tail->td, 0, sizeof(tail->td)); | | 3145 | memset(&tail->td, 0, sizeof(tail->td)); |
3136 | tail->nexttd = NULL; | | 3146 | tail->nexttd = NULL; |
3137 | tail->xfer = NULL; | | 3147 | tail->xfer = NULL; |
3138 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), | | 3148 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), |
3139 | BUS_DMASYNC_PREWRITE); | | 3149 | BUS_DMASYNC_PREWRITE); |
3140 | xfer->ux_hcpriv = data; | | 3150 | xfer->ux_hcpriv = data; |
3141 | | | 3151 | |
| @@ -3309,27 +3319,30 @@ ohci_device_intr_start(struct usbd_xfer | | | @@ -3309,27 +3319,30 @@ ohci_device_intr_start(struct usbd_xfer |
3309 | return USBD_IOERROR; | | 3319 | return USBD_IOERROR; |
3310 | | | 3320 | |
3311 | DPRINTFN(3, "xfer=%p len=%d flags=%d priv=%p", xfer, xfer->ux_length, | | 3321 | DPRINTFN(3, "xfer=%p len=%d flags=%d priv=%p", xfer, xfer->ux_length, |
3312 | xfer->ux_flags, xfer->ux_priv); | | 3322 | xfer->ux_flags, xfer->ux_priv); |
3313 | | | 3323 | |
3314 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); | | 3324 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); |
3315 | | | 3325 | |
3316 | len = xfer->ux_length; | | 3326 | len = xfer->ux_length; |
3317 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 3327 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; |
3318 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 3328 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
3319 | | | 3329 | |
3320 | mutex_enter(&sc->sc_lock); | | 3330 | mutex_enter(&sc->sc_lock); |
3321 | | | 3331 | |
3322 | /* Use "tail" TD and loan our first TD to next transfer */ | | 3332 | /* |
| | | 3333 | * Use the pipe "tail" TD as our first and loan our first TD to the |
| | | 3334 | * next transfer. |
| | | 3335 | */ |
3323 | data = opipe->tail.td; | | 3336 | data = opipe->tail.td; |
3324 | opipe->tail.td = ox->ox_stds[0]; | | 3337 | opipe->tail.td = ox->ox_stds[0]; |
3325 | ox->ox_stds[0] = data; | | 3338 | ox->ox_stds[0] = data; |
3326 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); | | 3339 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); |
3327 | | | 3340 | |
3328 | tail = opipe->tail.td; /* point at sentinel */ | | 3341 | tail = opipe->tail.td; /* point at sentinel */ |
3329 | memset(&tail->td, 0, sizeof(tail->td)); | | 3342 | memset(&tail->td, 0, sizeof(tail->td)); |
3330 | tail->nexttd = NULL; | | 3343 | tail->nexttd = NULL; |
3331 | tail->xfer = NULL; | | 3344 | tail->xfer = NULL; |
3332 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), | | 3345 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), |
3333 | BUS_DMASYNC_PREWRITE); | | 3346 | BUS_DMASYNC_PREWRITE); |
3334 | xfer->ux_hcpriv = data; | | 3347 | xfer->ux_hcpriv = data; |
3335 | | | 3348 | |