| @@ -1,1533 +1,1533 @@ | | | @@ -1,1533 +1,1533 @@ |
1 | /* $NetBSD: ohci.c,v 1.297 2020/03/05 08:12:30 skrll Exp $ */ | | 1 | /* $NetBSD: ohci.c,v 1.298 2020/03/05 08:30:58 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 |
15 | * modification, are permitted provided that the following conditions | | 15 | * modification, are permitted provided that the following conditions |
16 | * are met: | | 16 | * are met: |
17 | * 1. Redistributions of source code must retain the above copyright | | 17 | * 1. Redistributions of source code must retain the above copyright |
18 | * notice, this list of conditions and the following disclaimer. | | 18 | * notice, this list of conditions and the following disclaimer. |
19 | * 2. Redistributions in binary form must reproduce the above copyright | | 19 | * 2. Redistributions in binary form must reproduce the above copyright |
20 | * notice, this list of conditions and the following disclaimer in the | | 20 | * notice, this list of conditions and the following disclaimer in the |
21 | * documentation and/or other materials provided with the distribution. | | 21 | * documentation and/or other materials provided with the distribution. |
22 | * | | 22 | * |
23 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 23 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
24 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 24 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
25 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 25 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
26 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 26 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
27 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 27 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
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.297 2020/03/05 08:12:30 skrll Exp $"); | | 44 | __KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.298 2020/03/05 08:30:58 skrll Exp $"); |
45 | | | 45 | |
46 | #ifdef _KERNEL_OPT | | 46 | #ifdef _KERNEL_OPT |
47 | #include "opt_usb.h" | | 47 | #include "opt_usb.h" |
48 | #endif | | 48 | #endif |
49 | | | 49 | |
50 | #include <sys/param.h> | | 50 | #include <sys/param.h> |
51 | | | 51 | |
52 | #include <sys/cpu.h> | | 52 | #include <sys/cpu.h> |
53 | #include <sys/device.h> | | 53 | #include <sys/device.h> |
54 | #include <sys/kernel.h> | | 54 | #include <sys/kernel.h> |
55 | #include <sys/kmem.h> | | 55 | #include <sys/kmem.h> |
56 | #include <sys/proc.h> | | 56 | #include <sys/proc.h> |
57 | #include <sys/queue.h> | | 57 | #include <sys/queue.h> |
58 | #include <sys/select.h> | | 58 | #include <sys/select.h> |
59 | #include <sys/sysctl.h> | | 59 | #include <sys/sysctl.h> |
60 | #include <sys/systm.h> | | 60 | #include <sys/systm.h> |
61 | | | 61 | |
62 | #include <machine/endian.h> | | 62 | #include <machine/endian.h> |
63 | | | 63 | |
64 | #include <dev/usb/usb.h> | | 64 | #include <dev/usb/usb.h> |
65 | #include <dev/usb/usbdi.h> | | 65 | #include <dev/usb/usbdi.h> |
66 | #include <dev/usb/usbdivar.h> | | 66 | #include <dev/usb/usbdivar.h> |
67 | #include <dev/usb/usb_mem.h> | | 67 | #include <dev/usb/usb_mem.h> |
68 | #include <dev/usb/usb_quirks.h> | | 68 | #include <dev/usb/usb_quirks.h> |
69 | | | 69 | |
70 | #include <dev/usb/ohcireg.h> | | 70 | #include <dev/usb/ohcireg.h> |
71 | #include <dev/usb/ohcivar.h> | | 71 | #include <dev/usb/ohcivar.h> |
72 | #include <dev/usb/usbroothub.h> | | 72 | #include <dev/usb/usbroothub.h> |
73 | #include <dev/usb/usbhist.h> | | 73 | #include <dev/usb/usbhist.h> |
74 | | | 74 | |
75 | #ifdef USB_DEBUG | | 75 | #ifdef USB_DEBUG |
76 | #ifndef OHCI_DEBUG | | 76 | #ifndef OHCI_DEBUG |
77 | #define ohcidebug 0 | | 77 | #define ohcidebug 0 |
78 | #else | | 78 | #else |
79 | static int ohcidebug = 10; | | 79 | static int ohcidebug = 10; |
80 | | | 80 | |
81 | SYSCTL_SETUP(sysctl_hw_ohci_setup, "sysctl hw.ohci setup") | | 81 | SYSCTL_SETUP(sysctl_hw_ohci_setup, "sysctl hw.ohci setup") |
82 | { | | 82 | { |
83 | int err; | | 83 | int err; |
84 | const struct sysctlnode *rnode; | | 84 | const struct sysctlnode *rnode; |
85 | const struct sysctlnode *cnode; | | 85 | const struct sysctlnode *cnode; |
86 | | | 86 | |
87 | err = sysctl_createv(clog, 0, NULL, &rnode, | | 87 | err = sysctl_createv(clog, 0, NULL, &rnode, |
88 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "ohci", | | 88 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "ohci", |
89 | SYSCTL_DESCR("ohci global controls"), | | 89 | SYSCTL_DESCR("ohci global controls"), |
90 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | | 90 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); |
91 | | | 91 | |
92 | if (err) | | 92 | if (err) |
93 | goto fail; | | 93 | goto fail; |
94 | | | 94 | |
95 | /* control debugging printfs */ | | 95 | /* control debugging printfs */ |
96 | err = sysctl_createv(clog, 0, &rnode, &cnode, | | 96 | err = sysctl_createv(clog, 0, &rnode, &cnode, |
97 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | | 97 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
98 | "debug", SYSCTL_DESCR("Enable debugging output"), | | 98 | "debug", SYSCTL_DESCR("Enable debugging output"), |
99 | NULL, 0, &ohcidebug, sizeof(ohcidebug), CTL_CREATE, CTL_EOL); | | 99 | NULL, 0, &ohcidebug, sizeof(ohcidebug), CTL_CREATE, CTL_EOL); |
100 | if (err) | | 100 | if (err) |
101 | goto fail; | | 101 | goto fail; |
102 | | | 102 | |
103 | return; | | 103 | return; |
104 | fail: | | 104 | fail: |
105 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | | 105 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); |
106 | } | | 106 | } |
107 | | | 107 | |
108 | #endif /* OHCI_DEBUG */ | | 108 | #endif /* OHCI_DEBUG */ |
109 | #endif /* USB_DEBUG */ | | 109 | #endif /* USB_DEBUG */ |
110 | | | 110 | |
111 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOG(ohcidebug,FMT,A,B,C,D) | | 111 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOG(ohcidebug,FMT,A,B,C,D) |
112 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(ohcidebug,N,FMT,A,B,C,D) | | 112 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(ohcidebug,N,FMT,A,B,C,D) |
113 | #define OHCIHIST_FUNC() USBHIST_FUNC() | | 113 | #define OHCIHIST_FUNC() USBHIST_FUNC() |
114 | #define OHCIHIST_CALLED(name) USBHIST_CALLED(ohcidebug) | | 114 | #define OHCIHIST_CALLED(name) USBHIST_CALLED(ohcidebug) |
115 | | | 115 | |
116 | #if BYTE_ORDER == BIG_ENDIAN | | 116 | #if BYTE_ORDER == BIG_ENDIAN |
117 | #define SWAP_ENDIAN OHCI_LITTLE_ENDIAN | | 117 | #define SWAP_ENDIAN OHCI_LITTLE_ENDIAN |
118 | #else | | 118 | #else |
119 | #define SWAP_ENDIAN OHCI_BIG_ENDIAN | | 119 | #define SWAP_ENDIAN OHCI_BIG_ENDIAN |
120 | #endif | | 120 | #endif |
121 | | | 121 | |
122 | #define O16TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap16(val) : val) | | 122 | #define O16TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap16(val) : val) |
123 | #define O32TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap32(val) : val) | | 123 | #define O32TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap32(val) : val) |
124 | #define HTOO16(val) O16TOH(val) | | 124 | #define HTOO16(val) O16TOH(val) |
125 | #define HTOO32(val) O32TOH(val) | | 125 | #define HTOO32(val) O32TOH(val) |
126 | | | 126 | |
127 | struct ohci_pipe; | | 127 | struct ohci_pipe; |
128 | | | 128 | |
129 | Static ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *); | | 129 | Static ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *); |
130 | Static void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *); | | 130 | Static void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *); |
131 | | | 131 | |
132 | Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *); | | 132 | Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *); |
133 | Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *); | | 133 | Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *); |
134 | Static void ohci_free_std_locked(ohci_softc_t *, ohci_soft_td_t *); | | 134 | Static void ohci_free_std_locked(ohci_softc_t *, ohci_soft_td_t *); |
135 | | | 135 | |
136 | Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *); | | 136 | Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *); |
137 | Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *); | | 137 | Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *); |
138 | Static void ohci_free_sitd_locked(ohci_softc_t *, | | 138 | Static void ohci_free_sitd_locked(ohci_softc_t *, |
139 | ohci_soft_itd_t *); | | 139 | ohci_soft_itd_t *); |
140 | | | 140 | |
141 | Static int ohci_alloc_std_chain(ohci_softc_t *, struct usbd_xfer *, | | 141 | Static int ohci_alloc_std_chain(ohci_softc_t *, struct usbd_xfer *, |
142 | int, int); | | 142 | int, int); |
143 | Static void ohci_free_stds(ohci_softc_t *, struct ohci_xfer *); | | 143 | Static void ohci_free_stds(ohci_softc_t *, struct ohci_xfer *); |
144 | | | 144 | |
145 | Static void ohci_reset_std_chain(ohci_softc_t *, struct usbd_xfer *, | | 145 | Static void ohci_reset_std_chain(ohci_softc_t *, struct usbd_xfer *, |
146 | int, int, ohci_soft_td_t *, ohci_soft_td_t **); | | 146 | int, int, ohci_soft_td_t *, ohci_soft_td_t **); |
147 | | | 147 | |
148 | Static usbd_status ohci_open(struct usbd_pipe *); | | 148 | Static usbd_status ohci_open(struct usbd_pipe *); |
149 | Static void ohci_poll(struct usbd_bus *); | | 149 | Static void ohci_poll(struct usbd_bus *); |
150 | Static void ohci_softintr(void *); | | 150 | Static void ohci_softintr(void *); |
151 | Static void ohci_rhsc(ohci_softc_t *, struct usbd_xfer *); | | 151 | Static void ohci_rhsc(ohci_softc_t *, struct usbd_xfer *); |
152 | Static void ohci_rhsc_softint(void *); | | 152 | Static void ohci_rhsc_softint(void *); |
153 | | | 153 | |
154 | Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *, | | 154 | Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *, |
155 | ohci_soft_ed_t *); | | 155 | ohci_soft_ed_t *); |
156 | | | 156 | |
157 | Static void ohci_rem_ed(ohci_softc_t *, ohci_soft_ed_t *, | | 157 | Static void ohci_rem_ed(ohci_softc_t *, ohci_soft_ed_t *, |
158 | ohci_soft_ed_t *); | | 158 | ohci_soft_ed_t *); |
159 | Static void ohci_hash_add_td(ohci_softc_t *, ohci_soft_td_t *); | | 159 | Static void ohci_hash_add_td(ohci_softc_t *, ohci_soft_td_t *); |
160 | Static void ohci_hash_rem_td(ohci_softc_t *, ohci_soft_td_t *); | | 160 | Static void ohci_hash_rem_td(ohci_softc_t *, ohci_soft_td_t *); |
161 | Static ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, ohci_physaddr_t); | | 161 | Static ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, ohci_physaddr_t); |
162 | Static void ohci_hash_add_itd(ohci_softc_t *, ohci_soft_itd_t *); | | 162 | Static void ohci_hash_add_itd(ohci_softc_t *, ohci_soft_itd_t *); |
163 | Static void ohci_hash_rem_itd(ohci_softc_t *, ohci_soft_itd_t *); | | 163 | Static void ohci_hash_rem_itd(ohci_softc_t *, ohci_soft_itd_t *); |
164 | Static ohci_soft_itd_t *ohci_hash_find_itd(ohci_softc_t *, ohci_physaddr_t); | | 164 | Static ohci_soft_itd_t *ohci_hash_find_itd(ohci_softc_t *, ohci_physaddr_t); |
165 | | | 165 | |
166 | Static usbd_status ohci_setup_isoc(struct usbd_pipe *); | | 166 | Static usbd_status ohci_setup_isoc(struct usbd_pipe *); |
167 | Static void ohci_device_isoc_enter(struct usbd_xfer *); | | 167 | Static void ohci_device_isoc_enter(struct usbd_xfer *); |
168 | | | 168 | |
169 | Static struct usbd_xfer * | | 169 | Static struct usbd_xfer * |
170 | ohci_allocx(struct usbd_bus *, unsigned int); | | 170 | ohci_allocx(struct usbd_bus *, unsigned int); |
171 | Static void ohci_freex(struct usbd_bus *, struct usbd_xfer *); | | 171 | Static void ohci_freex(struct usbd_bus *, struct usbd_xfer *); |
172 | Static bool ohci_dying(struct usbd_bus *); | | 172 | Static bool ohci_dying(struct usbd_bus *); |
173 | Static void ohci_get_lock(struct usbd_bus *, kmutex_t **); | | 173 | Static void ohci_get_lock(struct usbd_bus *, kmutex_t **); |
174 | Static int ohci_roothub_ctrl(struct usbd_bus *, | | 174 | Static int ohci_roothub_ctrl(struct usbd_bus *, |
175 | usb_device_request_t *, void *, int); | | 175 | usb_device_request_t *, void *, int); |
176 | | | 176 | |
177 | Static usbd_status ohci_root_intr_transfer(struct usbd_xfer *); | | 177 | Static usbd_status ohci_root_intr_transfer(struct usbd_xfer *); |
178 | Static usbd_status ohci_root_intr_start(struct usbd_xfer *); | | 178 | Static usbd_status ohci_root_intr_start(struct usbd_xfer *); |
179 | Static void ohci_root_intr_abort(struct usbd_xfer *); | | 179 | Static void ohci_root_intr_abort(struct usbd_xfer *); |
180 | Static void ohci_root_intr_close(struct usbd_pipe *); | | 180 | Static void ohci_root_intr_close(struct usbd_pipe *); |
181 | Static void ohci_root_intr_done(struct usbd_xfer *); | | 181 | Static void ohci_root_intr_done(struct usbd_xfer *); |
182 | | | 182 | |
183 | Static int ohci_device_ctrl_init(struct usbd_xfer *); | | 183 | Static int ohci_device_ctrl_init(struct usbd_xfer *); |
184 | Static void ohci_device_ctrl_fini(struct usbd_xfer *); | | 184 | Static void ohci_device_ctrl_fini(struct usbd_xfer *); |
185 | Static usbd_status ohci_device_ctrl_transfer(struct usbd_xfer *); | | 185 | Static usbd_status ohci_device_ctrl_transfer(struct usbd_xfer *); |
186 | Static usbd_status ohci_device_ctrl_start(struct usbd_xfer *); | | 186 | Static usbd_status ohci_device_ctrl_start(struct usbd_xfer *); |
187 | Static void ohci_device_ctrl_abort(struct usbd_xfer *); | | 187 | Static void ohci_device_ctrl_abort(struct usbd_xfer *); |
188 | Static void ohci_device_ctrl_close(struct usbd_pipe *); | | 188 | Static void ohci_device_ctrl_close(struct usbd_pipe *); |
189 | Static void ohci_device_ctrl_done(struct usbd_xfer *); | | 189 | Static void ohci_device_ctrl_done(struct usbd_xfer *); |
190 | | | 190 | |
191 | Static int ohci_device_bulk_init(struct usbd_xfer *); | | 191 | Static int ohci_device_bulk_init(struct usbd_xfer *); |
192 | Static void ohci_device_bulk_fini(struct usbd_xfer *); | | 192 | Static void ohci_device_bulk_fini(struct usbd_xfer *); |
193 | Static usbd_status ohci_device_bulk_transfer(struct usbd_xfer *); | | 193 | Static usbd_status ohci_device_bulk_transfer(struct usbd_xfer *); |
194 | Static usbd_status ohci_device_bulk_start(struct usbd_xfer *); | | 194 | Static usbd_status ohci_device_bulk_start(struct usbd_xfer *); |
195 | Static void ohci_device_bulk_abort(struct usbd_xfer *); | | 195 | Static void ohci_device_bulk_abort(struct usbd_xfer *); |
196 | Static void ohci_device_bulk_close(struct usbd_pipe *); | | 196 | Static void ohci_device_bulk_close(struct usbd_pipe *); |
197 | Static void ohci_device_bulk_done(struct usbd_xfer *); | | 197 | Static void ohci_device_bulk_done(struct usbd_xfer *); |
198 | | | 198 | |
199 | Static int ohci_device_intr_init(struct usbd_xfer *); | | 199 | Static int ohci_device_intr_init(struct usbd_xfer *); |
200 | Static void ohci_device_intr_fini(struct usbd_xfer *); | | 200 | Static void ohci_device_intr_fini(struct usbd_xfer *); |
201 | Static usbd_status ohci_device_intr_transfer(struct usbd_xfer *); | | 201 | Static usbd_status ohci_device_intr_transfer(struct usbd_xfer *); |
202 | Static usbd_status ohci_device_intr_start(struct usbd_xfer *); | | 202 | Static usbd_status ohci_device_intr_start(struct usbd_xfer *); |
203 | Static void ohci_device_intr_abort(struct usbd_xfer *); | | 203 | Static void ohci_device_intr_abort(struct usbd_xfer *); |
204 | Static void ohci_device_intr_close(struct usbd_pipe *); | | 204 | Static void ohci_device_intr_close(struct usbd_pipe *); |
205 | Static void ohci_device_intr_done(struct usbd_xfer *); | | 205 | Static void ohci_device_intr_done(struct usbd_xfer *); |
206 | | | 206 | |
207 | Static int ohci_device_isoc_init(struct usbd_xfer *); | | 207 | Static int ohci_device_isoc_init(struct usbd_xfer *); |
208 | Static void ohci_device_isoc_fini(struct usbd_xfer *); | | 208 | Static void ohci_device_isoc_fini(struct usbd_xfer *); |
209 | Static usbd_status ohci_device_isoc_transfer(struct usbd_xfer *); | | 209 | Static usbd_status ohci_device_isoc_transfer(struct usbd_xfer *); |
210 | Static void ohci_device_isoc_abort(struct usbd_xfer *); | | 210 | Static void ohci_device_isoc_abort(struct usbd_xfer *); |
211 | Static void ohci_device_isoc_close(struct usbd_pipe *); | | 211 | Static void ohci_device_isoc_close(struct usbd_pipe *); |
212 | Static void ohci_device_isoc_done(struct usbd_xfer *); | | 212 | Static void ohci_device_isoc_done(struct usbd_xfer *); |
213 | | | 213 | |
214 | Static usbd_status ohci_device_setintr(ohci_softc_t *, | | 214 | Static usbd_status ohci_device_setintr(ohci_softc_t *, |
215 | struct ohci_pipe *, int); | | 215 | struct ohci_pipe *, int); |
216 | | | 216 | |
217 | Static void ohci_rhsc_enable(void *); | | 217 | Static void ohci_rhsc_enable(void *); |
218 | | | 218 | |
219 | Static void ohci_close_pipe(struct usbd_pipe *, ohci_soft_ed_t *); | | 219 | Static void ohci_close_pipe(struct usbd_pipe *, ohci_soft_ed_t *); |
220 | Static void ohci_abortx(struct usbd_xfer *); | | 220 | Static void ohci_abortx(struct usbd_xfer *); |
221 | | | 221 | |
222 | Static void ohci_device_clear_toggle(struct usbd_pipe *); | | 222 | Static void ohci_device_clear_toggle(struct usbd_pipe *); |
223 | Static void ohci_noop(struct usbd_pipe *); | | 223 | Static void ohci_noop(struct usbd_pipe *); |
224 | | | 224 | |
225 | #ifdef OHCI_DEBUG | | 225 | #ifdef OHCI_DEBUG |
226 | Static void ohci_dumpregs(ohci_softc_t *); | | 226 | Static void ohci_dumpregs(ohci_softc_t *); |
227 | Static void ohci_dump_tds(ohci_softc_t *, ohci_soft_td_t *); | | 227 | Static void ohci_dump_tds(ohci_softc_t *, ohci_soft_td_t *); |
228 | Static void ohci_dump_td(ohci_softc_t *, ohci_soft_td_t *); | | 228 | Static void ohci_dump_td(ohci_softc_t *, ohci_soft_td_t *); |
229 | Static void ohci_dump_ed(ohci_softc_t *, ohci_soft_ed_t *); | | 229 | Static void ohci_dump_ed(ohci_softc_t *, ohci_soft_ed_t *); |
230 | Static void ohci_dump_itd(ohci_softc_t *, ohci_soft_itd_t *); | | 230 | Static void ohci_dump_itd(ohci_softc_t *, ohci_soft_itd_t *); |
231 | Static void ohci_dump_itds(ohci_softc_t *, ohci_soft_itd_t *); | | 231 | Static void ohci_dump_itds(ohci_softc_t *, ohci_soft_itd_t *); |
232 | #endif | | 232 | #endif |
233 | | | 233 | |
234 | #define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ | | 234 | #define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ |
235 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) | | 235 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) |
236 | #define OWRITE1(sc, r, x) \ | | 236 | #define OWRITE1(sc, r, x) \ |
237 | do { OBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | | 237 | do { OBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0) |
238 | #define OWRITE2(sc, r, x) \ | | 238 | #define OWRITE2(sc, r, x) \ |
239 | do { OBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | | 239 | do { OBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0) |
240 | #define OWRITE4(sc, r, x) \ | | 240 | #define OWRITE4(sc, r, x) \ |
241 | do { OBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | | 241 | do { OBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0) |
242 | | | 242 | |
243 | static __inline uint32_t | | 243 | static __inline uint32_t |
244 | OREAD4(ohci_softc_t *sc, bus_size_t r) | | 244 | OREAD4(ohci_softc_t *sc, bus_size_t r) |
245 | { | | 245 | { |
246 | | | 246 | |
247 | OBARR(sc); | | 247 | OBARR(sc); |
248 | return bus_space_read_4(sc->iot, sc->ioh, r); | | 248 | return bus_space_read_4(sc->iot, sc->ioh, r); |
249 | } | | 249 | } |
250 | | | 250 | |
251 | /* Reverse the bits in a value 0 .. 31 */ | | 251 | /* Reverse the bits in a value 0 .. 31 */ |
252 | Static uint8_t revbits[OHCI_NO_INTRS] = | | 252 | Static uint8_t revbits[OHCI_NO_INTRS] = |
253 | { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, | | 253 | { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, |
254 | 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, | | 254 | 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, |
255 | 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, | | 255 | 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, |
256 | 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; | | 256 | 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; |
257 | | | 257 | |
258 | struct ohci_pipe { | | 258 | struct ohci_pipe { |
259 | struct usbd_pipe pipe; | | 259 | struct usbd_pipe pipe; |
260 | ohci_soft_ed_t *sed; | | 260 | ohci_soft_ed_t *sed; |
261 | union { | | 261 | union { |
262 | ohci_soft_td_t *td; | | 262 | ohci_soft_td_t *td; |
263 | ohci_soft_itd_t *itd; | | 263 | ohci_soft_itd_t *itd; |
264 | } tail; | | 264 | } tail; |
265 | /* Info needed for different pipe kinds. */ | | 265 | /* Info needed for different pipe kinds. */ |
266 | union { | | 266 | union { |
267 | /* Control pipe */ | | 267 | /* Control pipe */ |
268 | struct { | | 268 | struct { |
269 | usb_dma_t reqdma; | | 269 | usb_dma_t reqdma; |
270 | } ctrl; | | 270 | } ctrl; |
271 | /* Interrupt pipe */ | | 271 | /* Interrupt pipe */ |
272 | struct { | | 272 | struct { |
273 | int nslots; | | 273 | int nslots; |
274 | int pos; | | 274 | int pos; |
275 | } intr; | | 275 | } intr; |
276 | /* Isochronous pipe */ | | 276 | /* Isochronous pipe */ |
277 | struct isoc { | | 277 | struct isoc { |
278 | int next, inuse; | | 278 | int next, inuse; |
279 | } isoc; | | 279 | } isoc; |
280 | }; | | 280 | }; |
281 | }; | | 281 | }; |
282 | | | 282 | |
283 | Static const struct usbd_bus_methods ohci_bus_methods = { | | 283 | Static const struct usbd_bus_methods ohci_bus_methods = { |
284 | .ubm_open = ohci_open, | | 284 | .ubm_open = ohci_open, |
285 | .ubm_softint = ohci_softintr, | | 285 | .ubm_softint = ohci_softintr, |
286 | .ubm_dopoll = ohci_poll, | | 286 | .ubm_dopoll = ohci_poll, |
287 | .ubm_allocx = ohci_allocx, | | 287 | .ubm_allocx = ohci_allocx, |
288 | .ubm_freex = ohci_freex, | | 288 | .ubm_freex = ohci_freex, |
289 | .ubm_abortx = ohci_abortx, | | 289 | .ubm_abortx = ohci_abortx, |
290 | .ubm_dying = ohci_dying, | | 290 | .ubm_dying = ohci_dying, |
291 | .ubm_getlock = ohci_get_lock, | | 291 | .ubm_getlock = ohci_get_lock, |
292 | .ubm_rhctrl = ohci_roothub_ctrl, | | 292 | .ubm_rhctrl = ohci_roothub_ctrl, |
293 | }; | | 293 | }; |
294 | | | 294 | |
295 | Static const struct usbd_pipe_methods ohci_root_intr_methods = { | | 295 | Static const struct usbd_pipe_methods ohci_root_intr_methods = { |
296 | .upm_transfer = ohci_root_intr_transfer, | | 296 | .upm_transfer = ohci_root_intr_transfer, |
297 | .upm_start = ohci_root_intr_start, | | 297 | .upm_start = ohci_root_intr_start, |
298 | .upm_abort = ohci_root_intr_abort, | | 298 | .upm_abort = ohci_root_intr_abort, |
299 | .upm_close = ohci_root_intr_close, | | 299 | .upm_close = ohci_root_intr_close, |
300 | .upm_cleartoggle = ohci_noop, | | 300 | .upm_cleartoggle = ohci_noop, |
301 | .upm_done = ohci_root_intr_done, | | 301 | .upm_done = ohci_root_intr_done, |
302 | }; | | 302 | }; |
303 | | | 303 | |
304 | Static const struct usbd_pipe_methods ohci_device_ctrl_methods = { | | 304 | Static const struct usbd_pipe_methods ohci_device_ctrl_methods = { |
305 | .upm_init = ohci_device_ctrl_init, | | 305 | .upm_init = ohci_device_ctrl_init, |
306 | .upm_fini = ohci_device_ctrl_fini, | | 306 | .upm_fini = ohci_device_ctrl_fini, |
307 | .upm_transfer = ohci_device_ctrl_transfer, | | 307 | .upm_transfer = ohci_device_ctrl_transfer, |
308 | .upm_start = ohci_device_ctrl_start, | | 308 | .upm_start = ohci_device_ctrl_start, |
309 | .upm_abort = ohci_device_ctrl_abort, | | 309 | .upm_abort = ohci_device_ctrl_abort, |
310 | .upm_close = ohci_device_ctrl_close, | | 310 | .upm_close = ohci_device_ctrl_close, |
311 | .upm_cleartoggle = ohci_noop, | | 311 | .upm_cleartoggle = ohci_noop, |
312 | .upm_done = ohci_device_ctrl_done, | | 312 | .upm_done = ohci_device_ctrl_done, |
313 | }; | | 313 | }; |
314 | | | 314 | |
315 | Static const struct usbd_pipe_methods ohci_device_intr_methods = { | | 315 | Static const struct usbd_pipe_methods ohci_device_intr_methods = { |
316 | .upm_init = ohci_device_intr_init, | | 316 | .upm_init = ohci_device_intr_init, |
317 | .upm_fini = ohci_device_intr_fini, | | 317 | .upm_fini = ohci_device_intr_fini, |
318 | .upm_transfer = ohci_device_intr_transfer, | | 318 | .upm_transfer = ohci_device_intr_transfer, |
319 | .upm_start = ohci_device_intr_start, | | 319 | .upm_start = ohci_device_intr_start, |
320 | .upm_abort = ohci_device_intr_abort, | | 320 | .upm_abort = ohci_device_intr_abort, |
321 | .upm_close = ohci_device_intr_close, | | 321 | .upm_close = ohci_device_intr_close, |
322 | .upm_cleartoggle = ohci_device_clear_toggle, | | 322 | .upm_cleartoggle = ohci_device_clear_toggle, |
323 | .upm_done = ohci_device_intr_done, | | 323 | .upm_done = ohci_device_intr_done, |
324 | }; | | 324 | }; |
325 | | | 325 | |
326 | Static const struct usbd_pipe_methods ohci_device_bulk_methods = { | | 326 | Static const struct usbd_pipe_methods ohci_device_bulk_methods = { |
327 | .upm_init = ohci_device_bulk_init, | | 327 | .upm_init = ohci_device_bulk_init, |
328 | .upm_fini = ohci_device_bulk_fini, | | 328 | .upm_fini = ohci_device_bulk_fini, |
329 | .upm_transfer = ohci_device_bulk_transfer, | | 329 | .upm_transfer = ohci_device_bulk_transfer, |
330 | .upm_start = ohci_device_bulk_start, | | 330 | .upm_start = ohci_device_bulk_start, |
331 | .upm_abort = ohci_device_bulk_abort, | | 331 | .upm_abort = ohci_device_bulk_abort, |
332 | .upm_close = ohci_device_bulk_close, | | 332 | .upm_close = ohci_device_bulk_close, |
333 | .upm_cleartoggle = ohci_device_clear_toggle, | | 333 | .upm_cleartoggle = ohci_device_clear_toggle, |
334 | .upm_done = ohci_device_bulk_done, | | 334 | .upm_done = ohci_device_bulk_done, |
335 | }; | | 335 | }; |
336 | | | 336 | |
337 | Static const struct usbd_pipe_methods ohci_device_isoc_methods = { | | 337 | Static const struct usbd_pipe_methods ohci_device_isoc_methods = { |
338 | .upm_init = ohci_device_isoc_init, | | 338 | .upm_init = ohci_device_isoc_init, |
339 | .upm_fini = ohci_device_isoc_fini, | | 339 | .upm_fini = ohci_device_isoc_fini, |
340 | .upm_transfer = ohci_device_isoc_transfer, | | 340 | .upm_transfer = ohci_device_isoc_transfer, |
341 | .upm_abort = ohci_device_isoc_abort, | | 341 | .upm_abort = ohci_device_isoc_abort, |
342 | .upm_close = ohci_device_isoc_close, | | 342 | .upm_close = ohci_device_isoc_close, |
343 | .upm_cleartoggle = ohci_noop, | | 343 | .upm_cleartoggle = ohci_noop, |
344 | .upm_done = ohci_device_isoc_done, | | 344 | .upm_done = ohci_device_isoc_done, |
345 | }; | | 345 | }; |
346 | | | 346 | |
347 | int | | 347 | int |
348 | ohci_activate(device_t self, enum devact act) | | 348 | ohci_activate(device_t self, enum devact act) |
349 | { | | 349 | { |
350 | struct ohci_softc *sc = device_private(self); | | 350 | struct ohci_softc *sc = device_private(self); |
351 | | | 351 | |
352 | switch (act) { | | 352 | switch (act) { |
353 | case DVACT_DEACTIVATE: | | 353 | case DVACT_DEACTIVATE: |
354 | sc->sc_dying = 1; | | 354 | sc->sc_dying = 1; |
355 | return 0; | | 355 | return 0; |
356 | default: | | 356 | default: |
357 | return EOPNOTSUPP; | | 357 | return EOPNOTSUPP; |
358 | } | | 358 | } |
359 | } | | 359 | } |
360 | | | 360 | |
361 | void | | 361 | void |
362 | ohci_childdet(device_t self, device_t child) | | 362 | ohci_childdet(device_t self, device_t child) |
363 | { | | 363 | { |
364 | struct ohci_softc *sc = device_private(self); | | 364 | struct ohci_softc *sc = device_private(self); |
365 | | | 365 | |
366 | KASSERT(sc->sc_child == child); | | 366 | KASSERT(sc->sc_child == child); |
367 | sc->sc_child = NULL; | | 367 | sc->sc_child = NULL; |
368 | } | | 368 | } |
369 | | | 369 | |
370 | int | | 370 | int |
371 | ohci_detach(struct ohci_softc *sc, int flags) | | 371 | ohci_detach(struct ohci_softc *sc, int flags) |
372 | { | | 372 | { |
373 | int rv = 0; | | 373 | int rv = 0; |
374 | | | 374 | |
375 | if (sc->sc_child != NULL) | | 375 | if (sc->sc_child != NULL) |
376 | rv = config_detach(sc->sc_child, flags); | | 376 | rv = config_detach(sc->sc_child, flags); |
377 | | | 377 | |
378 | if (rv != 0) | | 378 | if (rv != 0) |
379 | return rv; | | 379 | return rv; |
380 | | | 380 | |
381 | softint_disestablish(sc->sc_rhsc_si); | | 381 | softint_disestablish(sc->sc_rhsc_si); |
382 | | | 382 | |
383 | callout_halt(&sc->sc_tmo_rhsc, NULL); | | 383 | callout_halt(&sc->sc_tmo_rhsc, NULL); |
384 | callout_destroy(&sc->sc_tmo_rhsc); | | 384 | callout_destroy(&sc->sc_tmo_rhsc); |
385 | | | 385 | |
386 | mutex_destroy(&sc->sc_lock); | | 386 | mutex_destroy(&sc->sc_lock); |
387 | mutex_destroy(&sc->sc_intr_lock); | | 387 | mutex_destroy(&sc->sc_intr_lock); |
388 | | | 388 | |
389 | if (sc->sc_hcca != NULL) | | 389 | if (sc->sc_hcca != NULL) |
390 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | | 390 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); |
391 | pool_cache_destroy(sc->sc_xferpool); | | 391 | pool_cache_destroy(sc->sc_xferpool); |
392 | | | 392 | |
393 | return rv; | | 393 | return rv; |
394 | } | | 394 | } |
395 | | | 395 | |
396 | ohci_soft_ed_t * | | 396 | ohci_soft_ed_t * |
397 | ohci_alloc_sed(ohci_softc_t *sc) | | 397 | ohci_alloc_sed(ohci_softc_t *sc) |
398 | { | | 398 | { |
399 | ohci_soft_ed_t *sed; | | 399 | ohci_soft_ed_t *sed; |
400 | usbd_status err; | | 400 | usbd_status err; |
401 | int i, offs; | | 401 | int i, offs; |
402 | usb_dma_t dma; | | 402 | usb_dma_t dma; |
403 | | | 403 | |
404 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 404 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
405 | | | 405 | |
406 | mutex_enter(&sc->sc_lock); | | 406 | mutex_enter(&sc->sc_lock); |
407 | if (sc->sc_freeeds == NULL) { | | 407 | if (sc->sc_freeeds == NULL) { |
408 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); | | 408 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); |
409 | mutex_exit(&sc->sc_lock); | | 409 | mutex_exit(&sc->sc_lock); |
410 | | | 410 | |
411 | err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK, | | 411 | err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK, |
412 | OHCI_ED_ALIGN, &dma); | | 412 | OHCI_ED_ALIGN, &dma); |
413 | if (err) | | 413 | if (err) |
414 | return 0; | | 414 | return 0; |
415 | | | 415 | |
416 | mutex_enter(&sc->sc_lock); | | 416 | mutex_enter(&sc->sc_lock); |
417 | for (i = 0; i < OHCI_SED_CHUNK; i++) { | | 417 | for (i = 0; i < OHCI_SED_CHUNK; i++) { |
418 | offs = i * OHCI_SED_SIZE; | | 418 | offs = i * OHCI_SED_SIZE; |
419 | sed = KERNADDR(&dma, offs); | | 419 | sed = KERNADDR(&dma, offs); |
420 | sed->physaddr = DMAADDR(&dma, offs); | | 420 | sed->physaddr = DMAADDR(&dma, offs); |
421 | sed->dma = dma; | | 421 | sed->dma = dma; |
422 | sed->offs = offs; | | 422 | sed->offs = offs; |
423 | sed->next = sc->sc_freeeds; | | 423 | sed->next = sc->sc_freeeds; |
424 | sc->sc_freeeds = sed; | | 424 | sc->sc_freeeds = sed; |
425 | } | | 425 | } |
426 | } | | 426 | } |
427 | sed = sc->sc_freeeds; | | 427 | sed = sc->sc_freeeds; |
428 | sc->sc_freeeds = sed->next; | | 428 | sc->sc_freeeds = sed->next; |
429 | mutex_exit(&sc->sc_lock); | | 429 | mutex_exit(&sc->sc_lock); |
430 | | | 430 | |
431 | memset(&sed->ed, 0, sizeof(ohci_ed_t)); | | 431 | memset(&sed->ed, 0, sizeof(ohci_ed_t)); |
432 | sed->next = 0; | | 432 | sed->next = 0; |
433 | return sed; | | 433 | return sed; |
434 | } | | 434 | } |
435 | | | 435 | |
436 | static inline void | | 436 | static inline void |
437 | ohci_free_sed_locked(ohci_softc_t *sc, ohci_soft_ed_t *sed) | | 437 | ohci_free_sed_locked(ohci_softc_t *sc, ohci_soft_ed_t *sed) |
438 | { | | 438 | { |
439 | | | 439 | |
440 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 440 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
441 | | | 441 | |
442 | sed->next = sc->sc_freeeds; | | 442 | sed->next = sc->sc_freeeds; |
443 | sc->sc_freeeds = sed; | | 443 | sc->sc_freeeds = sed; |
444 | } | | 444 | } |
445 | | | 445 | |
446 | void | | 446 | void |
447 | ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed) | | 447 | ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed) |
448 | { | | 448 | { |
449 | | | 449 | |
450 | mutex_enter(&sc->sc_lock); | | 450 | mutex_enter(&sc->sc_lock); |
451 | ohci_free_sed_locked(sc, sed); | | 451 | ohci_free_sed_locked(sc, sed); |
452 | mutex_exit(&sc->sc_lock); | | 452 | mutex_exit(&sc->sc_lock); |
453 | } | | 453 | } |
454 | | | 454 | |
455 | ohci_soft_td_t * | | 455 | ohci_soft_td_t * |
456 | ohci_alloc_std(ohci_softc_t *sc) | | 456 | ohci_alloc_std(ohci_softc_t *sc) |
457 | { | | 457 | { |
458 | ohci_soft_td_t *std; | | 458 | ohci_soft_td_t *std; |
459 | usbd_status err; | | 459 | usbd_status err; |
460 | int i, offs; | | 460 | int i, offs; |
461 | usb_dma_t dma; | | 461 | usb_dma_t dma; |
462 | | | 462 | |
463 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 463 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
464 | | | 464 | |
465 | mutex_enter(&sc->sc_lock); | | 465 | mutex_enter(&sc->sc_lock); |
466 | if (sc->sc_freetds == NULL) { | | 466 | if (sc->sc_freetds == NULL) { |
467 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); | | 467 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); |
468 | mutex_exit(&sc->sc_lock); | | 468 | mutex_exit(&sc->sc_lock); |
469 | | | 469 | |
470 | err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK, | | 470 | err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK, |
471 | OHCI_TD_ALIGN, &dma); | | 471 | OHCI_TD_ALIGN, &dma); |
472 | if (err) | | 472 | if (err) |
473 | return NULL; | | 473 | return NULL; |
474 | | | 474 | |
475 | mutex_enter(&sc->sc_lock); | | 475 | mutex_enter(&sc->sc_lock); |
476 | for (i = 0; i < OHCI_STD_CHUNK; i++) { | | 476 | for (i = 0; i < OHCI_STD_CHUNK; i++) { |
477 | offs = i * OHCI_STD_SIZE; | | 477 | offs = i * OHCI_STD_SIZE; |
478 | std = KERNADDR(&dma, offs); | | 478 | std = KERNADDR(&dma, offs); |
479 | std->physaddr = DMAADDR(&dma, offs); | | 479 | std->physaddr = DMAADDR(&dma, offs); |
480 | std->dma = dma; | | 480 | std->dma = dma; |
481 | std->offs = offs; | | 481 | std->offs = offs; |
482 | std->nexttd = sc->sc_freetds; | | 482 | std->nexttd = sc->sc_freetds; |
483 | sc->sc_freetds = std; | | 483 | sc->sc_freetds = std; |
484 | } | | 484 | } |
485 | } | | 485 | } |
486 | | | 486 | |
487 | std = sc->sc_freetds; | | 487 | std = sc->sc_freetds; |
488 | sc->sc_freetds = std->nexttd; | | 488 | sc->sc_freetds = std->nexttd; |
489 | mutex_exit(&sc->sc_lock); | | 489 | mutex_exit(&sc->sc_lock); |
490 | | | 490 | |
491 | memset(&std->td, 0, sizeof(ohci_td_t)); | | 491 | memset(&std->td, 0, sizeof(ohci_td_t)); |
492 | std->nexttd = NULL; | | 492 | std->nexttd = NULL; |
493 | std->xfer = NULL; | | 493 | std->xfer = NULL; |
494 | | | 494 | |
495 | return std; | | 495 | return std; |
496 | } | | 496 | } |
497 | | | 497 | |
498 | void | | 498 | void |
499 | ohci_free_std_locked(ohci_softc_t *sc, ohci_soft_td_t *std) | | 499 | ohci_free_std_locked(ohci_softc_t *sc, ohci_soft_td_t *std) |
500 | { | | 500 | { |
501 | | | 501 | |
502 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 502 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
503 | | | 503 | |
504 | std->nexttd = sc->sc_freetds; | | 504 | std->nexttd = sc->sc_freetds; |
505 | sc->sc_freetds = std; | | 505 | sc->sc_freetds = std; |
506 | } | | 506 | } |
507 | | | 507 | |
508 | void | | 508 | void |
509 | ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std) | | 509 | ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std) |
510 | { | | 510 | { |
511 | | | 511 | |
512 | mutex_enter(&sc->sc_lock); | | 512 | mutex_enter(&sc->sc_lock); |
513 | ohci_free_std_locked(sc, std); | | 513 | ohci_free_std_locked(sc, std); |
514 | mutex_exit(&sc->sc_lock); | | 514 | mutex_exit(&sc->sc_lock); |
515 | } | | 515 | } |
516 | | | 516 | |
517 | Static int | | 517 | Static int |
518 | ohci_alloc_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, int length, int rd) | | 518 | ohci_alloc_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, int length, int rd) |
519 | { | | 519 | { |
520 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 520 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
521 | uint16_t flags = xfer->ux_flags; | | 521 | uint16_t flags = xfer->ux_flags; |
522 | | | 522 | |
523 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 523 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
524 | | | 524 | |
525 | DPRINTFN(8, "addr=%jd endpt=%jd len=%jd speed=%jd", | | 525 | DPRINTFN(8, "addr=%jd endpt=%jd len=%jd speed=%jd", |
526 | xfer->ux_pipe->up_dev->ud_addr, | | 526 | xfer->ux_pipe->up_dev->ud_addr, |
527 | UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress), | | 527 | UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress), |
528 | length, xfer->ux_pipe->up_dev->ud_speed); | | 528 | length, xfer->ux_pipe->up_dev->ud_speed); |
529 | | | 529 | |
530 | ASSERT_SLEEPABLE(); | | 530 | ASSERT_SLEEPABLE(); |
531 | KASSERT(length != 0 || (!rd && (flags & USBD_FORCE_SHORT_XFER))); | | 531 | KASSERT(length != 0 || (!rd && (flags & USBD_FORCE_SHORT_XFER))); |
532 | | | 532 | |
533 | size_t nstd = (!rd && (flags & USBD_FORCE_SHORT_XFER)) ? 1 : 0; | | 533 | size_t nstd = (!rd && (flags & USBD_FORCE_SHORT_XFER)) ? 1 : 0; |
534 | nstd += ((length + OHCI_PAGE_SIZE - 1) / OHCI_PAGE_SIZE); | | 534 | nstd += howmany(length, OHCI_PAGE_SIZE); |
535 | ox->ox_stds = kmem_zalloc(sizeof(ohci_soft_td_t *) * nstd, | | 535 | ox->ox_stds = kmem_zalloc(sizeof(ohci_soft_td_t *) * nstd, |
536 | KM_SLEEP); | | 536 | KM_SLEEP); |
537 | ox->ox_nstd = nstd; | | 537 | ox->ox_nstd = nstd; |
538 | | | 538 | |
539 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, nstd, 0, 0); | | 539 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, nstd, 0, 0); |
540 | | | 540 | |
541 | for (size_t j = 0; j < ox->ox_nstd;) { | | 541 | for (size_t j = 0; j < ox->ox_nstd;) { |
542 | ohci_soft_td_t *cur = ohci_alloc_std(sc); | | 542 | ohci_soft_td_t *cur = ohci_alloc_std(sc); |
543 | if (cur == NULL) | | 543 | if (cur == NULL) |
544 | goto nomem; | | 544 | goto nomem; |
545 | | | 545 | |
546 | ox->ox_stds[j++] = cur; | | 546 | ox->ox_stds[j++] = cur; |
547 | cur->xfer = xfer; | | 547 | cur->xfer = xfer; |
548 | cur->flags = 0; | | 548 | cur->flags = 0; |
549 | } | | 549 | } |
550 | | | 550 | |
551 | return 0; | | 551 | return 0; |
552 | | | 552 | |
553 | nomem: | | 553 | nomem: |
554 | ohci_free_stds(sc, ox); | | 554 | ohci_free_stds(sc, ox); |
555 | kmem_free(ox->ox_stds, sizeof(ohci_soft_td_t *) * nstd); | | 555 | kmem_free(ox->ox_stds, sizeof(ohci_soft_td_t *) * nstd); |
556 | | | 556 | |
557 | return ENOMEM; | | 557 | return ENOMEM; |
558 | } | | 558 | } |
559 | | | 559 | |
560 | Static void | | 560 | Static void |
561 | ohci_free_stds(ohci_softc_t *sc, struct ohci_xfer *ox) | | 561 | ohci_free_stds(ohci_softc_t *sc, struct ohci_xfer *ox) |
562 | { | | 562 | { |
563 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 563 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
564 | DPRINTF("ox=%#jx", (uintptr_t)ox, 0, 0, 0); | | 564 | DPRINTF("ox=%#jx", (uintptr_t)ox, 0, 0, 0); |
565 | | | 565 | |
566 | mutex_enter(&sc->sc_lock); | | 566 | mutex_enter(&sc->sc_lock); |
567 | for (size_t i = 0; i < ox->ox_nstd; i++) { | | 567 | for (size_t i = 0; i < ox->ox_nstd; i++) { |
568 | ohci_soft_td_t *std = ox->ox_stds[i]; | | 568 | ohci_soft_td_t *std = ox->ox_stds[i]; |
569 | if (std == NULL) | | 569 | if (std == NULL) |
570 | break; | | 570 | break; |
571 | ohci_free_std_locked(sc, std); | | 571 | ohci_free_std_locked(sc, std); |
572 | } | | 572 | } |
573 | mutex_exit(&sc->sc_lock); | | 573 | mutex_exit(&sc->sc_lock); |
574 | } | | 574 | } |
575 | | | 575 | |
576 | void | | 576 | void |
577 | ohci_reset_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, | | 577 | ohci_reset_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, |
578 | int alen, int rd, ohci_soft_td_t *sp, ohci_soft_td_t **ep) | | 578 | int alen, int rd, ohci_soft_td_t *sp, ohci_soft_td_t **ep) |
579 | { | | 579 | { |
580 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 580 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
581 | ohci_soft_td_t *next, *cur; | | 581 | ohci_soft_td_t *next, *cur; |
582 | int len, curlen; | | 582 | int len, curlen; |
583 | usb_dma_t *dma = &xfer->ux_dmabuf; | | 583 | usb_dma_t *dma = &xfer->ux_dmabuf; |
584 | uint16_t flags = xfer->ux_flags; | | 584 | uint16_t flags = xfer->ux_flags; |
585 | | | 585 | |
586 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 586 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
587 | DPRINTF("start len=%jd", alen, 0, 0, 0); | | 587 | DPRINTF("start len=%jd", alen, 0, 0, 0); |
588 | | | 588 | |
589 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 589 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
590 | | | 590 | |
591 | DPRINTFN(8, "addr=%jd endpt=%jd len=%jd speed=%jd", | | 591 | DPRINTFN(8, "addr=%jd endpt=%jd len=%jd speed=%jd", |
592 | xfer->ux_pipe->up_dev->ud_addr, | | 592 | xfer->ux_pipe->up_dev->ud_addr, |
593 | UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress), | | 593 | UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress), |
594 | alen, xfer->ux_pipe->up_dev->ud_speed); | | 594 | alen, xfer->ux_pipe->up_dev->ud_speed); |
595 | | | 595 | |
596 | KASSERT(sp); | | 596 | KASSERT(sp); |
597 | | | 597 | |
598 | int mps = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize); | | 598 | int mps = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize); |
599 | | | 599 | |
600 | /* | | 600 | /* |
601 | * Assign next for the len == 0 case where we don't go through the | | 601 | * Assign next for the len == 0 case where we don't go through the |
602 | * main loop. | | 602 | * main loop. |
603 | */ | | 603 | */ |
604 | len = alen; | | 604 | len = alen; |
605 | cur = next = sp; | | 605 | cur = next = sp; |
606 | | | 606 | |
607 | usb_syncmem(dma, 0, len, | | 607 | usb_syncmem(dma, 0, len, |
608 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | | 608 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); |
609 | const uint32_t tdflags = HTOO32( | | 609 | const uint32_t tdflags = HTOO32( |
610 | (rd ? OHCI_TD_IN : OHCI_TD_OUT) | | | 610 | (rd ? OHCI_TD_IN : OHCI_TD_OUT) | |
611 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); | | 611 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); |
612 | | | 612 | |
613 | size_t curoffs = 0; | | 613 | size_t curoffs = 0; |
614 | for (size_t j = 1; len != 0;) { | | 614 | for (size_t j = 1; len != 0;) { |
615 | if (j == ox->ox_nstd) | | 615 | if (j == ox->ox_nstd) |
616 | next = NULL; | | 616 | next = NULL; |
617 | else | | 617 | else |
618 | next = ox->ox_stds[j++]; | | 618 | next = ox->ox_stds[j++]; |
619 | KASSERT(next != cur); | | 619 | KASSERT(next != cur); |
620 | | | 620 | |
621 | curlen = 0; | | 621 | curlen = 0; |
622 | const ohci_physaddr_t sdataphys = DMAADDR(dma, curoffs); | | 622 | const ohci_physaddr_t sdataphys = DMAADDR(dma, curoffs); |
623 | ohci_physaddr_t edataphys = DMAADDR(dma, curoffs + len - 1); | | 623 | ohci_physaddr_t edataphys = DMAADDR(dma, curoffs + len - 1); |
624 | | | 624 | |
625 | const ohci_physaddr_t sphyspg = OHCI_PAGE(sdataphys); | | 625 | const ohci_physaddr_t sphyspg = OHCI_PAGE(sdataphys); |
626 | ohci_physaddr_t ephyspg = OHCI_PAGE(edataphys); | | 626 | ohci_physaddr_t ephyspg = OHCI_PAGE(edataphys); |
627 | /* | | 627 | /* |
628 | * The OHCI hardware can handle at most one page | | 628 | * The OHCI hardware can handle at most one page |
629 | * crossing per TD | | 629 | * crossing per TD |
630 | */ | | 630 | */ |
631 | curlen = len; | | 631 | curlen = len; |
632 | if (sphyspg != ephyspg && | | 632 | if (sphyspg != ephyspg && |
633 | sphyspg + OHCI_PAGE_SIZE != ephyspg) { | | 633 | sphyspg + OHCI_PAGE_SIZE != ephyspg) { |
634 | /* must use multiple TDs, fill as much as possible. */ | | 634 | /* must use multiple TDs, fill as much as possible. */ |
635 | curlen = 2 * OHCI_PAGE_SIZE - | | 635 | curlen = 2 * OHCI_PAGE_SIZE - |
636 | OHCI_PAGE_OFFSET(sdataphys); | | 636 | OHCI_PAGE_OFFSET(sdataphys); |
637 | /* the length must be a multiple of the max size */ | | 637 | /* the length must be a multiple of the max size */ |
638 | curlen -= curlen % mps; | | 638 | curlen -= curlen % mps; |
639 | edataphys = DMAADDR(dma, curoffs + curlen - 1); | | 639 | edataphys = DMAADDR(dma, curoffs + curlen - 1); |
640 | } | | 640 | } |
641 | KASSERT(curlen != 0); | | 641 | KASSERT(curlen != 0); |
642 | DPRINTFN(4, "sdataphys=0x%08jx edataphys=0x%08jx " | | 642 | DPRINTFN(4, "sdataphys=0x%08jx edataphys=0x%08jx " |
643 | "len=%jd curlen=%jd", sdataphys, edataphys, len, curlen); | | 643 | "len=%jd curlen=%jd", sdataphys, edataphys, len, curlen); |
644 | | | 644 | |
645 | cur->td.td_flags = tdflags; | | 645 | cur->td.td_flags = tdflags; |
646 | cur->td.td_cbp = HTOO32(sdataphys); | | 646 | cur->td.td_cbp = HTOO32(sdataphys); |
647 | cur->td.td_be = HTOO32(edataphys); | | 647 | cur->td.td_be = HTOO32(edataphys); |
648 | cur->td.td_nexttd = (next != NULL) ? HTOO32(next->physaddr) : 0; | | 648 | cur->td.td_nexttd = (next != NULL) ? HTOO32(next->physaddr) : 0; |
649 | cur->nexttd = next; | | 649 | cur->nexttd = next; |
650 | cur->len = curlen; | | 650 | cur->len = curlen; |
651 | cur->flags = OHCI_ADD_LEN; | | 651 | cur->flags = OHCI_ADD_LEN; |
652 | cur->xfer = xfer; | | 652 | cur->xfer = xfer; |
653 | ohci_hash_add_td(sc, cur); | | 653 | ohci_hash_add_td(sc, cur); |
654 | | | 654 | |
655 | curoffs += curlen; | | 655 | curoffs += curlen; |
656 | len -= curlen; | | 656 | len -= curlen; |
657 | | | 657 | |
658 | if (len != 0) { | | 658 | if (len != 0) { |
659 | KASSERT(next != NULL); | | 659 | KASSERT(next != NULL); |
660 | DPRINTFN(10, "extend chain", 0, 0, 0, 0); | | 660 | DPRINTFN(10, "extend chain", 0, 0, 0, 0); |
661 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), | | 661 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), |
662 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 662 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
663 | | | 663 | |
664 | cur = next; | | 664 | cur = next; |
665 | } | | 665 | } |
666 | } | | 666 | } |
667 | cur->td.td_flags |= | | 667 | cur->td.td_flags |= |
668 | HTOO32(xfer->ux_flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0); | | 668 | HTOO32(xfer->ux_flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0); |
669 | | | 669 | |
670 | if (!rd && | | 670 | if (!rd && |
671 | (flags & USBD_FORCE_SHORT_XFER) && | | 671 | (flags & USBD_FORCE_SHORT_XFER) && |
672 | alen % mps == 0) { | | 672 | alen % mps == 0) { |
673 | /* We're adding a ZLP so sync the previous TD */ | | 673 | /* We're adding a ZLP so sync the previous TD */ |
674 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), | | 674 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), |
675 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 675 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
676 | | | 676 | |
677 | /* Force a 0 length transfer at the end. */ | | 677 | /* Force a 0 length transfer at the end. */ |
678 | | | 678 | |
679 | KASSERT(next != NULL); | | 679 | KASSERT(next != NULL); |
680 | cur = next; | | 680 | cur = next; |
681 | | | 681 | |
682 | cur->td.td_flags = tdflags; | | 682 | cur->td.td_flags = tdflags; |
683 | cur->td.td_cbp = 0; /* indicate 0 length packet */ | | 683 | cur->td.td_cbp = 0; /* indicate 0 length packet */ |
684 | cur->td.td_nexttd = 0; | | 684 | cur->td.td_nexttd = 0; |
685 | cur->td.td_be = ~0; | | 685 | cur->td.td_be = ~0; |
686 | cur->nexttd = NULL; | | 686 | cur->nexttd = NULL; |
687 | cur->len = 0; | | 687 | cur->len = 0; |
688 | cur->flags = 0; | | 688 | cur->flags = 0; |
689 | cur->xfer = xfer; | | 689 | cur->xfer = xfer; |
690 | ohci_hash_add_td(sc, cur); | | 690 | ohci_hash_add_td(sc, cur); |
691 | | | 691 | |
692 | DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0); | | 692 | DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0); |
693 | } | | 693 | } |
694 | | | 694 | |
695 | /* Last TD gets usb_syncmem'ed by caller */ | | 695 | /* Last TD gets usb_syncmem'ed by caller */ |
696 | *ep = cur; | | 696 | *ep = cur; |
697 | } | | 697 | } |
698 | | | 698 | |
699 | ohci_soft_itd_t * | | 699 | ohci_soft_itd_t * |
700 | ohci_alloc_sitd(ohci_softc_t *sc) | | 700 | ohci_alloc_sitd(ohci_softc_t *sc) |
701 | { | | 701 | { |
702 | ohci_soft_itd_t *sitd; | | 702 | ohci_soft_itd_t *sitd; |
703 | usbd_status err; | | 703 | usbd_status err; |
704 | int i, offs; | | 704 | int i, offs; |
705 | usb_dma_t dma; | | 705 | usb_dma_t dma; |
706 | | | 706 | |
707 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 707 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
708 | | | 708 | |
709 | mutex_enter(&sc->sc_lock); | | 709 | mutex_enter(&sc->sc_lock); |
710 | if (sc->sc_freeitds == NULL) { | | 710 | if (sc->sc_freeitds == NULL) { |
711 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); | | 711 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); |
712 | mutex_exit(&sc->sc_lock); | | 712 | mutex_exit(&sc->sc_lock); |
713 | | | 713 | |
714 | err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK, | | 714 | err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK, |
715 | OHCI_ITD_ALIGN, &dma); | | 715 | OHCI_ITD_ALIGN, &dma); |
716 | if (err) | | 716 | if (err) |
717 | return NULL; | | 717 | return NULL; |
718 | mutex_enter(&sc->sc_lock); | | 718 | mutex_enter(&sc->sc_lock); |
719 | for (i = 0; i < OHCI_SITD_CHUNK; i++) { | | 719 | for (i = 0; i < OHCI_SITD_CHUNK; i++) { |
720 | offs = i * OHCI_SITD_SIZE; | | 720 | offs = i * OHCI_SITD_SIZE; |
721 | sitd = KERNADDR(&dma, offs); | | 721 | sitd = KERNADDR(&dma, offs); |
722 | sitd->physaddr = DMAADDR(&dma, offs); | | 722 | sitd->physaddr = DMAADDR(&dma, offs); |
723 | sitd->dma = dma; | | 723 | sitd->dma = dma; |
724 | sitd->offs = offs; | | 724 | sitd->offs = offs; |
725 | sitd->nextitd = sc->sc_freeitds; | | 725 | sitd->nextitd = sc->sc_freeitds; |
726 | sc->sc_freeitds = sitd; | | 726 | sc->sc_freeitds = sitd; |
727 | } | | 727 | } |
728 | } | | 728 | } |
729 | | | 729 | |
730 | sitd = sc->sc_freeitds; | | 730 | sitd = sc->sc_freeitds; |
731 | sc->sc_freeitds = sitd->nextitd; | | 731 | sc->sc_freeitds = sitd->nextitd; |
732 | mutex_exit(&sc->sc_lock); | | 732 | mutex_exit(&sc->sc_lock); |
733 | | | 733 | |
734 | memset(&sitd->itd, 0, sizeof(ohci_itd_t)); | | 734 | memset(&sitd->itd, 0, sizeof(ohci_itd_t)); |
735 | sitd->nextitd = NULL; | | 735 | sitd->nextitd = NULL; |
736 | sitd->xfer = NULL; | | 736 | sitd->xfer = NULL; |
737 | | | 737 | |
738 | #ifdef DIAGNOSTIC | | 738 | #ifdef DIAGNOSTIC |
739 | sitd->isdone = true; | | 739 | sitd->isdone = true; |
740 | #endif | | 740 | #endif |
741 | | | 741 | |
742 | return sitd; | | 742 | return sitd; |
743 | } | | 743 | } |
744 | | | 744 | |
745 | Static void | | 745 | Static void |
746 | ohci_free_sitd_locked(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | | 746 | ohci_free_sitd_locked(ohci_softc_t *sc, ohci_soft_itd_t *sitd) |
747 | { | | 747 | { |
748 | | | 748 | |
749 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 749 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
750 | DPRINTFN(10, "sitd=%#jx", (uintptr_t)sitd, 0, 0, 0); | | 750 | DPRINTFN(10, "sitd=%#jx", (uintptr_t)sitd, 0, 0, 0); |
751 | | | 751 | |
752 | KASSERT(sitd->isdone); | | 752 | KASSERT(sitd->isdone); |
753 | #ifdef DIAGNOSTIC | | 753 | #ifdef DIAGNOSTIC |
754 | /* Warn double free */ | | 754 | /* Warn double free */ |
755 | sitd->isdone = false; | | 755 | sitd->isdone = false; |
756 | #endif | | 756 | #endif |
757 | | | 757 | |
758 | sitd->nextitd = sc->sc_freeitds; | | 758 | sitd->nextitd = sc->sc_freeitds; |
759 | sc->sc_freeitds = sitd; | | 759 | sc->sc_freeitds = sitd; |
760 | } | | 760 | } |
761 | | | 761 | |
762 | void | | 762 | void |
763 | ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | | 763 | ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) |
764 | { | | 764 | { |
765 | | | 765 | |
766 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 766 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
767 | | | 767 | |
768 | mutex_enter(&sc->sc_lock); | | 768 | mutex_enter(&sc->sc_lock); |
769 | ohci_free_sitd_locked(sc, sitd); | | 769 | ohci_free_sitd_locked(sc, sitd); |
770 | mutex_exit(&sc->sc_lock); | | 770 | mutex_exit(&sc->sc_lock); |
771 | } | | 771 | } |
772 | | | 772 | |
773 | int | | 773 | int |
774 | ohci_init(ohci_softc_t *sc) | | 774 | ohci_init(ohci_softc_t *sc) |
775 | { | | 775 | { |
776 | ohci_soft_ed_t *sed, *psed; | | 776 | ohci_soft_ed_t *sed, *psed; |
777 | usbd_status err; | | 777 | usbd_status err; |
778 | int i; | | 778 | int i; |
779 | uint32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca /*, descb */; | | 779 | uint32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca /*, descb */; |
780 | | | 780 | |
781 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 781 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
782 | | | 782 | |
783 | aprint_normal_dev(sc->sc_dev, ""); | | 783 | aprint_normal_dev(sc->sc_dev, ""); |
784 | | | 784 | |
785 | sc->sc_hcca = NULL; | | 785 | sc->sc_hcca = NULL; |
786 | callout_init(&sc->sc_tmo_rhsc, CALLOUT_MPSAFE); | | 786 | callout_init(&sc->sc_tmo_rhsc, CALLOUT_MPSAFE); |
787 | | | 787 | |
788 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | | 788 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); |
789 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | | 789 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); |
790 | | | 790 | |
791 | sc->sc_rhsc_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE, | | 791 | sc->sc_rhsc_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE, |
792 | ohci_rhsc_softint, sc); | | 792 | ohci_rhsc_softint, sc); |
793 | | | 793 | |
794 | for (i = 0; i < OHCI_HASH_SIZE; i++) | | 794 | for (i = 0; i < OHCI_HASH_SIZE; i++) |
795 | LIST_INIT(&sc->sc_hash_tds[i]); | | 795 | LIST_INIT(&sc->sc_hash_tds[i]); |
796 | for (i = 0; i < OHCI_HASH_SIZE; i++) | | 796 | for (i = 0; i < OHCI_HASH_SIZE; i++) |
797 | LIST_INIT(&sc->sc_hash_itds[i]); | | 797 | LIST_INIT(&sc->sc_hash_itds[i]); |
798 | | | 798 | |
799 | sc->sc_xferpool = pool_cache_init(sizeof(struct ohci_xfer), 0, 0, 0, | | 799 | sc->sc_xferpool = pool_cache_init(sizeof(struct ohci_xfer), 0, 0, 0, |
800 | "ohcixfer", NULL, IPL_USB, NULL, NULL, NULL); | | 800 | "ohcixfer", NULL, IPL_USB, NULL, NULL, NULL); |
801 | | | 801 | |
802 | rev = OREAD4(sc, OHCI_REVISION); | | 802 | rev = OREAD4(sc, OHCI_REVISION); |
803 | aprint_normal("OHCI version %d.%d%s\n", | | 803 | aprint_normal("OHCI version %d.%d%s\n", |
804 | OHCI_REV_HI(rev), OHCI_REV_LO(rev), | | 804 | OHCI_REV_HI(rev), OHCI_REV_LO(rev), |
805 | OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); | | 805 | OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); |
806 | | | 806 | |
807 | if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { | | 807 | if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { |
808 | aprint_error_dev(sc->sc_dev, "unsupported OHCI revision\n"); | | 808 | aprint_error_dev(sc->sc_dev, "unsupported OHCI revision\n"); |
809 | sc->sc_bus.ub_revision = USBREV_UNKNOWN; | | 809 | sc->sc_bus.ub_revision = USBREV_UNKNOWN; |
810 | return -1; | | 810 | return -1; |
811 | } | | 811 | } |
812 | sc->sc_bus.ub_revision = USBREV_1_0; | | 812 | sc->sc_bus.ub_revision = USBREV_1_0; |
813 | sc->sc_bus.ub_usedma = true; | | 813 | sc->sc_bus.ub_usedma = true; |
814 | | | 814 | |
815 | /* XXX determine alignment by R/W */ | | 815 | /* XXX determine alignment by R/W */ |
816 | /* Allocate the HCCA area. */ | | 816 | /* Allocate the HCCA area. */ |
817 | err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, | | 817 | err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, |
818 | OHCI_HCCA_ALIGN, &sc->sc_hccadma); | | 818 | OHCI_HCCA_ALIGN, &sc->sc_hccadma); |
819 | if (err) { | | 819 | if (err) { |
820 | sc->sc_hcca = NULL; | | 820 | sc->sc_hcca = NULL; |
821 | return err; | | 821 | return err; |
822 | } | | 822 | } |
823 | sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0); | | 823 | sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0); |
824 | memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE); | | 824 | memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE); |
825 | | | 825 | |
826 | sc->sc_eintrs = OHCI_NORMAL_INTRS; | | 826 | sc->sc_eintrs = OHCI_NORMAL_INTRS; |
827 | | | 827 | |
828 | /* Allocate dummy ED that starts the control list. */ | | 828 | /* Allocate dummy ED that starts the control list. */ |
829 | sc->sc_ctrl_head = ohci_alloc_sed(sc); | | 829 | sc->sc_ctrl_head = ohci_alloc_sed(sc); |
830 | if (sc->sc_ctrl_head == NULL) { | | 830 | if (sc->sc_ctrl_head == NULL) { |
831 | err = ENOMEM; | | 831 | err = ENOMEM; |
832 | goto bad1; | | 832 | goto bad1; |
833 | } | | 833 | } |
834 | sc->sc_ctrl_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 834 | sc->sc_ctrl_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
835 | | | 835 | |
836 | /* Allocate dummy ED that starts the bulk list. */ | | 836 | /* Allocate dummy ED that starts the bulk list. */ |
837 | sc->sc_bulk_head = ohci_alloc_sed(sc); | | 837 | sc->sc_bulk_head = ohci_alloc_sed(sc); |
838 | if (sc->sc_bulk_head == NULL) { | | 838 | if (sc->sc_bulk_head == NULL) { |
839 | err = ENOMEM; | | 839 | err = ENOMEM; |
840 | goto bad2; | | 840 | goto bad2; |
841 | } | | 841 | } |
842 | sc->sc_bulk_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 842 | sc->sc_bulk_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
843 | usb_syncmem(&sc->sc_bulk_head->dma, sc->sc_bulk_head->offs, | | 843 | usb_syncmem(&sc->sc_bulk_head->dma, sc->sc_bulk_head->offs, |
844 | sizeof(sc->sc_bulk_head->ed), | | 844 | sizeof(sc->sc_bulk_head->ed), |
845 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 845 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
846 | | | 846 | |
847 | /* Allocate dummy ED that starts the isochronous list. */ | | 847 | /* Allocate dummy ED that starts the isochronous list. */ |
848 | sc->sc_isoc_head = ohci_alloc_sed(sc); | | 848 | sc->sc_isoc_head = ohci_alloc_sed(sc); |
849 | if (sc->sc_isoc_head == NULL) { | | 849 | if (sc->sc_isoc_head == NULL) { |
850 | err = ENOMEM; | | 850 | err = ENOMEM; |
851 | goto bad3; | | 851 | goto bad3; |
852 | } | | 852 | } |
853 | sc->sc_isoc_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 853 | sc->sc_isoc_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
854 | usb_syncmem(&sc->sc_isoc_head->dma, sc->sc_isoc_head->offs, | | 854 | usb_syncmem(&sc->sc_isoc_head->dma, sc->sc_isoc_head->offs, |
855 | sizeof(sc->sc_isoc_head->ed), | | 855 | sizeof(sc->sc_isoc_head->ed), |
856 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 856 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
857 | | | 857 | |
858 | /* Allocate all the dummy EDs that make up the interrupt tree. */ | | 858 | /* Allocate all the dummy EDs that make up the interrupt tree. */ |
859 | for (i = 0; i < OHCI_NO_EDS; i++) { | | 859 | for (i = 0; i < OHCI_NO_EDS; i++) { |
860 | sed = ohci_alloc_sed(sc); | | 860 | sed = ohci_alloc_sed(sc); |
861 | if (sed == NULL) { | | 861 | if (sed == NULL) { |
862 | while (--i >= 0) | | 862 | while (--i >= 0) |
863 | ohci_free_sed(sc, sc->sc_eds[i]); | | 863 | ohci_free_sed(sc, sc->sc_eds[i]); |
864 | err = ENOMEM; | | 864 | err = ENOMEM; |
865 | goto bad4; | | 865 | goto bad4; |
866 | } | | 866 | } |
867 | /* All ED fields are set to 0. */ | | 867 | /* All ED fields are set to 0. */ |
868 | sc->sc_eds[i] = sed; | | 868 | sc->sc_eds[i] = sed; |
869 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 869 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
870 | if (i != 0) | | 870 | if (i != 0) |
871 | psed = sc->sc_eds[(i-1) / 2]; | | 871 | psed = sc->sc_eds[(i-1) / 2]; |
872 | else | | 872 | else |
873 | psed= sc->sc_isoc_head; | | 873 | psed= sc->sc_isoc_head; |
874 | sed->next = psed; | | 874 | sed->next = psed; |
875 | sed->ed.ed_nexted = HTOO32(psed->physaddr); | | 875 | sed->ed.ed_nexted = HTOO32(psed->physaddr); |
876 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 876 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
877 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 877 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
878 | } | | 878 | } |
879 | /* | | 879 | /* |
880 | * Fill HCCA interrupt table. The bit reversal is to get | | 880 | * Fill HCCA interrupt table. The bit reversal is to get |
881 | * the tree set up properly to spread the interrupts. | | 881 | * the tree set up properly to spread the interrupts. |
882 | */ | | 882 | */ |
883 | for (i = 0; i < OHCI_NO_INTRS; i++) | | 883 | for (i = 0; i < OHCI_NO_INTRS; i++) |
884 | sc->sc_hcca->hcca_interrupt_table[revbits[i]] = | | 884 | sc->sc_hcca->hcca_interrupt_table[revbits[i]] = |
885 | HTOO32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); | | 885 | HTOO32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); |
886 | usb_syncmem(&sc->sc_hccadma, 0, OHCI_HCCA_SIZE, | | 886 | usb_syncmem(&sc->sc_hccadma, 0, OHCI_HCCA_SIZE, |
887 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 887 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
888 | | | 888 | |
889 | #ifdef OHCI_DEBUG | | 889 | #ifdef OHCI_DEBUG |
890 | DPRINTFN(15, "--- dump start ---", 0, 0, 0 ,0); | | 890 | DPRINTFN(15, "--- dump start ---", 0, 0, 0 ,0); |
891 | if (ohcidebug >= 15) { | | 891 | if (ohcidebug >= 15) { |
892 | for (i = 0; i < OHCI_NO_EDS; i++) { | | 892 | for (i = 0; i < OHCI_NO_EDS; i++) { |
893 | DPRINTFN(15, "ed#%jd ", i, 0, 0, 0); | | 893 | DPRINTFN(15, "ed#%jd ", i, 0, 0, 0); |
894 | ohci_dump_ed(sc, sc->sc_eds[i]); | | 894 | ohci_dump_ed(sc, sc->sc_eds[i]); |
895 | } | | 895 | } |
896 | DPRINTFN(15, "iso", 0, 0, 0 ,0); | | 896 | DPRINTFN(15, "iso", 0, 0, 0 ,0); |
897 | ohci_dump_ed(sc, sc->sc_isoc_head); | | 897 | ohci_dump_ed(sc, sc->sc_isoc_head); |
898 | } | | 898 | } |
899 | DPRINTFN(15, "--- dump end ---", 0, 0, 0 ,0); | | 899 | DPRINTFN(15, "--- dump end ---", 0, 0, 0 ,0); |
900 | #endif | | 900 | #endif |
901 | | | 901 | |
902 | /* Preserve values programmed by SMM/BIOS but lost over reset. */ | | 902 | /* Preserve values programmed by SMM/BIOS but lost over reset. */ |
903 | ctl = OREAD4(sc, OHCI_CONTROL); | | 903 | ctl = OREAD4(sc, OHCI_CONTROL); |
904 | rwc = ctl & OHCI_RWC; | | 904 | rwc = ctl & OHCI_RWC; |
905 | fm = OREAD4(sc, OHCI_FM_INTERVAL); | | 905 | fm = OREAD4(sc, OHCI_FM_INTERVAL); |
906 | desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); | | 906 | desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); |
907 | /* descb = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); */ | | 907 | /* descb = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); */ |
908 | | | 908 | |
909 | /* Determine in what context we are running. */ | | 909 | /* Determine in what context we are running. */ |
910 | if (ctl & OHCI_IR) { | | 910 | if (ctl & OHCI_IR) { |
911 | /* SMM active, request change */ | | 911 | /* SMM active, request change */ |
912 | DPRINTF("SMM active, request owner change", 0, 0, 0, 0); | | 912 | DPRINTF("SMM active, request owner change", 0, 0, 0, 0); |
913 | if ((sc->sc_intre & (OHCI_OC | OHCI_MIE)) == | | 913 | if ((sc->sc_intre & (OHCI_OC | OHCI_MIE)) == |
914 | (OHCI_OC | OHCI_MIE)) | | 914 | (OHCI_OC | OHCI_MIE)) |
915 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_MIE); | | 915 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_MIE); |
916 | s = OREAD4(sc, OHCI_COMMAND_STATUS); | | 916 | s = OREAD4(sc, OHCI_COMMAND_STATUS); |
917 | OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR); | | 917 | OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR); |
918 | for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { | | 918 | for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { |
919 | usb_delay_ms(&sc->sc_bus, 1); | | 919 | usb_delay_ms(&sc->sc_bus, 1); |
920 | ctl = OREAD4(sc, OHCI_CONTROL); | | 920 | ctl = OREAD4(sc, OHCI_CONTROL); |
921 | } | | 921 | } |
922 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_MIE); | | 922 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_MIE); |
923 | if ((ctl & OHCI_IR) == 0) { | | 923 | if ((ctl & OHCI_IR) == 0) { |
924 | aprint_error_dev(sc->sc_dev, | | 924 | aprint_error_dev(sc->sc_dev, |
925 | "SMM does not respond, resetting\n"); | | 925 | "SMM does not respond, resetting\n"); |
926 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); | | 926 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); |
927 | goto reset; | | 927 | goto reset; |
928 | } | | 928 | } |
929 | #if 0 | | 929 | #if 0 |
930 | /* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */ | | 930 | /* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */ |
931 | } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { | | 931 | } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { |
932 | /* BIOS started controller. */ | | 932 | /* BIOS started controller. */ |
933 | DPRINTF("BIOS active", 0, 0, 0, 0); | | 933 | DPRINTF("BIOS active", 0, 0, 0, 0); |
934 | if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) { | | 934 | if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) { |
935 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL | rwc); | | 935 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL | rwc); |
936 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | | 936 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); |
937 | } | | 937 | } |
938 | #endif | | 938 | #endif |
939 | } else { | | 939 | } else { |
940 | DPRINTF("cold started", 0 ,0 ,0 ,0); | | 940 | DPRINTF("cold started", 0 ,0 ,0 ,0); |
941 | reset: | | 941 | reset: |
942 | /* Controller was cold started. */ | | 942 | /* Controller was cold started. */ |
943 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); | | 943 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); |
944 | } | | 944 | } |
945 | | | 945 | |
946 | /* | | 946 | /* |
947 | * This reset should not be necessary according to the OHCI spec, but | | 947 | * This reset should not be necessary according to the OHCI spec, but |
948 | * without it some controllers do not start. | | 948 | * without it some controllers do not start. |
949 | */ | | 949 | */ |
950 | DPRINTF("sc %#jx: resetting", (uintptr_t)sc, 0, 0, 0); | | 950 | DPRINTF("sc %#jx: resetting", (uintptr_t)sc, 0, 0, 0); |
951 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); | | 951 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); |
952 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); | | 952 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); |
953 | | | 953 | |
954 | /* We now own the host controller and the bus has been reset. */ | | 954 | /* We now own the host controller and the bus has been reset. */ |
955 | | | 955 | |
956 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ | | 956 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ |
957 | /* Nominal time for a reset is 10 us. */ | | 957 | /* Nominal time for a reset is 10 us. */ |
958 | for (i = 0; i < 10; i++) { | | 958 | for (i = 0; i < 10; i++) { |
959 | delay(10); | | 959 | delay(10); |
960 | hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; | | 960 | hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; |
961 | if (!hcr) | | 961 | if (!hcr) |
962 | break; | | 962 | break; |
963 | } | | 963 | } |
964 | if (hcr) { | | 964 | if (hcr) { |
965 | aprint_error_dev(sc->sc_dev, "reset timeout\n"); | | 965 | aprint_error_dev(sc->sc_dev, "reset timeout\n"); |
966 | err = EIO; | | 966 | err = EIO; |
967 | goto bad5; | | 967 | goto bad5; |
968 | } | | 968 | } |
969 | #ifdef OHCI_DEBUG | | 969 | #ifdef OHCI_DEBUG |
970 | if (ohcidebug >= 15) | | 970 | if (ohcidebug >= 15) |
971 | ohci_dumpregs(sc); | | 971 | ohci_dumpregs(sc); |
972 | #endif | | 972 | #endif |
973 | | | 973 | |
974 | /* The controller is now in SUSPEND state, we have 2ms to finish. */ | | 974 | /* The controller is now in SUSPEND state, we have 2ms to finish. */ |
975 | | | 975 | |
976 | /* Set up HC registers. */ | | 976 | /* Set up HC registers. */ |
977 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); | | 977 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); |
978 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); | | 978 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); |
979 | OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); | | 979 | OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); |
980 | /* disable all interrupts and then switch on all desired interrupts */ | | 980 | /* disable all interrupts and then switch on all desired interrupts */ |
981 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); | | 981 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); |
982 | /* switch on desired functional features */ | | 982 | /* switch on desired functional features */ |
983 | ctl = OREAD4(sc, OHCI_CONTROL); | | 983 | ctl = OREAD4(sc, OHCI_CONTROL); |
984 | ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); | | 984 | ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); |
985 | ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | | | 985 | ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | |
986 | OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL | rwc; | | 986 | OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL | rwc; |
987 | /* And finally start it! */ | | 987 | /* And finally start it! */ |
988 | OWRITE4(sc, OHCI_CONTROL, ctl); | | 988 | OWRITE4(sc, OHCI_CONTROL, ctl); |
989 | | | 989 | |
990 | /* | | 990 | /* |
991 | * The controller is now OPERATIONAL. Set a some final | | 991 | * The controller is now OPERATIONAL. Set a some final |
992 | * registers that should be set earlier, but that the | | 992 | * registers that should be set earlier, but that the |
993 | * controller ignores when in the SUSPEND state. | | 993 | * controller ignores when in the SUSPEND state. |
994 | */ | | 994 | */ |
995 | ival = OHCI_GET_IVAL(fm); | | 995 | ival = OHCI_GET_IVAL(fm); |
996 | fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; | | 996 | fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; |
997 | fm |= OHCI_FSMPS(ival) | ival; | | 997 | fm |= OHCI_FSMPS(ival) | ival; |
998 | OWRITE4(sc, OHCI_FM_INTERVAL, fm); | | 998 | OWRITE4(sc, OHCI_FM_INTERVAL, fm); |
999 | per = OHCI_PERIODIC(ival); /* 90% periodic */ | | 999 | per = OHCI_PERIODIC(ival); /* 90% periodic */ |
1000 | OWRITE4(sc, OHCI_PERIODIC_START, per); | | 1000 | OWRITE4(sc, OHCI_PERIODIC_START, per); |
1001 | | | 1001 | |
1002 | if (sc->sc_flags & OHCIF_SUPERIO) { | | 1002 | if (sc->sc_flags & OHCIF_SUPERIO) { |
1003 | /* no overcurrent protection */ | | 1003 | /* no overcurrent protection */ |
1004 | desca |= OHCI_NOCP; | | 1004 | desca |= OHCI_NOCP; |
1005 | /* | | 1005 | /* |
1006 | * Clear NoPowerSwitching and PowerOnToPowerGoodTime meaning | | 1006 | * Clear NoPowerSwitching and PowerOnToPowerGoodTime meaning |
1007 | * that | | 1007 | * that |
1008 | * - ports are always power switched | | 1008 | * - ports are always power switched |
1009 | * - don't wait for powered root hub port | | 1009 | * - don't wait for powered root hub port |
1010 | */ | | 1010 | */ |
1011 | desca &= ~(__SHIFTIN(0xff, OHCI_POTPGT_MASK) | OHCI_NPS); | | 1011 | desca &= ~(__SHIFTIN(0xff, OHCI_POTPGT_MASK) | OHCI_NPS); |
1012 | } | | 1012 | } |
1013 | | | 1013 | |
1014 | /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ | | 1014 | /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ |
1015 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); | | 1015 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); |
1016 | OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ | | 1016 | OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ |
1017 | usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY); | | 1017 | usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY); |
1018 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); | | 1018 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); |
1019 | | | 1019 | |
1020 | /* | | 1020 | /* |
1021 | * The AMD756 requires a delay before re-reading the register, | | 1021 | * The AMD756 requires a delay before re-reading the register, |
1022 | * otherwise it will occasionally report 0 ports. | | 1022 | * otherwise it will occasionally report 0 ports. |
1023 | */ | | 1023 | */ |
1024 | sc->sc_noport = 0; | | 1024 | sc->sc_noport = 0; |
1025 | for (i = 0; i < 10 && sc->sc_noport == 0; i++) { | | 1025 | for (i = 0; i < 10 && sc->sc_noport == 0; i++) { |
1026 | usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY); | | 1026 | usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY); |
1027 | sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); | | 1027 | sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); |
1028 | } | | 1028 | } |
1029 | | | 1029 | |
1030 | #ifdef OHCI_DEBUG | | 1030 | #ifdef OHCI_DEBUG |
1031 | if (ohcidebug >= 5) | | 1031 | if (ohcidebug >= 5) |
1032 | ohci_dumpregs(sc); | | 1032 | ohci_dumpregs(sc); |
1033 | #endif | | 1033 | #endif |
1034 | | | 1034 | |
1035 | /* Set up the bus struct. */ | | 1035 | /* Set up the bus struct. */ |
1036 | sc->sc_bus.ub_methods = &ohci_bus_methods; | | 1036 | sc->sc_bus.ub_methods = &ohci_bus_methods; |
1037 | sc->sc_bus.ub_pipesize = sizeof(struct ohci_pipe); | | 1037 | sc->sc_bus.ub_pipesize = sizeof(struct ohci_pipe); |
1038 | | | 1038 | |
1039 | sc->sc_control = sc->sc_intre = 0; | | 1039 | sc->sc_control = sc->sc_intre = 0; |
1040 | | | 1040 | |
1041 | /* Finally, turn on interrupts. */ | | 1041 | /* Finally, turn on interrupts. */ |
1042 | DPRINTF("enabling %#jx", sc->sc_eintrs | OHCI_MIE, 0, 0, 0); | | 1042 | DPRINTF("enabling %#jx", sc->sc_eintrs | OHCI_MIE, 0, 0, 0); |
1043 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); | | 1043 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); |
1044 | | | 1044 | |
1045 | return 0; | | 1045 | return 0; |
1046 | | | 1046 | |
1047 | bad5: | | 1047 | bad5: |
1048 | for (i = 0; i < OHCI_NO_EDS; i++) | | 1048 | for (i = 0; i < OHCI_NO_EDS; i++) |
1049 | ohci_free_sed(sc, sc->sc_eds[i]); | | 1049 | ohci_free_sed(sc, sc->sc_eds[i]); |
1050 | bad4: | | 1050 | bad4: |
1051 | ohci_free_sed(sc, sc->sc_isoc_head); | | 1051 | ohci_free_sed(sc, sc->sc_isoc_head); |
1052 | bad3: | | 1052 | bad3: |
1053 | ohci_free_sed(sc, sc->sc_bulk_head); | | 1053 | ohci_free_sed(sc, sc->sc_bulk_head); |
1054 | bad2: | | 1054 | bad2: |
1055 | ohci_free_sed(sc, sc->sc_ctrl_head); | | 1055 | ohci_free_sed(sc, sc->sc_ctrl_head); |
1056 | bad1: | | 1056 | bad1: |
1057 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | | 1057 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); |
1058 | sc->sc_hcca = NULL; | | 1058 | sc->sc_hcca = NULL; |
1059 | return err; | | 1059 | return err; |
1060 | } | | 1060 | } |
1061 | | | 1061 | |
1062 | struct usbd_xfer * | | 1062 | struct usbd_xfer * |
1063 | ohci_allocx(struct usbd_bus *bus, unsigned int nframes) | | 1063 | ohci_allocx(struct usbd_bus *bus, unsigned int nframes) |
1064 | { | | 1064 | { |
1065 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | | 1065 | ohci_softc_t *sc = OHCI_BUS2SC(bus); |
1066 | struct usbd_xfer *xfer; | | 1066 | struct usbd_xfer *xfer; |
1067 | | | 1067 | |
1068 | xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); | | 1068 | xfer = pool_cache_get(sc->sc_xferpool, PR_WAITOK); |
1069 | if (xfer != NULL) { | | 1069 | if (xfer != NULL) { |
1070 | memset(xfer, 0, sizeof(struct ohci_xfer)); | | 1070 | memset(xfer, 0, sizeof(struct ohci_xfer)); |
1071 | | | 1071 | |
1072 | #ifdef DIAGNOSTIC | | 1072 | #ifdef DIAGNOSTIC |
1073 | xfer->ux_state = XFER_BUSY; | | 1073 | xfer->ux_state = XFER_BUSY; |
1074 | #endif | | 1074 | #endif |
1075 | } | | 1075 | } |
1076 | return xfer; | | 1076 | return xfer; |
1077 | } | | 1077 | } |
1078 | | | 1078 | |
1079 | void | | 1079 | void |
1080 | ohci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | | 1080 | ohci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) |
1081 | { | | 1081 | { |
1082 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | | 1082 | ohci_softc_t *sc = OHCI_BUS2SC(bus); |
1083 | | | 1083 | |
1084 | KASSERTMSG(xfer->ux_state == XFER_BUSY || | | 1084 | KASSERTMSG(xfer->ux_state == XFER_BUSY || |
1085 | xfer->ux_status == USBD_NOT_STARTED, | | 1085 | xfer->ux_status == USBD_NOT_STARTED, |
1086 | "xfer=%p not busy, 0x%08x\n", xfer, xfer->ux_state); | | 1086 | "xfer=%p not busy, 0x%08x\n", xfer, xfer->ux_state); |
1087 | #ifdef DIAGNOSTIC | | 1087 | #ifdef DIAGNOSTIC |
1088 | xfer->ux_state = XFER_FREE; | | 1088 | xfer->ux_state = XFER_FREE; |
1089 | #endif | | 1089 | #endif |
1090 | pool_cache_put(sc->sc_xferpool, xfer); | | 1090 | pool_cache_put(sc->sc_xferpool, xfer); |
1091 | } | | 1091 | } |
1092 | | | 1092 | |
1093 | Static bool | | 1093 | Static bool |
1094 | ohci_dying(struct usbd_bus *bus) | | 1094 | ohci_dying(struct usbd_bus *bus) |
1095 | { | | 1095 | { |
1096 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | | 1096 | ohci_softc_t *sc = OHCI_BUS2SC(bus); |
1097 | | | 1097 | |
1098 | return sc->sc_dying; | | 1098 | return sc->sc_dying; |
1099 | } | | 1099 | } |
1100 | | | 1100 | |
1101 | Static void | | 1101 | Static void |
1102 | ohci_get_lock(struct usbd_bus *bus, kmutex_t **lock) | | 1102 | ohci_get_lock(struct usbd_bus *bus, kmutex_t **lock) |
1103 | { | | 1103 | { |
1104 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | | 1104 | ohci_softc_t *sc = OHCI_BUS2SC(bus); |
1105 | | | 1105 | |
1106 | *lock = &sc->sc_lock; | | 1106 | *lock = &sc->sc_lock; |
1107 | } | | 1107 | } |
1108 | | | 1108 | |
1109 | /* | | 1109 | /* |
1110 | * Shut down the controller when the system is going down. | | 1110 | * Shut down the controller when the system is going down. |
1111 | */ | | 1111 | */ |
1112 | bool | | 1112 | bool |
1113 | ohci_shutdown(device_t self, int flags) | | 1113 | ohci_shutdown(device_t self, int flags) |
1114 | { | | 1114 | { |
1115 | ohci_softc_t *sc = device_private(self); | | 1115 | ohci_softc_t *sc = device_private(self); |
1116 | | | 1116 | |
1117 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1117 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1118 | | | 1118 | |
1119 | DPRINTF("stopping the HC", 0, 0, 0, 0); | | 1119 | DPRINTF("stopping the HC", 0, 0, 0, 0); |
1120 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); | | 1120 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); |
1121 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); | | 1121 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); |
1122 | return true; | | 1122 | return true; |
1123 | } | | 1123 | } |
1124 | | | 1124 | |
1125 | bool | | 1125 | bool |
1126 | ohci_resume(device_t dv, const pmf_qual_t *qual) | | 1126 | ohci_resume(device_t dv, const pmf_qual_t *qual) |
1127 | { | | 1127 | { |
1128 | ohci_softc_t *sc = device_private(dv); | | 1128 | ohci_softc_t *sc = device_private(dv); |
1129 | uint32_t ctl; | | 1129 | uint32_t ctl; |
1130 | | | 1130 | |
1131 | mutex_spin_enter(&sc->sc_intr_lock); | | 1131 | mutex_spin_enter(&sc->sc_intr_lock); |
1132 | sc->sc_bus.ub_usepolling++; | | 1132 | sc->sc_bus.ub_usepolling++; |
1133 | mutex_spin_exit(&sc->sc_intr_lock); | | 1133 | mutex_spin_exit(&sc->sc_intr_lock); |
1134 | | | 1134 | |
1135 | /* Some broken BIOSes do not recover these values */ | | 1135 | /* Some broken BIOSes do not recover these values */ |
1136 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); | | 1136 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); |
1137 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, | | 1137 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, |
1138 | sc->sc_ctrl_head->physaddr); | | 1138 | sc->sc_ctrl_head->physaddr); |
1139 | OWRITE4(sc, OHCI_BULK_HEAD_ED, | | 1139 | OWRITE4(sc, OHCI_BULK_HEAD_ED, |
1140 | sc->sc_bulk_head->physaddr); | | 1140 | sc->sc_bulk_head->physaddr); |
1141 | if (sc->sc_intre) | | 1141 | if (sc->sc_intre) |
1142 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_intre & | | 1142 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_intre & |
1143 | (OHCI_ALL_INTRS | OHCI_MIE)); | | 1143 | (OHCI_ALL_INTRS | OHCI_MIE)); |
1144 | if (sc->sc_control) | | 1144 | if (sc->sc_control) |
1145 | ctl = sc->sc_control; | | 1145 | ctl = sc->sc_control; |
1146 | else | | 1146 | else |
1147 | ctl = OREAD4(sc, OHCI_CONTROL); | | 1147 | ctl = OREAD4(sc, OHCI_CONTROL); |
1148 | ctl |= OHCI_HCFS_RESUME; | | 1148 | ctl |= OHCI_HCFS_RESUME; |
1149 | OWRITE4(sc, OHCI_CONTROL, ctl); | | 1149 | OWRITE4(sc, OHCI_CONTROL, ctl); |
1150 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | | 1150 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); |
1151 | ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL; | | 1151 | ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL; |
1152 | OWRITE4(sc, OHCI_CONTROL, ctl); | | 1152 | OWRITE4(sc, OHCI_CONTROL, ctl); |
1153 | usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); | | 1153 | usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); |
1154 | sc->sc_control = sc->sc_intre = 0; | | 1154 | sc->sc_control = sc->sc_intre = 0; |
1155 | | | 1155 | |
1156 | mutex_spin_enter(&sc->sc_intr_lock); | | 1156 | mutex_spin_enter(&sc->sc_intr_lock); |
1157 | sc->sc_bus.ub_usepolling--; | | 1157 | sc->sc_bus.ub_usepolling--; |
1158 | mutex_spin_exit(&sc->sc_intr_lock); | | 1158 | mutex_spin_exit(&sc->sc_intr_lock); |
1159 | | | 1159 | |
1160 | return true; | | 1160 | return true; |
1161 | } | | 1161 | } |
1162 | | | 1162 | |
1163 | bool | | 1163 | bool |
1164 | ohci_suspend(device_t dv, const pmf_qual_t *qual) | | 1164 | ohci_suspend(device_t dv, const pmf_qual_t *qual) |
1165 | { | | 1165 | { |
1166 | ohci_softc_t *sc = device_private(dv); | | 1166 | ohci_softc_t *sc = device_private(dv); |
1167 | uint32_t ctl; | | 1167 | uint32_t ctl; |
1168 | | | 1168 | |
1169 | mutex_spin_enter(&sc->sc_intr_lock); | | 1169 | mutex_spin_enter(&sc->sc_intr_lock); |
1170 | sc->sc_bus.ub_usepolling++; | | 1170 | sc->sc_bus.ub_usepolling++; |
1171 | mutex_spin_exit(&sc->sc_intr_lock); | | 1171 | mutex_spin_exit(&sc->sc_intr_lock); |
1172 | | | 1172 | |
1173 | ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK; | | 1173 | ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK; |
1174 | if (sc->sc_control == 0) { | | 1174 | if (sc->sc_control == 0) { |
1175 | /* | | 1175 | /* |
1176 | * Preserve register values, in case that BIOS | | 1176 | * Preserve register values, in case that BIOS |
1177 | * does not recover them. | | 1177 | * does not recover them. |
1178 | */ | | 1178 | */ |
1179 | sc->sc_control = ctl; | | 1179 | sc->sc_control = ctl; |
1180 | sc->sc_intre = OREAD4(sc, | | 1180 | sc->sc_intre = OREAD4(sc, |
1181 | OHCI_INTERRUPT_ENABLE); | | 1181 | OHCI_INTERRUPT_ENABLE); |
1182 | } | | 1182 | } |
1183 | ctl |= OHCI_HCFS_SUSPEND; | | 1183 | ctl |= OHCI_HCFS_SUSPEND; |
1184 | OWRITE4(sc, OHCI_CONTROL, ctl); | | 1184 | OWRITE4(sc, OHCI_CONTROL, ctl); |
1185 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); | | 1185 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); |
1186 | | | 1186 | |
1187 | mutex_spin_enter(&sc->sc_intr_lock); | | 1187 | mutex_spin_enter(&sc->sc_intr_lock); |
1188 | sc->sc_bus.ub_usepolling--; | | 1188 | sc->sc_bus.ub_usepolling--; |
1189 | mutex_spin_exit(&sc->sc_intr_lock); | | 1189 | mutex_spin_exit(&sc->sc_intr_lock); |
1190 | | | 1190 | |
1191 | return true; | | 1191 | return true; |
1192 | } | | 1192 | } |
1193 | | | 1193 | |
1194 | #ifdef OHCI_DEBUG | | 1194 | #ifdef OHCI_DEBUG |
1195 | void | | 1195 | void |
1196 | ohci_dumpregs(ohci_softc_t *sc) | | 1196 | ohci_dumpregs(ohci_softc_t *sc) |
1197 | { | | 1197 | { |
1198 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1198 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1199 | | | 1199 | |
1200 | DPRINTF("rev=0x%08jx control=0x%08jx command=0x%08jx", | | 1200 | DPRINTF("rev=0x%08jx control=0x%08jx command=0x%08jx", |
1201 | OREAD4(sc, OHCI_REVISION), | | 1201 | OREAD4(sc, OHCI_REVISION), |
1202 | OREAD4(sc, OHCI_CONTROL), | | 1202 | OREAD4(sc, OHCI_CONTROL), |
1203 | OREAD4(sc, OHCI_COMMAND_STATUS), 0); | | 1203 | OREAD4(sc, OHCI_COMMAND_STATUS), 0); |
1204 | DPRINTF(" intrstat=0x%08jx intre=0x%08jx intrd=0x%08jx", | | 1204 | DPRINTF(" intrstat=0x%08jx intre=0x%08jx intrd=0x%08jx", |
1205 | OREAD4(sc, OHCI_INTERRUPT_STATUS), | | 1205 | OREAD4(sc, OHCI_INTERRUPT_STATUS), |
1206 | OREAD4(sc, OHCI_INTERRUPT_ENABLE), | | 1206 | OREAD4(sc, OHCI_INTERRUPT_ENABLE), |
1207 | OREAD4(sc, OHCI_INTERRUPT_DISABLE), 0); | | 1207 | OREAD4(sc, OHCI_INTERRUPT_DISABLE), 0); |
1208 | DPRINTF(" hcca=0x%08jx percur=0x%08jx ctrlhd=0x%08jx", | | 1208 | DPRINTF(" hcca=0x%08jx percur=0x%08jx ctrlhd=0x%08jx", |
1209 | OREAD4(sc, OHCI_HCCA), | | 1209 | OREAD4(sc, OHCI_HCCA), |
1210 | OREAD4(sc, OHCI_PERIOD_CURRENT_ED), | | 1210 | OREAD4(sc, OHCI_PERIOD_CURRENT_ED), |
1211 | OREAD4(sc, OHCI_CONTROL_HEAD_ED), 0); | | 1211 | OREAD4(sc, OHCI_CONTROL_HEAD_ED), 0); |
1212 | DPRINTF(" ctrlcur=0x%08jx bulkhd=0x%08jx bulkcur=0x%08jx", | | 1212 | DPRINTF(" ctrlcur=0x%08jx bulkhd=0x%08jx bulkcur=0x%08jx", |
1213 | OREAD4(sc, OHCI_CONTROL_CURRENT_ED), | | 1213 | OREAD4(sc, OHCI_CONTROL_CURRENT_ED), |
1214 | OREAD4(sc, OHCI_BULK_HEAD_ED), | | 1214 | OREAD4(sc, OHCI_BULK_HEAD_ED), |
1215 | OREAD4(sc, OHCI_BULK_CURRENT_ED) ,0); | | 1215 | OREAD4(sc, OHCI_BULK_CURRENT_ED) ,0); |
1216 | DPRINTF(" done=0x%08jx fmival=0x%08jx fmrem=0x%08jx", | | 1216 | DPRINTF(" done=0x%08jx fmival=0x%08jx fmrem=0x%08jx", |
1217 | OREAD4(sc, OHCI_DONE_HEAD), | | 1217 | OREAD4(sc, OHCI_DONE_HEAD), |
1218 | OREAD4(sc, OHCI_FM_INTERVAL), | | 1218 | OREAD4(sc, OHCI_FM_INTERVAL), |
1219 | OREAD4(sc, OHCI_FM_REMAINING), 0); | | 1219 | OREAD4(sc, OHCI_FM_REMAINING), 0); |
1220 | DPRINTF(" fmnum=0x%08jx perst=0x%08jx lsthrs=0x%08jx", | | 1220 | DPRINTF(" fmnum=0x%08jx perst=0x%08jx lsthrs=0x%08jx", |
1221 | OREAD4(sc, OHCI_FM_NUMBER), | | 1221 | OREAD4(sc, OHCI_FM_NUMBER), |
1222 | OREAD4(sc, OHCI_PERIODIC_START), | | 1222 | OREAD4(sc, OHCI_PERIODIC_START), |
1223 | OREAD4(sc, OHCI_LS_THRESHOLD), 0); | | 1223 | OREAD4(sc, OHCI_LS_THRESHOLD), 0); |
1224 | DPRINTF(" desca=0x%08jx descb=0x%08jx stat=0x%08jx", | | 1224 | DPRINTF(" desca=0x%08jx descb=0x%08jx stat=0x%08jx", |
1225 | OREAD4(sc, OHCI_RH_DESCRIPTOR_A), | | 1225 | OREAD4(sc, OHCI_RH_DESCRIPTOR_A), |
1226 | OREAD4(sc, OHCI_RH_DESCRIPTOR_B), | | 1226 | OREAD4(sc, OHCI_RH_DESCRIPTOR_B), |
1227 | OREAD4(sc, OHCI_RH_STATUS), 0); | | 1227 | OREAD4(sc, OHCI_RH_STATUS), 0); |
1228 | DPRINTF(" port1=0x%08jx port2=0x%08jx", | | 1228 | DPRINTF(" port1=0x%08jx port2=0x%08jx", |
1229 | OREAD4(sc, OHCI_RH_PORT_STATUS(1)), | | 1229 | OREAD4(sc, OHCI_RH_PORT_STATUS(1)), |
1230 | OREAD4(sc, OHCI_RH_PORT_STATUS(2)), 0, 0); | | 1230 | OREAD4(sc, OHCI_RH_PORT_STATUS(2)), 0, 0); |
1231 | DPRINTF(" HCCA: frame_number=0x%04jx done_head=0x%08jx", | | 1231 | DPRINTF(" HCCA: frame_number=0x%04jx done_head=0x%08jx", |
1232 | O32TOH(sc->sc_hcca->hcca_frame_number), | | 1232 | O32TOH(sc->sc_hcca->hcca_frame_number), |
1233 | O32TOH(sc->sc_hcca->hcca_done_head), 0, 0); | | 1233 | O32TOH(sc->sc_hcca->hcca_done_head), 0, 0); |
1234 | } | | 1234 | } |
1235 | #endif | | 1235 | #endif |
1236 | | | 1236 | |
1237 | Static int ohci_intr1(ohci_softc_t *); | | 1237 | Static int ohci_intr1(ohci_softc_t *); |
1238 | | | 1238 | |
1239 | int | | 1239 | int |
1240 | ohci_intr(void *p) | | 1240 | ohci_intr(void *p) |
1241 | { | | 1241 | { |
1242 | ohci_softc_t *sc = p; | | 1242 | ohci_softc_t *sc = p; |
1243 | int ret = 0; | | 1243 | int ret = 0; |
1244 | | | 1244 | |
1245 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1245 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1246 | | | 1246 | |
1247 | if (sc == NULL) | | 1247 | if (sc == NULL) |
1248 | return 0; | | 1248 | return 0; |
1249 | | | 1249 | |
1250 | mutex_spin_enter(&sc->sc_intr_lock); | | 1250 | mutex_spin_enter(&sc->sc_intr_lock); |
1251 | | | 1251 | |
1252 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) | | 1252 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) |
1253 | goto done; | | 1253 | goto done; |
1254 | | | 1254 | |
1255 | /* If we get an interrupt while polling, then just ignore it. */ | | 1255 | /* If we get an interrupt while polling, then just ignore it. */ |
1256 | if (sc->sc_bus.ub_usepolling) { | | 1256 | if (sc->sc_bus.ub_usepolling) { |
1257 | DPRINTFN(16, "ignored interrupt while polling", 0, 0, 0, 0); | | 1257 | DPRINTFN(16, "ignored interrupt while polling", 0, 0, 0, 0); |
1258 | /* for level triggered intrs, should do something to ack */ | | 1258 | /* for level triggered intrs, should do something to ack */ |
1259 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, | | 1259 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, |
1260 | OREAD4(sc, OHCI_INTERRUPT_STATUS)); | | 1260 | OREAD4(sc, OHCI_INTERRUPT_STATUS)); |
1261 | | | 1261 | |
1262 | goto done; | | 1262 | goto done; |
1263 | } | | 1263 | } |
1264 | | | 1264 | |
1265 | ret = ohci_intr1(sc); | | 1265 | ret = ohci_intr1(sc); |
1266 | | | 1266 | |
1267 | done: | | 1267 | done: |
1268 | mutex_spin_exit(&sc->sc_intr_lock); | | 1268 | mutex_spin_exit(&sc->sc_intr_lock); |
1269 | return ret; | | 1269 | return ret; |
1270 | } | | 1270 | } |
1271 | | | 1271 | |
1272 | Static int | | 1272 | Static int |
1273 | ohci_intr1(ohci_softc_t *sc) | | 1273 | ohci_intr1(ohci_softc_t *sc) |
1274 | { | | 1274 | { |
1275 | uint32_t intrs, eintrs; | | 1275 | uint32_t intrs, eintrs; |
1276 | | | 1276 | |
1277 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1277 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1278 | | | 1278 | |
1279 | /* In case the interrupt occurs before initialization has completed. */ | | 1279 | /* In case the interrupt occurs before initialization has completed. */ |
1280 | if (sc == NULL || sc->sc_hcca == NULL) { | | 1280 | if (sc == NULL || sc->sc_hcca == NULL) { |
1281 | #ifdef DIAGNOSTIC | | 1281 | #ifdef DIAGNOSTIC |
1282 | printf("ohci_intr: sc->sc_hcca == NULL\n"); | | 1282 | printf("ohci_intr: sc->sc_hcca == NULL\n"); |
1283 | #endif | | 1283 | #endif |
1284 | return 0; | | 1284 | return 0; |
1285 | } | | 1285 | } |
1286 | | | 1286 | |
1287 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | | 1287 | KASSERT(mutex_owned(&sc->sc_intr_lock)); |
1288 | | | 1288 | |
1289 | intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS); | | 1289 | intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS); |
1290 | if (!intrs) | | 1290 | if (!intrs) |
1291 | return 0; | | 1291 | return 0; |
1292 | | | 1292 | |
1293 | /* Acknowledge */ | | 1293 | /* Acknowledge */ |
1294 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs & ~(OHCI_MIE|OHCI_WDH)); | | 1294 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs & ~(OHCI_MIE|OHCI_WDH)); |
1295 | eintrs = intrs & sc->sc_eintrs; | | 1295 | eintrs = intrs & sc->sc_eintrs; |
1296 | DPRINTFN(7, "sc=%#jx", (uintptr_t)sc, 0, 0, 0); | | 1296 | DPRINTFN(7, "sc=%#jx", (uintptr_t)sc, 0, 0, 0); |
1297 | DPRINTFN(7, "intrs=%#jx(%#jx) eintrs=%#jx(%#jx)", | | 1297 | DPRINTFN(7, "intrs=%#jx(%#jx) eintrs=%#jx(%#jx)", |
1298 | intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS), eintrs, | | 1298 | intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS), eintrs, |
1299 | sc->sc_eintrs); | | 1299 | sc->sc_eintrs); |
1300 | | | 1300 | |
1301 | if (!eintrs) { | | 1301 | if (!eintrs) { |
1302 | return 0; | | 1302 | return 0; |
1303 | } | | 1303 | } |
1304 | | | 1304 | |
1305 | if (eintrs & OHCI_SO) { | | 1305 | if (eintrs & OHCI_SO) { |
1306 | sc->sc_overrun_cnt++; | | 1306 | sc->sc_overrun_cnt++; |
1307 | if (usbd_ratecheck(&sc->sc_overrun_ntc)) { | | 1307 | if (usbd_ratecheck(&sc->sc_overrun_ntc)) { |
1308 | printf("%s: %u scheduling overruns\n", | | 1308 | printf("%s: %u scheduling overruns\n", |
1309 | device_xname(sc->sc_dev), sc->sc_overrun_cnt); | | 1309 | device_xname(sc->sc_dev), sc->sc_overrun_cnt); |
1310 | sc->sc_overrun_cnt = 0; | | 1310 | sc->sc_overrun_cnt = 0; |
1311 | } | | 1311 | } |
1312 | /* XXX do what */ | | 1312 | /* XXX do what */ |
1313 | eintrs &= ~OHCI_SO; | | 1313 | eintrs &= ~OHCI_SO; |
1314 | } | | 1314 | } |
1315 | if (eintrs & OHCI_WDH) { | | 1315 | if (eintrs & OHCI_WDH) { |
1316 | /* | | 1316 | /* |
1317 | * We block the interrupt below, and reenable it later from | | 1317 | * We block the interrupt below, and reenable it later from |
1318 | * ohci_softintr(). | | 1318 | * ohci_softintr(). |
1319 | */ | | 1319 | */ |
1320 | usb_schedsoftintr(&sc->sc_bus); | | 1320 | usb_schedsoftintr(&sc->sc_bus); |
1321 | } | | 1321 | } |
1322 | if (eintrs & OHCI_RD) { | | 1322 | if (eintrs & OHCI_RD) { |
1323 | DPRINTFN(5, "resume detect sc=%#jx", (uintptr_t)sc, 0, 0, 0); | | 1323 | DPRINTFN(5, "resume detect sc=%#jx", (uintptr_t)sc, 0, 0, 0); |
1324 | printf("%s: resume detect\n", device_xname(sc->sc_dev)); | | 1324 | printf("%s: resume detect\n", device_xname(sc->sc_dev)); |
1325 | /* XXX process resume detect */ | | 1325 | /* XXX process resume detect */ |
1326 | } | | 1326 | } |
1327 | if (eintrs & OHCI_UE) { | | 1327 | if (eintrs & OHCI_UE) { |
1328 | DPRINTFN(5, "unrecoverable error sc=%#jx", (uintptr_t)sc, 0, 0, 0); | | 1328 | DPRINTFN(5, "unrecoverable error sc=%#jx", (uintptr_t)sc, 0, 0, 0); |
1329 | printf("%s: unrecoverable error, controller halted\n", | | 1329 | printf("%s: unrecoverable error, controller halted\n", |
1330 | device_xname(sc->sc_dev)); | | 1330 | device_xname(sc->sc_dev)); |
1331 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); | | 1331 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); |
1332 | /* XXX what else */ | | 1332 | /* XXX what else */ |
1333 | } | | 1333 | } |
1334 | if (eintrs & OHCI_RHSC) { | | 1334 | if (eintrs & OHCI_RHSC) { |
1335 | /* | | 1335 | /* |
1336 | * We block the interrupt below, and reenable it later from | | 1336 | * We block the interrupt below, and reenable it later from |
1337 | * a timeout. | | 1337 | * a timeout. |
1338 | */ | | 1338 | */ |
1339 | softint_schedule(sc->sc_rhsc_si); | | 1339 | softint_schedule(sc->sc_rhsc_si); |
1340 | } | | 1340 | } |
1341 | | | 1341 | |
1342 | if (eintrs != 0) { | | 1342 | if (eintrs != 0) { |
1343 | /* Block unprocessed interrupts. */ | | 1343 | /* Block unprocessed interrupts. */ |
1344 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs); | | 1344 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs); |
1345 | sc->sc_eintrs &= ~eintrs; | | 1345 | sc->sc_eintrs &= ~eintrs; |
1346 | DPRINTF("sc %#jx blocking intrs 0x%jx", (uintptr_t)sc, | | 1346 | DPRINTF("sc %#jx blocking intrs 0x%jx", (uintptr_t)sc, |
1347 | eintrs, 0, 0); | | 1347 | eintrs, 0, 0); |
1348 | } | | 1348 | } |
1349 | | | 1349 | |
1350 | return 1; | | 1350 | return 1; |
1351 | } | | 1351 | } |
1352 | | | 1352 | |
1353 | void | | 1353 | void |
1354 | ohci_rhsc_enable(void *v_sc) | | 1354 | ohci_rhsc_enable(void *v_sc) |
1355 | { | | 1355 | { |
1356 | ohci_softc_t *sc = v_sc; | | 1356 | ohci_softc_t *sc = v_sc; |
1357 | | | 1357 | |
1358 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1358 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1359 | DPRINTF("sc %#jx", (uintptr_t)sc, 0, 0, 0); | | 1359 | DPRINTF("sc %#jx", (uintptr_t)sc, 0, 0, 0); |
1360 | mutex_spin_enter(&sc->sc_intr_lock); | | 1360 | mutex_spin_enter(&sc->sc_intr_lock); |
1361 | sc->sc_eintrs |= OHCI_RHSC; | | 1361 | sc->sc_eintrs |= OHCI_RHSC; |
1362 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); | | 1362 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); |
1363 | mutex_spin_exit(&sc->sc_intr_lock); | | 1363 | mutex_spin_exit(&sc->sc_intr_lock); |
1364 | } | | 1364 | } |
1365 | | | 1365 | |
1366 | #ifdef OHCI_DEBUG | | 1366 | #ifdef OHCI_DEBUG |
1367 | const char *ohci_cc_strs[] = { | | 1367 | const char *ohci_cc_strs[] = { |
1368 | "NO_ERROR", | | 1368 | "NO_ERROR", |
1369 | "CRC", | | 1369 | "CRC", |
1370 | "BIT_STUFFING", | | 1370 | "BIT_STUFFING", |
1371 | "DATA_TOGGLE_MISMATCH", | | 1371 | "DATA_TOGGLE_MISMATCH", |
1372 | "STALL", | | 1372 | "STALL", |
1373 | "DEVICE_NOT_RESPONDING", | | 1373 | "DEVICE_NOT_RESPONDING", |
1374 | "PID_CHECK_FAILURE", | | 1374 | "PID_CHECK_FAILURE", |
1375 | "UNEXPECTED_PID", | | 1375 | "UNEXPECTED_PID", |
1376 | "DATA_OVERRUN", | | 1376 | "DATA_OVERRUN", |
1377 | "DATA_UNDERRUN", | | 1377 | "DATA_UNDERRUN", |
1378 | "BUFFER_OVERRUN", | | 1378 | "BUFFER_OVERRUN", |
1379 | "BUFFER_UNDERRUN", | | 1379 | "BUFFER_UNDERRUN", |
1380 | "reserved", | | 1380 | "reserved", |
1381 | "reserved", | | 1381 | "reserved", |
1382 | "NOT_ACCESSED", | | 1382 | "NOT_ACCESSED", |
1383 | "NOT_ACCESSED", | | 1383 | "NOT_ACCESSED", |
1384 | }; | | 1384 | }; |
1385 | #endif | | 1385 | #endif |
1386 | | | 1386 | |
1387 | void | | 1387 | void |
1388 | ohci_softintr(void *v) | | 1388 | ohci_softintr(void *v) |
1389 | { | | 1389 | { |
1390 | struct usbd_bus *bus = v; | | 1390 | struct usbd_bus *bus = v; |
1391 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | | 1391 | ohci_softc_t *sc = OHCI_BUS2SC(bus); |
1392 | ohci_soft_itd_t *sitd, *sidone, *sitdnext; | | 1392 | ohci_soft_itd_t *sitd, *sidone, *sitdnext; |
1393 | ohci_soft_td_t *std, *sdone, *stdnext; | | 1393 | ohci_soft_td_t *std, *sdone, *stdnext; |
1394 | struct usbd_xfer *xfer; | | 1394 | struct usbd_xfer *xfer; |
1395 | struct ohci_pipe *opipe; | | 1395 | struct ohci_pipe *opipe; |
1396 | int len, cc; | | 1396 | int len, cc; |
1397 | int i, j, actlen, iframes, uedir; | | 1397 | int i, j, actlen, iframes, uedir; |
1398 | ohci_physaddr_t done; | | 1398 | ohci_physaddr_t done; |
1399 | | | 1399 | |
1400 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 1400 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
1401 | | | 1401 | |
1402 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1402 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1403 | | | 1403 | |
1404 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), | | 1404 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), |
1405 | sizeof(sc->sc_hcca->hcca_done_head), | | 1405 | sizeof(sc->sc_hcca->hcca_done_head), |
1406 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1406 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1407 | done = O32TOH(sc->sc_hcca->hcca_done_head) & ~OHCI_DONE_INTRS; | | 1407 | done = O32TOH(sc->sc_hcca->hcca_done_head) & ~OHCI_DONE_INTRS; |
1408 | sc->sc_hcca->hcca_done_head = 0; | | 1408 | sc->sc_hcca->hcca_done_head = 0; |
1409 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), | | 1409 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), |
1410 | sizeof(sc->sc_hcca->hcca_done_head), | | 1410 | sizeof(sc->sc_hcca->hcca_done_head), |
1411 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 1411 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1412 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_WDH); | | 1412 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_WDH); |
1413 | sc->sc_eintrs |= OHCI_WDH; | | 1413 | sc->sc_eintrs |= OHCI_WDH; |
1414 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_WDH); | | 1414 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_WDH); |
1415 | | | 1415 | |
1416 | /* Reverse the done list. */ | | 1416 | /* Reverse the done list. */ |
1417 | for (sdone = NULL, sidone = NULL; done != 0; ) { | | 1417 | for (sdone = NULL, sidone = NULL; done != 0; ) { |
1418 | std = ohci_hash_find_td(sc, done); | | 1418 | std = ohci_hash_find_td(sc, done); |
1419 | if (std != NULL) { | | 1419 | if (std != NULL) { |
1420 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | | 1420 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), |
1421 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1421 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1422 | std->dnext = sdone; | | 1422 | std->dnext = sdone; |
1423 | done = O32TOH(std->td.td_nexttd); | | 1423 | done = O32TOH(std->td.td_nexttd); |
1424 | sdone = std; | | 1424 | sdone = std; |
1425 | DPRINTFN(10, "add TD %#jx", (uintptr_t)std, 0, 0, 0); | | 1425 | DPRINTFN(10, "add TD %#jx", (uintptr_t)std, 0, 0, 0); |
1426 | continue; | | 1426 | continue; |
1427 | } | | 1427 | } |
1428 | sitd = ohci_hash_find_itd(sc, done); | | 1428 | sitd = ohci_hash_find_itd(sc, done); |
1429 | if (sitd != NULL) { | | 1429 | if (sitd != NULL) { |
1430 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), | | 1430 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), |
1431 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1431 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1432 | sitd->dnext = sidone; | | 1432 | sitd->dnext = sidone; |
1433 | done = O32TOH(sitd->itd.itd_nextitd); | | 1433 | done = O32TOH(sitd->itd.itd_nextitd); |
1434 | sidone = sitd; | | 1434 | sidone = sitd; |
1435 | DPRINTFN(5, "add ITD %#jx", (uintptr_t)sitd, 0, 0, 0); | | 1435 | DPRINTFN(5, "add ITD %#jx", (uintptr_t)sitd, 0, 0, 0); |
1436 | continue; | | 1436 | continue; |
1437 | } | | 1437 | } |
1438 | DPRINTFN(10, "addr %#jx not found", (uintptr_t)done, 0, 0, 0); | | 1438 | DPRINTFN(10, "addr %#jx not found", (uintptr_t)done, 0, 0, 0); |
1439 | device_printf(sc->sc_dev, "WARNING: addr 0x%08lx not found\n", | | 1439 | device_printf(sc->sc_dev, "WARNING: addr 0x%08lx not found\n", |
1440 | (u_long)done); | | 1440 | (u_long)done); |
1441 | break; | | 1441 | break; |
1442 | } | | 1442 | } |
1443 | | | 1443 | |
1444 | DPRINTFN(10, "sdone=%#jx sidone=%#jx", (uintptr_t)sdone, | | 1444 | DPRINTFN(10, "sdone=%#jx sidone=%#jx", (uintptr_t)sdone, |
1445 | (uintptr_t)sidone, 0, 0); | | 1445 | (uintptr_t)sidone, 0, 0); |
1446 | DPRINTFN(10, "--- TD dump start ---", 0, 0, 0, 0); | | 1446 | DPRINTFN(10, "--- TD dump start ---", 0, 0, 0, 0); |
1447 | #ifdef OHCI_DEBUG | | 1447 | #ifdef OHCI_DEBUG |
1448 | if (ohcidebug >= 10) { | | 1448 | if (ohcidebug >= 10) { |
1449 | for (std = sdone; std; std = std->dnext) | | 1449 | for (std = sdone; std; std = std->dnext) |
1450 | ohci_dump_td(sc, std); | | 1450 | ohci_dump_td(sc, std); |
1451 | } | | 1451 | } |
1452 | #endif | | 1452 | #endif |
1453 | DPRINTFN(10, "--- TD dump end ---", 0, 0, 0, 0); | | 1453 | DPRINTFN(10, "--- TD dump end ---", 0, 0, 0, 0); |
1454 | | | 1454 | |
1455 | for (std = sdone; std; std = stdnext) { | | 1455 | for (std = sdone; std; std = stdnext) { |
1456 | xfer = std->xfer; | | 1456 | xfer = std->xfer; |
1457 | stdnext = std->dnext; | | 1457 | stdnext = std->dnext; |
1458 | DPRINTFN(10, "std=%#jx xfer=%#jx hcpriv=%#jx", (uintptr_t)std, | | 1458 | DPRINTFN(10, "std=%#jx xfer=%#jx hcpriv=%#jx", (uintptr_t)std, |
1459 | (uintptr_t)xfer, (uintptr_t)(xfer ? xfer->ux_hcpriv : 0), | | 1459 | (uintptr_t)xfer, (uintptr_t)(xfer ? xfer->ux_hcpriv : 0), |
1460 | 0); | | 1460 | 0); |
1461 | if (xfer == NULL) { | | 1461 | if (xfer == NULL) { |
1462 | /* | | 1462 | /* |
1463 | * xfer == NULL: There seems to be no xfer associated | | 1463 | * xfer == NULL: There seems to be no xfer associated |
1464 | * with this TD. It is tailp that happened to end up on | | 1464 | * with this TD. It is tailp that happened to end up on |
1465 | * the done queue. | | 1465 | * the done queue. |
1466 | * Shouldn't happen, but some chips are broken(?). | | 1466 | * Shouldn't happen, but some chips are broken(?). |
1467 | */ | | 1467 | */ |
1468 | continue; | | 1468 | continue; |
1469 | } | | 1469 | } |
1470 | | | 1470 | |
1471 | /* | | 1471 | /* |
1472 | * Try to claim this xfer for completion. If it has | | 1472 | * Try to claim this xfer for completion. If it has |
1473 | * already completed or aborted, drop it on the floor. | | 1473 | * already completed or aborted, drop it on the floor. |
1474 | */ | | 1474 | */ |
1475 | if (!usbd_xfer_trycomplete(xfer)) | | 1475 | if (!usbd_xfer_trycomplete(xfer)) |
1476 | continue; | | 1476 | continue; |
1477 | | | 1477 | |
1478 | len = std->len; | | 1478 | len = std->len; |
1479 | if (std->td.td_cbp != 0) | | 1479 | if (std->td.td_cbp != 0) |
1480 | len -= O32TOH(std->td.td_be) - | | 1480 | len -= O32TOH(std->td.td_be) - |
1481 | O32TOH(std->td.td_cbp) + 1; | | 1481 | O32TOH(std->td.td_cbp) + 1; |
1482 | DPRINTFN(10, "len=%jd, flags=0x%jx", len, std->flags, 0, 0); | | 1482 | DPRINTFN(10, "len=%jd, flags=0x%jx", len, std->flags, 0, 0); |
1483 | if (std->flags & OHCI_ADD_LEN) | | 1483 | if (std->flags & OHCI_ADD_LEN) |
1484 | xfer->ux_actlen += len; | | 1484 | xfer->ux_actlen += len; |
1485 | | | 1485 | |
1486 | cc = OHCI_TD_GET_CC(O32TOH(std->td.td_flags)); | | 1486 | cc = OHCI_TD_GET_CC(O32TOH(std->td.td_flags)); |
1487 | if (cc == OHCI_CC_NO_ERROR) { | | 1487 | if (cc == OHCI_CC_NO_ERROR) { |
1488 | ohci_hash_rem_td(sc, std); | | 1488 | ohci_hash_rem_td(sc, std); |
1489 | if (std->flags & OHCI_CALL_DONE) { | | 1489 | if (std->flags & OHCI_CALL_DONE) { |
1490 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 1490 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
1491 | usb_transfer_complete(xfer); | | 1491 | usb_transfer_complete(xfer); |
1492 | } | | 1492 | } |
1493 | } else { | | 1493 | } else { |
1494 | /* | | 1494 | /* |
1495 | * Endpoint is halted. First unlink all the TDs | | 1495 | * Endpoint is halted. First unlink all the TDs |
1496 | * belonging to the failed transfer, and then restart | | 1496 | * belonging to the failed transfer, and then restart |
1497 | * the endpoint. | | 1497 | * the endpoint. |
1498 | */ | | 1498 | */ |
1499 | ohci_soft_td_t *p, *n; | | 1499 | ohci_soft_td_t *p, *n; |
1500 | opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 1500 | opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
1501 | | | 1501 | |
1502 | DPRINTFN(10, "error cc=%jd", cc, 0, 0, 0); | | 1502 | DPRINTFN(10, "error cc=%jd", cc, 0, 0, 0); |
1503 | | | 1503 | |
1504 | /* remove xfer's TDs from the hash */ | | 1504 | /* remove xfer's TDs from the hash */ |
1505 | for (p = std; p->xfer == xfer; p = n) { | | 1505 | for (p = std; p->xfer == xfer; p = n) { |
1506 | n = p->nexttd; | | 1506 | n = p->nexttd; |
1507 | ohci_hash_rem_td(sc, p); | | 1507 | ohci_hash_rem_td(sc, p); |
1508 | } | | 1508 | } |
1509 | | | 1509 | |
1510 | ohci_soft_ed_t *sed = opipe->sed; | | 1510 | ohci_soft_ed_t *sed = opipe->sed; |
1511 | | | 1511 | |
1512 | /* clear halt and TD chain, preserving toggle carry */ | | 1512 | /* clear halt and TD chain, preserving toggle carry */ |
1513 | sed->ed.ed_headp = HTOO32(p->physaddr | | | 1513 | sed->ed.ed_headp = HTOO32(p->physaddr | |
1514 | (O32TOH(sed->ed.ed_headp) & OHCI_TOGGLECARRY)); | | 1514 | (O32TOH(sed->ed.ed_headp) & OHCI_TOGGLECARRY)); |
1515 | usb_syncmem(&sed->dma, | | 1515 | usb_syncmem(&sed->dma, |
1516 | sed->offs + offsetof(ohci_ed_t, ed_headp), | | 1516 | sed->offs + offsetof(ohci_ed_t, ed_headp), |
1517 | sizeof(sed->ed.ed_headp), | | 1517 | sizeof(sed->ed.ed_headp), |
1518 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 1518 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1519 | | | 1519 | |
1520 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); | | 1520 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); |
1521 | | | 1521 | |
1522 | if (cc == OHCI_CC_DATA_UNDERRUN) | | 1522 | if (cc == OHCI_CC_DATA_UNDERRUN) |
1523 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 1523 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
1524 | else if (cc == OHCI_CC_STALL) | | 1524 | else if (cc == OHCI_CC_STALL) |
1525 | xfer->ux_status = USBD_STALLED; | | 1525 | xfer->ux_status = USBD_STALLED; |
1526 | else | | 1526 | else |
1527 | xfer->ux_status = USBD_IOERROR; | | 1527 | xfer->ux_status = USBD_IOERROR; |
1528 | usb_transfer_complete(xfer); | | 1528 | usb_transfer_complete(xfer); |
1529 | } | | 1529 | } |
1530 | } | | 1530 | } |
1531 | DPRINTFN(10, "--- ITD dump start ---", 0, 0, 0, 0); | | 1531 | DPRINTFN(10, "--- ITD dump start ---", 0, 0, 0, 0); |
1532 | #ifdef OHCI_DEBUG | | 1532 | #ifdef OHCI_DEBUG |
1533 | if (ohcidebug >= 10) { | | 1533 | if (ohcidebug >= 10) { |
| @@ -2362,1307 +2362,1306 @@ ohci_roothub_ctrl(struct usbd_bus *bus, | | | @@ -2362,1307 +2362,1306 @@ ohci_roothub_ctrl(struct usbd_bus *bus, |
2362 | OWRITE4(sc, port, UPS_LOW_SPEED); | | 2362 | OWRITE4(sc, port, UPS_LOW_SPEED); |
2363 | break; | | 2363 | break; |
2364 | case UHF_C_PORT_CONNECTION: | | 2364 | case UHF_C_PORT_CONNECTION: |
2365 | OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16); | | 2365 | OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16); |
2366 | break; | | 2366 | break; |
2367 | case UHF_C_PORT_ENABLE: | | 2367 | case UHF_C_PORT_ENABLE: |
2368 | OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16); | | 2368 | OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16); |
2369 | break; | | 2369 | break; |
2370 | case UHF_C_PORT_SUSPEND: | | 2370 | case UHF_C_PORT_SUSPEND: |
2371 | OWRITE4(sc, port, UPS_C_SUSPEND << 16); | | 2371 | OWRITE4(sc, port, UPS_C_SUSPEND << 16); |
2372 | break; | | 2372 | break; |
2373 | case UHF_C_PORT_OVER_CURRENT: | | 2373 | case UHF_C_PORT_OVER_CURRENT: |
2374 | OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16); | | 2374 | OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16); |
2375 | break; | | 2375 | break; |
2376 | case UHF_C_PORT_RESET: | | 2376 | case UHF_C_PORT_RESET: |
2377 | OWRITE4(sc, port, UPS_C_PORT_RESET << 16); | | 2377 | OWRITE4(sc, port, UPS_C_PORT_RESET << 16); |
2378 | break; | | 2378 | break; |
2379 | default: | | 2379 | default: |
2380 | return -1; | | 2380 | return -1; |
2381 | } | | 2381 | } |
2382 | switch(value) { | | 2382 | switch(value) { |
2383 | case UHF_C_PORT_CONNECTION: | | 2383 | case UHF_C_PORT_CONNECTION: |
2384 | case UHF_C_PORT_ENABLE: | | 2384 | case UHF_C_PORT_ENABLE: |
2385 | case UHF_C_PORT_SUSPEND: | | 2385 | case UHF_C_PORT_SUSPEND: |
2386 | case UHF_C_PORT_OVER_CURRENT: | | 2386 | case UHF_C_PORT_OVER_CURRENT: |
2387 | case UHF_C_PORT_RESET: | | 2387 | case UHF_C_PORT_RESET: |
2388 | /* Enable RHSC interrupt if condition is cleared. */ | | 2388 | /* Enable RHSC interrupt if condition is cleared. */ |
2389 | if ((OREAD4(sc, port) >> 16) == 0) | | 2389 | if ((OREAD4(sc, port) >> 16) == 0) |
2390 | ohci_rhsc_enable(sc); | | 2390 | ohci_rhsc_enable(sc); |
2391 | break; | | 2391 | break; |
2392 | default: | | 2392 | default: |
2393 | break; | | 2393 | break; |
2394 | } | | 2394 | } |
2395 | break; | | 2395 | break; |
2396 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): | | 2396 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): |
2397 | if (len == 0) | | 2397 | if (len == 0) |
2398 | break; | | 2398 | break; |
2399 | if ((value & 0xff) != 0) { | | 2399 | if ((value & 0xff) != 0) { |
2400 | return -1; | | 2400 | return -1; |
2401 | } | | 2401 | } |
2402 | usb_hub_descriptor_t hubd; | | 2402 | usb_hub_descriptor_t hubd; |
2403 | | | 2403 | |
2404 | totlen = uimin(buflen, sizeof(hubd)); | | 2404 | totlen = uimin(buflen, sizeof(hubd)); |
2405 | memcpy(&hubd, buf, totlen); | | 2405 | memcpy(&hubd, buf, totlen); |
2406 | | | 2406 | |
2407 | v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); | | 2407 | v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); |
2408 | hubd.bNbrPorts = sc->sc_noport; | | 2408 | hubd.bNbrPorts = sc->sc_noport; |
2409 | USETW(hubd.wHubCharacteristics, | | 2409 | USETW(hubd.wHubCharacteristics, |
2410 | (v & OHCI_NPS ? UHD_PWR_NO_SWITCH : | | 2410 | (v & OHCI_NPS ? UHD_PWR_NO_SWITCH : |
2411 | v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL) | | 2411 | v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL) |
2412 | /* XXX overcurrent */ | | 2412 | /* XXX overcurrent */ |
2413 | ); | | 2413 | ); |
2414 | hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v); | | 2414 | hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v); |
2415 | v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); | | 2415 | v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); |
2416 | for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8) | | 2416 | for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8) |
2417 | hubd.DeviceRemovable[i++] = (uint8_t)v; | | 2417 | hubd.DeviceRemovable[i++] = (uint8_t)v; |
2418 | hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i; | | 2418 | hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i; |
2419 | totlen = uimin(totlen, hubd.bDescLength); | | 2419 | totlen = uimin(totlen, hubd.bDescLength); |
2420 | memcpy(buf, &hubd, totlen); | | 2420 | memcpy(buf, &hubd, totlen); |
2421 | break; | | 2421 | break; |
2422 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): | | 2422 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): |
2423 | if (len != 4) { | | 2423 | if (len != 4) { |
2424 | return -1; | | 2424 | return -1; |
2425 | } | | 2425 | } |
2426 | memset(buf, 0, len); /* ? XXX */ | | 2426 | memset(buf, 0, len); /* ? XXX */ |
2427 | totlen = len; | | 2427 | totlen = len; |
2428 | break; | | 2428 | break; |
2429 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): | | 2429 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): |
2430 | DPRINTFN(8, "get port status i=%jd", index, 0, 0, 0); | | 2430 | DPRINTFN(8, "get port status i=%jd", index, 0, 0, 0); |
2431 | if (index < 1 || index > sc->sc_noport) { | | 2431 | if (index < 1 || index > sc->sc_noport) { |
2432 | return -1; | | 2432 | return -1; |
2433 | } | | 2433 | } |
2434 | if (len != 4) { | | 2434 | if (len != 4) { |
2435 | return -1; | | 2435 | return -1; |
2436 | } | | 2436 | } |
2437 | v = OREAD4(sc, OHCI_RH_PORT_STATUS(index)); | | 2437 | v = OREAD4(sc, OHCI_RH_PORT_STATUS(index)); |
2438 | DPRINTFN(8, "port status=0x%04jx", v, 0, 0, 0); | | 2438 | DPRINTFN(8, "port status=0x%04jx", v, 0, 0, 0); |
2439 | USETW(ps.wPortStatus, v); | | 2439 | USETW(ps.wPortStatus, v); |
2440 | USETW(ps.wPortChange, v >> 16); | | 2440 | USETW(ps.wPortChange, v >> 16); |
2441 | totlen = uimin(len, sizeof(ps)); | | 2441 | totlen = uimin(len, sizeof(ps)); |
2442 | memcpy(buf, &ps, totlen); | | 2442 | memcpy(buf, &ps, totlen); |
2443 | break; | | 2443 | break; |
2444 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): | | 2444 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): |
2445 | return -1; | | 2445 | return -1; |
2446 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): | | 2446 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): |
2447 | break; | | 2447 | break; |
2448 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): | | 2448 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): |
2449 | if (index < 1 || index > sc->sc_noport) { | | 2449 | if (index < 1 || index > sc->sc_noport) { |
2450 | return -1; | | 2450 | return -1; |
2451 | } | | 2451 | } |
2452 | port = OHCI_RH_PORT_STATUS(index); | | 2452 | port = OHCI_RH_PORT_STATUS(index); |
2453 | switch(value) { | | 2453 | switch(value) { |
2454 | case UHF_PORT_ENABLE: | | 2454 | case UHF_PORT_ENABLE: |
2455 | OWRITE4(sc, port, UPS_PORT_ENABLED); | | 2455 | OWRITE4(sc, port, UPS_PORT_ENABLED); |
2456 | break; | | 2456 | break; |
2457 | case UHF_PORT_SUSPEND: | | 2457 | case UHF_PORT_SUSPEND: |
2458 | OWRITE4(sc, port, UPS_SUSPEND); | | 2458 | OWRITE4(sc, port, UPS_SUSPEND); |
2459 | break; | | 2459 | break; |
2460 | case UHF_PORT_RESET: | | 2460 | case UHF_PORT_RESET: |
2461 | DPRINTFN(5, "reset port %jd", index, 0, 0, 0); | | 2461 | DPRINTFN(5, "reset port %jd", index, 0, 0, 0); |
2462 | OWRITE4(sc, port, UPS_RESET); | | 2462 | OWRITE4(sc, port, UPS_RESET); |
2463 | for (i = 0; i < 5; i++) { | | 2463 | for (i = 0; i < 5; i++) { |
2464 | usb_delay_ms(&sc->sc_bus, | | 2464 | usb_delay_ms(&sc->sc_bus, |
2465 | USB_PORT_ROOT_RESET_DELAY); | | 2465 | USB_PORT_ROOT_RESET_DELAY); |
2466 | if (sc->sc_dying) { | | 2466 | if (sc->sc_dying) { |
2467 | return -1; | | 2467 | return -1; |
2468 | } | | 2468 | } |
2469 | if ((OREAD4(sc, port) & UPS_RESET) == 0) | | 2469 | if ((OREAD4(sc, port) & UPS_RESET) == 0) |
2470 | break; | | 2470 | break; |
2471 | } | | 2471 | } |
2472 | DPRINTFN(8, "port %jd reset, status = 0x%04jx", index, | | 2472 | DPRINTFN(8, "port %jd reset, status = 0x%04jx", index, |
2473 | OREAD4(sc, port), 0, 0); | | 2473 | OREAD4(sc, port), 0, 0); |
2474 | break; | | 2474 | break; |
2475 | case UHF_PORT_POWER: | | 2475 | case UHF_PORT_POWER: |
2476 | DPRINTFN(2, "set port power %jd", index, 0, 0, 0); | | 2476 | DPRINTFN(2, "set port power %jd", index, 0, 0, 0); |
2477 | OWRITE4(sc, port, UPS_PORT_POWER); | | 2477 | OWRITE4(sc, port, UPS_PORT_POWER); |
2478 | break; | | 2478 | break; |
2479 | default: | | 2479 | default: |
2480 | return -1; | | 2480 | return -1; |
2481 | } | | 2481 | } |
2482 | break; | | 2482 | break; |
2483 | default: | | 2483 | default: |
2484 | /* default from usbroothub */ | | 2484 | /* default from usbroothub */ |
2485 | return buflen; | | 2485 | return buflen; |
2486 | } | | 2486 | } |
2487 | | | 2487 | |
2488 | return totlen; | | 2488 | return totlen; |
2489 | } | | 2489 | } |
2490 | | | 2490 | |
2491 | Static usbd_status | | 2491 | Static usbd_status |
2492 | ohci_root_intr_transfer(struct usbd_xfer *xfer) | | 2492 | ohci_root_intr_transfer(struct usbd_xfer *xfer) |
2493 | { | | 2493 | { |
2494 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2494 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2495 | usbd_status err; | | 2495 | usbd_status err; |
2496 | | | 2496 | |
2497 | /* Insert last in queue. */ | | 2497 | /* Insert last in queue. */ |
2498 | mutex_enter(&sc->sc_lock); | | 2498 | mutex_enter(&sc->sc_lock); |
2499 | err = usb_insert_transfer(xfer); | | 2499 | err = usb_insert_transfer(xfer); |
2500 | mutex_exit(&sc->sc_lock); | | 2500 | mutex_exit(&sc->sc_lock); |
2501 | if (err) | | 2501 | if (err) |
2502 | return err; | | 2502 | return err; |
2503 | | | 2503 | |
2504 | /* Pipe isn't running, start first */ | | 2504 | /* Pipe isn't running, start first */ |
2505 | return ohci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 2505 | return ohci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
2506 | } | | 2506 | } |
2507 | | | 2507 | |
2508 | Static usbd_status | | 2508 | Static usbd_status |
2509 | ohci_root_intr_start(struct usbd_xfer *xfer) | | 2509 | ohci_root_intr_start(struct usbd_xfer *xfer) |
2510 | { | | 2510 | { |
2511 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2511 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2512 | const bool polling = sc->sc_bus.ub_usepolling; | | 2512 | const bool polling = sc->sc_bus.ub_usepolling; |
2513 | | | 2513 | |
2514 | if (sc->sc_dying) | | 2514 | if (sc->sc_dying) |
2515 | return USBD_IOERROR; | | 2515 | return USBD_IOERROR; |
2516 | | | 2516 | |
2517 | if (!polling) | | 2517 | if (!polling) |
2518 | mutex_enter(&sc->sc_lock); | | 2518 | mutex_enter(&sc->sc_lock); |
2519 | KASSERT(sc->sc_intrxfer == NULL); | | 2519 | KASSERT(sc->sc_intrxfer == NULL); |
2520 | sc->sc_intrxfer = xfer; | | 2520 | sc->sc_intrxfer = xfer; |
2521 | xfer->ux_status = USBD_IN_PROGRESS; | | 2521 | xfer->ux_status = USBD_IN_PROGRESS; |
2522 | if (!polling) | | 2522 | if (!polling) |
2523 | mutex_exit(&sc->sc_lock); | | 2523 | mutex_exit(&sc->sc_lock); |
2524 | | | 2524 | |
2525 | return USBD_IN_PROGRESS; | | 2525 | return USBD_IN_PROGRESS; |
2526 | } | | 2526 | } |
2527 | | | 2527 | |
2528 | /* Abort a root interrupt request. */ | | 2528 | /* Abort a root interrupt request. */ |
2529 | Static void | | 2529 | Static void |
2530 | ohci_root_intr_abort(struct usbd_xfer *xfer) | | 2530 | ohci_root_intr_abort(struct usbd_xfer *xfer) |
2531 | { | | 2531 | { |
2532 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2532 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2533 | | | 2533 | |
2534 | KASSERT(mutex_owned(&sc->sc_lock)); | | 2534 | KASSERT(mutex_owned(&sc->sc_lock)); |
2535 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); | | 2535 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); |
2536 | | | 2536 | |
2537 | /* If xfer has already completed, nothing to do here. */ | | 2537 | /* If xfer has already completed, nothing to do here. */ |
2538 | if (sc->sc_intrxfer == NULL) | | 2538 | if (sc->sc_intrxfer == NULL) |
2539 | return; | | 2539 | return; |
2540 | | | 2540 | |
2541 | /* | | 2541 | /* |
2542 | * Otherwise, sc->sc_intrxfer had better be this transfer. | | 2542 | * Otherwise, sc->sc_intrxfer had better be this transfer. |
2543 | * Cancel it. | | 2543 | * Cancel it. |
2544 | */ | | 2544 | */ |
2545 | KASSERT(sc->sc_intrxfer == xfer); | | 2545 | KASSERT(sc->sc_intrxfer == xfer); |
2546 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); | | 2546 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); |
2547 | xfer->ux_status = USBD_CANCELLED; | | 2547 | xfer->ux_status = USBD_CANCELLED; |
2548 | usb_transfer_complete(xfer); | | 2548 | usb_transfer_complete(xfer); |
2549 | } | | 2549 | } |
2550 | | | 2550 | |
2551 | /* Close the root pipe. */ | | 2551 | /* Close the root pipe. */ |
2552 | Static void | | 2552 | Static void |
2553 | ohci_root_intr_close(struct usbd_pipe *pipe) | | 2553 | ohci_root_intr_close(struct usbd_pipe *pipe) |
2554 | { | | 2554 | { |
2555 | ohci_softc_t *sc __diagused = OHCI_PIPE2SC(pipe); | | 2555 | ohci_softc_t *sc __diagused = OHCI_PIPE2SC(pipe); |
2556 | | | 2556 | |
2557 | KASSERT(mutex_owned(&sc->sc_lock)); | | 2557 | KASSERT(mutex_owned(&sc->sc_lock)); |
2558 | | | 2558 | |
2559 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2559 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2560 | | | 2560 | |
2561 | /* | | 2561 | /* |
2562 | * Caller must guarantee the xfer has completed first, by | | 2562 | * Caller must guarantee the xfer has completed first, by |
2563 | * closing the pipe only after normal completion or an abort. | | 2563 | * closing the pipe only after normal completion or an abort. |
2564 | */ | | 2564 | */ |
2565 | KASSERT(sc->sc_intrxfer == NULL); | | 2565 | KASSERT(sc->sc_intrxfer == NULL); |
2566 | } | | 2566 | } |
2567 | | | 2567 | |
2568 | /************************/ | | 2568 | /************************/ |
2569 | | | 2569 | |
2570 | int | | 2570 | int |
2571 | ohci_device_ctrl_init(struct usbd_xfer *xfer) | | 2571 | ohci_device_ctrl_init(struct usbd_xfer *xfer) |
2572 | { | | 2572 | { |
2573 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2573 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2574 | usb_device_request_t *req = &xfer->ux_request; | | 2574 | usb_device_request_t *req = &xfer->ux_request; |
2575 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2575 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2576 | ohci_soft_td_t *stat, *setup; | | 2576 | ohci_soft_td_t *stat, *setup; |
2577 | int isread = req->bmRequestType & UT_READ; | | 2577 | int isread = req->bmRequestType & UT_READ; |
2578 | int len = xfer->ux_bufsize; | | 2578 | int len = xfer->ux_bufsize; |
2579 | int err = ENOMEM; | | 2579 | int err = ENOMEM; |
2580 | | | 2580 | |
2581 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2581 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2582 | | | 2582 | |
2583 | setup = ohci_alloc_std(sc); | | 2583 | setup = ohci_alloc_std(sc); |
2584 | if (setup == NULL) { | | 2584 | if (setup == NULL) { |
2585 | goto bad1; | | 2585 | goto bad1; |
2586 | } | | 2586 | } |
2587 | stat = ohci_alloc_std(sc); | | 2587 | stat = ohci_alloc_std(sc); |
2588 | if (stat == NULL) { | | 2588 | if (stat == NULL) { |
2589 | goto bad2; | | 2589 | goto bad2; |
2590 | } | | 2590 | } |
2591 | | | 2591 | |
2592 | ox->ox_setup = setup; | | 2592 | ox->ox_setup = setup; |
2593 | ox->ox_stat = stat; | | 2593 | ox->ox_stat = stat; |
2594 | ox->ox_nstd = 0; | | 2594 | ox->ox_nstd = 0; |
2595 | | | 2595 | |
2596 | /* Set up data transaction */ | | 2596 | /* Set up data transaction */ |
2597 | if (len != 0) { | | 2597 | if (len != 0) { |
2598 | err = ohci_alloc_std_chain(sc, xfer, len, isread); | | 2598 | err = ohci_alloc_std_chain(sc, xfer, len, isread); |
2599 | if (err) { | | 2599 | if (err) { |
2600 | goto bad3; | | 2600 | goto bad3; |
2601 | } | | 2601 | } |
2602 | } | | 2602 | } |
2603 | return 0; | | 2603 | return 0; |
2604 | | | 2604 | |
2605 | bad3: | | 2605 | bad3: |
2606 | ohci_free_std(sc, stat); | | 2606 | ohci_free_std(sc, stat); |
2607 | bad2: | | 2607 | bad2: |
2608 | ohci_free_std(sc, setup); | | 2608 | ohci_free_std(sc, setup); |
2609 | bad1: | | 2609 | bad1: |
2610 | return err; | | 2610 | return err; |
2611 | } | | 2611 | } |
2612 | | | 2612 | |
2613 | void | | 2613 | void |
2614 | ohci_device_ctrl_fini(struct usbd_xfer *xfer) | | 2614 | ohci_device_ctrl_fini(struct usbd_xfer *xfer) |
2615 | { | | 2615 | { |
2616 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2616 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2617 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2617 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2618 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 2618 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
2619 | | | 2619 | |
2620 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2620 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2621 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); | | 2621 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); |
2622 | | | 2622 | |
2623 | mutex_enter(&sc->sc_lock); | | 2623 | mutex_enter(&sc->sc_lock); |
2624 | if (ox->ox_setup != opipe->tail.td) { | | 2624 | if (ox->ox_setup != opipe->tail.td) { |
2625 | ohci_free_std_locked(sc, ox->ox_setup); | | 2625 | ohci_free_std_locked(sc, ox->ox_setup); |
2626 | } | | 2626 | } |
2627 | for (size_t i = 0; i < ox->ox_nstd; i++) { | | 2627 | for (size_t i = 0; i < ox->ox_nstd; i++) { |
2628 | ohci_soft_td_t *std = ox->ox_stds[i]; | | 2628 | ohci_soft_td_t *std = ox->ox_stds[i]; |
2629 | if (std == NULL) | | 2629 | if (std == NULL) |
2630 | break; | | 2630 | break; |
2631 | ohci_free_std_locked(sc, std); | | 2631 | ohci_free_std_locked(sc, std); |
2632 | } | | 2632 | } |
2633 | ohci_free_std_locked(sc, ox->ox_stat); | | 2633 | ohci_free_std_locked(sc, ox->ox_stat); |
2634 | mutex_exit(&sc->sc_lock); | | 2634 | mutex_exit(&sc->sc_lock); |
2635 | | | 2635 | |
2636 | if (ox->ox_nstd) { | | 2636 | if (ox->ox_nstd) { |
2637 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; | | 2637 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; |
2638 | kmem_free(ox->ox_stds, sz); | | 2638 | kmem_free(ox->ox_stds, sz); |
2639 | } | | 2639 | } |
2640 | } | | 2640 | } |
2641 | | | 2641 | |
2642 | Static usbd_status | | 2642 | Static usbd_status |
2643 | ohci_device_ctrl_transfer(struct usbd_xfer *xfer) | | 2643 | ohci_device_ctrl_transfer(struct usbd_xfer *xfer) |
2644 | { | | 2644 | { |
2645 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2645 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2646 | usbd_status err; | | 2646 | usbd_status err; |
2647 | | | 2647 | |
2648 | /* Insert last in queue. */ | | 2648 | /* Insert last in queue. */ |
2649 | mutex_enter(&sc->sc_lock); | | 2649 | mutex_enter(&sc->sc_lock); |
2650 | err = usb_insert_transfer(xfer); | | 2650 | err = usb_insert_transfer(xfer); |
2651 | mutex_exit(&sc->sc_lock); | | 2651 | mutex_exit(&sc->sc_lock); |
2652 | if (err) | | 2652 | if (err) |
2653 | return err; | | 2653 | return err; |
2654 | | | 2654 | |
2655 | /* Pipe isn't running, start first */ | | 2655 | /* Pipe isn't running, start first */ |
2656 | return ohci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 2656 | return ohci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
2657 | } | | 2657 | } |
2658 | | | 2658 | |
2659 | Static usbd_status | | 2659 | Static usbd_status |
2660 | ohci_device_ctrl_start(struct usbd_xfer *xfer) | | 2660 | ohci_device_ctrl_start(struct usbd_xfer *xfer) |
2661 | { | | 2661 | { |
2662 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2662 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2663 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2663 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2664 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 2664 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
2665 | usb_device_request_t *req = &xfer->ux_request; | | 2665 | usb_device_request_t *req = &xfer->ux_request; |
2666 | struct usbd_device *dev __diagused = opipe->pipe.up_dev; | | 2666 | struct usbd_device *dev __diagused = opipe->pipe.up_dev; |
2667 | ohci_soft_td_t *setup, *stat, *next, *tail; | | 2667 | ohci_soft_td_t *setup, *stat, *next, *tail; |
2668 | ohci_soft_ed_t *sed; | | 2668 | ohci_soft_ed_t *sed; |
2669 | int isread; | | 2669 | int isread; |
2670 | int len; | | 2670 | int len; |
2671 | const bool polling = sc->sc_bus.ub_usepolling; | | 2671 | const bool polling = sc->sc_bus.ub_usepolling; |
2672 | | | 2672 | |
2673 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2673 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2674 | | | 2674 | |
2675 | if (sc->sc_dying) | | 2675 | if (sc->sc_dying) |
2676 | return USBD_IOERROR; | | 2676 | return USBD_IOERROR; |
2677 | | | 2677 | |
2678 | KASSERT(xfer->ux_rqflags & URQ_REQUEST); | | 2678 | KASSERT(xfer->ux_rqflags & URQ_REQUEST); |
2679 | | | 2679 | |
2680 | isread = req->bmRequestType & UT_READ; | | 2680 | isread = req->bmRequestType & UT_READ; |
2681 | len = UGETW(req->wLength); | | 2681 | len = UGETW(req->wLength); |
2682 | | | 2682 | |
2683 | DPRINTF("xfer=%#jx len=%jd, addr=%jd, endpt=%jd", (uintptr_t)xfer, len, | | 2683 | DPRINTF("xfer=%#jx len=%jd, addr=%jd, endpt=%jd", (uintptr_t)xfer, len, |
2684 | dev->ud_addr, opipe->pipe.up_endpoint->ue_edesc->bEndpointAddress); | | 2684 | dev->ud_addr, opipe->pipe.up_endpoint->ue_edesc->bEndpointAddress); |
2685 | DPRINTF("type=0x%02jx, request=0x%02jx, wValue=0x%04jx, wIndex=0x%04jx", | | 2685 | DPRINTF("type=0x%02jx, request=0x%02jx, wValue=0x%04jx, wIndex=0x%04jx", |
2686 | req->bmRequestType, req->bRequest, UGETW(req->wValue), | | 2686 | req->bmRequestType, req->bRequest, UGETW(req->wValue), |
2687 | UGETW(req->wIndex)); | | 2687 | UGETW(req->wIndex)); |
2688 | | | 2688 | |
2689 | /* Need to take lock here for pipe->tail.td */ | | 2689 | /* Need to take lock here for pipe->tail.td */ |
2690 | if (!polling) | | 2690 | if (!polling) |
2691 | mutex_enter(&sc->sc_lock); | | 2691 | mutex_enter(&sc->sc_lock); |
2692 | | | 2692 | |
2693 | /* | | 2693 | /* |
2694 | * Use the pipe "tail" TD as our first and loan our first TD to the | | 2694 | * Use the pipe "tail" TD as our first and loan our first TD to the |
2695 | * next transfer | | 2695 | * next transfer |
2696 | */ | | 2696 | */ |
2697 | setup = opipe->tail.td; | | 2697 | setup = opipe->tail.td; |
2698 | opipe->tail.td = ox->ox_setup; | | 2698 | opipe->tail.td = ox->ox_setup; |
2699 | ox->ox_setup = setup; | | 2699 | ox->ox_setup = setup; |
2700 | | | 2700 | |
2701 | stat = ox->ox_stat; | | 2701 | stat = ox->ox_stat; |
2702 | | | 2702 | |
2703 | /* point at sentinel */ | | 2703 | /* point at sentinel */ |
2704 | tail = opipe->tail.td; | | 2704 | tail = opipe->tail.td; |
2705 | sed = opipe->sed; | | 2705 | sed = opipe->sed; |
2706 | | | 2706 | |
2707 | KASSERTMSG(OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)) == dev->ud_addr, | | 2707 | KASSERTMSG(OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)) == dev->ud_addr, |
2708 | "address ED %d pipe %d\n", | | 2708 | "address ED %d pipe %d\n", |
2709 | OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)), dev->ud_addr); | | 2709 | OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)), dev->ud_addr); |
2710 | KASSERTMSG(OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)) == | | 2710 | KASSERTMSG(OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)) == |
2711 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize), | | 2711 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize), |
2712 | "MPL ED %d pipe %d\n", | | 2712 | "MPL ED %d pipe %d\n", |
2713 | OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)), | | 2713 | OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)), |
2714 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize)); | | 2714 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize)); |
2715 | | | 2715 | |
2716 | /* next will point to data if len != 0 */ | | 2716 | /* next will point to data if len != 0 */ |
2717 | next = stat; | | 2717 | next = stat; |
2718 | | | 2718 | |
2719 | /* Set up data transaction */ | | 2719 | /* Set up data transaction */ |
2720 | if (len != 0) { | | 2720 | if (len != 0) { |
2721 | ohci_soft_td_t *std; | | 2721 | ohci_soft_td_t *std; |
2722 | ohci_soft_td_t *end; | | 2722 | ohci_soft_td_t *end; |
2723 | | | 2723 | |
2724 | next = ox->ox_stds[0]; | | 2724 | next = ox->ox_stds[0]; |
2725 | ohci_reset_std_chain(sc, xfer, len, isread, next, &end); | | 2725 | ohci_reset_std_chain(sc, xfer, len, isread, next, &end); |
2726 | | | 2726 | |
2727 | end->td.td_nexttd = HTOO32(stat->physaddr); | | 2727 | end->td.td_nexttd = HTOO32(stat->physaddr); |
2728 | end->nexttd = stat; | | 2728 | end->nexttd = stat; |
2729 | | | 2729 | |
2730 | usb_syncmem(&end->dma, end->offs, sizeof(end->td), | | 2730 | usb_syncmem(&end->dma, end->offs, sizeof(end->td), |
2731 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2731 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2732 | | | 2732 | |
2733 | usb_syncmem(&xfer->ux_dmabuf, 0, len, | | 2733 | usb_syncmem(&xfer->ux_dmabuf, 0, len, |
2734 | isread ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | | 2734 | isread ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); |
2735 | std = ox->ox_stds[0]; | | 2735 | std = ox->ox_stds[0]; |
2736 | /* Start toggle at 1 and then use the carried toggle. */ | | 2736 | /* Start toggle at 1 and then use the carried toggle. */ |
2737 | std->td.td_flags &= HTOO32(~OHCI_TD_TOGGLE_MASK); | | 2737 | std->td.td_flags &= HTOO32(~OHCI_TD_TOGGLE_MASK); |
2738 | std->td.td_flags |= HTOO32(OHCI_TD_TOGGLE_1); | | 2738 | std->td.td_flags |= HTOO32(OHCI_TD_TOGGLE_1); |
2739 | usb_syncmem(&std->dma, | | 2739 | usb_syncmem(&std->dma, |
2740 | std->offs + offsetof(ohci_td_t, td_flags), | | 2740 | std->offs + offsetof(ohci_td_t, td_flags), |
2741 | sizeof(std->td.td_flags), | | 2741 | sizeof(std->td.td_flags), |
2742 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2742 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2743 | } | | 2743 | } |
2744 | | | 2744 | |
2745 | DPRINTFN(8, "setup %#jx data %#jx stat %#jx tail %#jx", | | 2745 | DPRINTFN(8, "setup %#jx data %#jx stat %#jx tail %#jx", |
2746 | (uintptr_t)setup, | | 2746 | (uintptr_t)setup, |
2747 | (uintptr_t)(len != 0 ? ox->ox_stds[0] : NULL), (uintptr_t)stat, | | 2747 | (uintptr_t)(len != 0 ? ox->ox_stds[0] : NULL), (uintptr_t)stat, |
2748 | (uintptr_t)tail); | | 2748 | (uintptr_t)tail); |
2749 | KASSERT(opipe->tail.td == tail); | | 2749 | KASSERT(opipe->tail.td == tail); |
2750 | | | 2750 | |
2751 | memcpy(KERNADDR(&opipe->ctrl.reqdma, 0), req, sizeof(*req)); | | 2751 | memcpy(KERNADDR(&opipe->ctrl.reqdma, 0), req, sizeof(*req)); |
2752 | usb_syncmem(&opipe->ctrl.reqdma, 0, sizeof(*req), BUS_DMASYNC_PREWRITE); | | 2752 | usb_syncmem(&opipe->ctrl.reqdma, 0, sizeof(*req), BUS_DMASYNC_PREWRITE); |
2753 | | | 2753 | |
2754 | setup->td.td_flags = HTOO32(OHCI_TD_SETUP | OHCI_TD_NOCC | | | 2754 | setup->td.td_flags = HTOO32(OHCI_TD_SETUP | OHCI_TD_NOCC | |
2755 | OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); | | 2755 | OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); |
2756 | setup->td.td_cbp = HTOO32(DMAADDR(&opipe->ctrl.reqdma, 0)); | | 2756 | setup->td.td_cbp = HTOO32(DMAADDR(&opipe->ctrl.reqdma, 0)); |
2757 | setup->td.td_nexttd = HTOO32(next->physaddr); | | 2757 | setup->td.td_nexttd = HTOO32(next->physaddr); |
2758 | setup->td.td_be = HTOO32(O32TOH(setup->td.td_cbp) + sizeof(*req) - 1); | | 2758 | setup->td.td_be = HTOO32(O32TOH(setup->td.td_cbp) + sizeof(*req) - 1); |
2759 | setup->nexttd = next; | | 2759 | setup->nexttd = next; |
2760 | setup->len = 0; | | 2760 | setup->len = 0; |
2761 | setup->xfer = xfer; | | 2761 | setup->xfer = xfer; |
2762 | setup->flags = 0; | | 2762 | setup->flags = 0; |
2763 | ohci_hash_add_td(sc, setup); | | 2763 | ohci_hash_add_td(sc, setup); |
2764 | | | 2764 | |
2765 | xfer->ux_hcpriv = setup; | | 2765 | xfer->ux_hcpriv = setup; |
2766 | usb_syncmem(&setup->dma, setup->offs, sizeof(setup->td), | | 2766 | usb_syncmem(&setup->dma, setup->offs, sizeof(setup->td), |
2767 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2767 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2768 | | | 2768 | |
2769 | stat->td.td_flags = HTOO32( | | 2769 | stat->td.td_flags = HTOO32( |
2770 | (isread ? OHCI_TD_OUT : OHCI_TD_IN) | | | 2770 | (isread ? OHCI_TD_OUT : OHCI_TD_IN) | |
2771 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); | | 2771 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); |
2772 | stat->td.td_cbp = 0; | | 2772 | stat->td.td_cbp = 0; |
2773 | stat->td.td_nexttd = HTOO32(tail->physaddr); | | 2773 | stat->td.td_nexttd = HTOO32(tail->physaddr); |
2774 | stat->td.td_be = 0; | | 2774 | stat->td.td_be = 0; |
2775 | stat->nexttd = tail; | | 2775 | stat->nexttd = tail; |
2776 | stat->flags = OHCI_CALL_DONE; | | 2776 | stat->flags = OHCI_CALL_DONE; |
2777 | stat->len = 0; | | 2777 | stat->len = 0; |
2778 | stat->xfer = xfer; | | 2778 | stat->xfer = xfer; |
2779 | ohci_hash_add_td(sc, stat); | | 2779 | ohci_hash_add_td(sc, stat); |
2780 | | | 2780 | |
2781 | usb_syncmem(&stat->dma, stat->offs, sizeof(stat->td), | | 2781 | usb_syncmem(&stat->dma, stat->offs, sizeof(stat->td), |
2782 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2782 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2783 | | | 2783 | |
2784 | memset(&tail->td, 0, sizeof(tail->td)); | | 2784 | memset(&tail->td, 0, sizeof(tail->td)); |
2785 | tail->nexttd = NULL; | | 2785 | tail->nexttd = NULL; |
2786 | tail->xfer = NULL; | | 2786 | tail->xfer = NULL; |
2787 | | | 2787 | |
2788 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), | | 2788 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), |
2789 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2789 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2790 | | | 2790 | |
2791 | #ifdef OHCI_DEBUG | | 2791 | #ifdef OHCI_DEBUG |
2792 | USBHIST_LOGN(ohcidebug, 5, "--- dump start ---", 0, 0, 0, 0); | | 2792 | USBHIST_LOGN(ohcidebug, 5, "--- dump start ---", 0, 0, 0, 0); |
2793 | if (ohcidebug >= 5) { | | 2793 | if (ohcidebug >= 5) { |
2794 | ohci_dump_ed(sc, sed); | | 2794 | ohci_dump_ed(sc, sed); |
2795 | ohci_dump_tds(sc, setup); | | 2795 | ohci_dump_tds(sc, setup); |
2796 | } | | 2796 | } |
2797 | USBHIST_LOGN(ohcidebug, 5, "--- dump end ---", 0, 0, 0, 0); | | 2797 | USBHIST_LOGN(ohcidebug, 5, "--- dump end ---", 0, 0, 0, 0); |
2798 | #endif | | 2798 | #endif |
2799 | | | 2799 | |
2800 | /* Insert ED in schedule */ | | 2800 | /* Insert ED in schedule */ |
2801 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | | 2801 | sed->ed.ed_tailp = HTOO32(tail->physaddr); |
2802 | usb_syncmem(&sed->dma, | | 2802 | usb_syncmem(&sed->dma, |
2803 | sed->offs + offsetof(ohci_ed_t, ed_tailp), | | 2803 | sed->offs + offsetof(ohci_ed_t, ed_tailp), |
2804 | sizeof(sed->ed.ed_tailp), | | 2804 | sizeof(sed->ed.ed_tailp), |
2805 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2805 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2806 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); | | 2806 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); |
2807 | usbd_xfer_schedule_timeout(xfer); | | 2807 | usbd_xfer_schedule_timeout(xfer); |
2808 | | | 2808 | |
2809 | DPRINTF("done", 0, 0, 0, 0); | | 2809 | DPRINTF("done", 0, 0, 0, 0); |
2810 | | | 2810 | |
2811 | xfer->ux_status = USBD_IN_PROGRESS; | | 2811 | xfer->ux_status = USBD_IN_PROGRESS; |
2812 | if (!polling) | | 2812 | if (!polling) |
2813 | mutex_exit(&sc->sc_lock); | | 2813 | mutex_exit(&sc->sc_lock); |
2814 | | | 2814 | |
2815 | return USBD_IN_PROGRESS; | | 2815 | return USBD_IN_PROGRESS; |
2816 | } | | 2816 | } |
2817 | | | 2817 | |
2818 | /* Abort a device control request. */ | | 2818 | /* Abort a device control request. */ |
2819 | Static void | | 2819 | Static void |
2820 | ohci_device_ctrl_abort(struct usbd_xfer *xfer) | | 2820 | ohci_device_ctrl_abort(struct usbd_xfer *xfer) |
2821 | { | | 2821 | { |
2822 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | | 2822 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); |
2823 | | | 2823 | |
2824 | KASSERT(mutex_owned(&sc->sc_lock)); | | 2824 | KASSERT(mutex_owned(&sc->sc_lock)); |
2825 | | | 2825 | |
2826 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2826 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2827 | DPRINTF("xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 2827 | DPRINTF("xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
2828 | usbd_xfer_abort(xfer); | | 2828 | usbd_xfer_abort(xfer); |
2829 | } | | 2829 | } |
2830 | | | 2830 | |
2831 | /* Close a device control pipe. */ | | 2831 | /* Close a device control pipe. */ |
2832 | Static void | | 2832 | Static void |
2833 | ohci_device_ctrl_close(struct usbd_pipe *pipe) | | 2833 | ohci_device_ctrl_close(struct usbd_pipe *pipe) |
2834 | { | | 2834 | { |
2835 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 2835 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
2836 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 2836 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
2837 | | | 2837 | |
2838 | KASSERT(mutex_owned(&sc->sc_lock)); | | 2838 | KASSERT(mutex_owned(&sc->sc_lock)); |
2839 | | | 2839 | |
2840 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2840 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2841 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); | | 2841 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); |
2842 | ohci_close_pipe(pipe, sc->sc_ctrl_head); | | 2842 | ohci_close_pipe(pipe, sc->sc_ctrl_head); |
2843 | ohci_free_std_locked(sc, opipe->tail.td); | | 2843 | ohci_free_std_locked(sc, opipe->tail.td); |
2844 | | | 2844 | |
2845 | usb_freemem(&sc->sc_bus, &opipe->ctrl.reqdma); | | 2845 | usb_freemem(&sc->sc_bus, &opipe->ctrl.reqdma); |
2846 | } | | 2846 | } |
2847 | | | 2847 | |
2848 | /************************/ | | 2848 | /************************/ |
2849 | | | 2849 | |
2850 | Static void | | 2850 | Static void |
2851 | ohci_device_clear_toggle(struct usbd_pipe *pipe) | | 2851 | ohci_device_clear_toggle(struct usbd_pipe *pipe) |
2852 | { | | 2852 | { |
2853 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 2853 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
2854 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 2854 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
2855 | | | 2855 | |
2856 | opipe->sed->ed.ed_headp &= HTOO32(~OHCI_TOGGLECARRY); | | 2856 | opipe->sed->ed.ed_headp &= HTOO32(~OHCI_TOGGLECARRY); |
2857 | } | | 2857 | } |
2858 | | | 2858 | |
2859 | Static void | | 2859 | Static void |
2860 | ohci_noop(struct usbd_pipe *pipe) | | 2860 | ohci_noop(struct usbd_pipe *pipe) |
2861 | { | | 2861 | { |
2862 | } | | 2862 | } |
2863 | | | 2863 | |
2864 | Static int | | 2864 | Static int |
2865 | ohci_device_bulk_init(struct usbd_xfer *xfer) | | 2865 | ohci_device_bulk_init(struct usbd_xfer *xfer) |
2866 | { | | 2866 | { |
2867 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2867 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2868 | int len = xfer->ux_bufsize; | | 2868 | int len = xfer->ux_bufsize; |
2869 | int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 2869 | int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; |
2870 | int isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 2870 | int isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
2871 | int err; | | 2871 | int err; |
2872 | | | 2872 | |
2873 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2873 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2874 | | | 2874 | |
2875 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); | | 2875 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); |
2876 | | | 2876 | |
2877 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, | | 2877 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, |
2878 | len, isread, xfer->ux_flags); | | 2878 | len, isread, xfer->ux_flags); |
2879 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); | | 2879 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); |
2880 | | | 2880 | |
2881 | /* Allocate a chain of new TDs (including a new tail). */ | | 2881 | /* Allocate a chain of new TDs (including a new tail). */ |
2882 | err = ohci_alloc_std_chain(sc, xfer, len, isread); | | 2882 | err = ohci_alloc_std_chain(sc, xfer, len, isread); |
2883 | if (err) | | 2883 | if (err) |
2884 | return err; | | 2884 | return err; |
2885 | | | 2885 | |
2886 | return 0; | | 2886 | return 0; |
2887 | } | | 2887 | } |
2888 | | | 2888 | |
2889 | Static void | | 2889 | Static void |
2890 | ohci_device_bulk_fini(struct usbd_xfer *xfer) | | 2890 | ohci_device_bulk_fini(struct usbd_xfer *xfer) |
2891 | { | | 2891 | { |
2892 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2892 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2893 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2893 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2894 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 2894 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
2895 | | | 2895 | |
2896 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2896 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2897 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); | | 2897 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); |
2898 | | | 2898 | |
2899 | mutex_enter(&sc->sc_lock); | | 2899 | mutex_enter(&sc->sc_lock); |
2900 | for (size_t i = 0; i < ox->ox_nstd; i++) { | | 2900 | for (size_t i = 0; i < ox->ox_nstd; i++) { |
2901 | ohci_soft_td_t *std = ox->ox_stds[i]; | | 2901 | ohci_soft_td_t *std = ox->ox_stds[i]; |
2902 | if (std == NULL) | | 2902 | if (std == NULL) |
2903 | break; | | 2903 | break; |
2904 | if (std != opipe->tail.td) | | 2904 | if (std != opipe->tail.td) |
2905 | ohci_free_std_locked(sc, std); | | 2905 | ohci_free_std_locked(sc, std); |
2906 | } | | 2906 | } |
2907 | mutex_exit(&sc->sc_lock); | | 2907 | mutex_exit(&sc->sc_lock); |
2908 | | | 2908 | |
2909 | if (ox->ox_nstd) { | | 2909 | if (ox->ox_nstd) { |
2910 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; | | 2910 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; |
2911 | kmem_free(ox->ox_stds, sz); | | 2911 | kmem_free(ox->ox_stds, sz); |
2912 | } | | 2912 | } |
2913 | } | | 2913 | } |
2914 | | | 2914 | |
2915 | Static usbd_status | | 2915 | Static usbd_status |
2916 | ohci_device_bulk_transfer(struct usbd_xfer *xfer) | | 2916 | ohci_device_bulk_transfer(struct usbd_xfer *xfer) |
2917 | { | | 2917 | { |
2918 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2918 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2919 | usbd_status err; | | 2919 | usbd_status err; |
2920 | | | 2920 | |
2921 | /* Insert last in queue. */ | | 2921 | /* Insert last in queue. */ |
2922 | mutex_enter(&sc->sc_lock); | | 2922 | mutex_enter(&sc->sc_lock); |
2923 | err = usb_insert_transfer(xfer); | | 2923 | err = usb_insert_transfer(xfer); |
2924 | mutex_exit(&sc->sc_lock); | | 2924 | mutex_exit(&sc->sc_lock); |
2925 | if (err) | | 2925 | if (err) |
2926 | return err; | | 2926 | return err; |
2927 | | | 2927 | |
2928 | /* Pipe isn't running, start first */ | | 2928 | /* Pipe isn't running, start first */ |
2929 | return ohci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 2929 | return ohci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
2930 | } | | 2930 | } |
2931 | | | 2931 | |
2932 | Static usbd_status | | 2932 | Static usbd_status |
2933 | ohci_device_bulk_start(struct usbd_xfer *xfer) | | 2933 | ohci_device_bulk_start(struct usbd_xfer *xfer) |
2934 | { | | 2934 | { |
2935 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2935 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2936 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 2936 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
2937 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2937 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2938 | ohci_soft_td_t *last; | | 2938 | ohci_soft_td_t *last; |
2939 | ohci_soft_td_t *data, *tail, *tdp; | | 2939 | ohci_soft_td_t *data, *tail, *tdp; |
2940 | ohci_soft_ed_t *sed; | | 2940 | ohci_soft_ed_t *sed; |
2941 | int len, isread, endpt; | | 2941 | int len, isread, endpt; |
2942 | const bool polling = sc->sc_bus.ub_usepolling; | | 2942 | const bool polling = sc->sc_bus.ub_usepolling; |
2943 | | | 2943 | |
2944 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2944 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2945 | | | 2945 | |
2946 | if (sc->sc_dying) | | 2946 | if (sc->sc_dying) |
2947 | return USBD_IOERROR; | | 2947 | return USBD_IOERROR; |
2948 | | | 2948 | |
2949 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); | | 2949 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); |
2950 | | | 2950 | |
2951 | len = xfer->ux_length; | | 2951 | len = xfer->ux_length; |
2952 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 2952 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; |
2953 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 2953 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
2954 | sed = opipe->sed; | | 2954 | sed = opipe->sed; |
2955 | | | 2955 | |
2956 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, | | 2956 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, |
2957 | len, isread, xfer->ux_flags); | | 2957 | len, isread, xfer->ux_flags); |
2958 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); | | 2958 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); |
2959 | | | 2959 | |
2960 | if (!polling) | | 2960 | if (!polling) |
2961 | mutex_enter(&sc->sc_lock); | | 2961 | mutex_enter(&sc->sc_lock); |
2962 | | | 2962 | |
2963 | /* | | 2963 | /* |
2964 | * Use the pipe "tail" TD as our first and loan our first TD to the | | 2964 | * Use the pipe "tail" TD as our first and loan our first TD to the |
2965 | * next transfer | | 2965 | * next transfer |
2966 | */ | | 2966 | */ |
2967 | data = opipe->tail.td; | | 2967 | data = opipe->tail.td; |
2968 | opipe->tail.td = ox->ox_stds[0]; | | 2968 | opipe->tail.td = ox->ox_stds[0]; |
2969 | ox->ox_stds[0] = data; | | 2969 | ox->ox_stds[0] = data; |
2970 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); | | 2970 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); |
2971 | | | 2971 | |
2972 | /* point at sentinel */ | | 2972 | /* point at sentinel */ |
2973 | tail = opipe->tail.td; | | 2973 | tail = opipe->tail.td; |
2974 | memset(&tail->td, 0, sizeof(tail->td)); | | 2974 | memset(&tail->td, 0, sizeof(tail->td)); |
2975 | tail->nexttd = NULL; | | 2975 | tail->nexttd = NULL; |
2976 | tail->xfer = NULL; | | 2976 | tail->xfer = NULL; |
2977 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), | | 2977 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), |
2978 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2978 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2979 | xfer->ux_hcpriv = data; | | 2979 | xfer->ux_hcpriv = data; |
2980 | | | 2980 | |
2981 | DPRINTFN(8, "xfer %#jx data %#jx tail %#jx", (uintptr_t)xfer, | | 2981 | DPRINTFN(8, "xfer %#jx data %#jx tail %#jx", (uintptr_t)xfer, |
2982 | (uintptr_t)ox->ox_stds[0], (uintptr_t)tail, 0); | | 2982 | (uintptr_t)ox->ox_stds[0], (uintptr_t)tail, 0); |
2983 | KASSERT(opipe->tail.td == tail); | | 2983 | KASSERT(opipe->tail.td == tail); |
2984 | | | 2984 | |
2985 | /* We want interrupt at the end of the transfer. */ | | 2985 | /* We want interrupt at the end of the transfer. */ |
2986 | last->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); | | 2986 | last->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); |
2987 | last->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); | | 2987 | last->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); |
2988 | last->td.td_nexttd = HTOO32(tail->physaddr); | | 2988 | last->td.td_nexttd = HTOO32(tail->physaddr); |
2989 | last->nexttd = tail; | | 2989 | last->nexttd = tail; |
2990 | last->flags |= OHCI_CALL_DONE; | | 2990 | last->flags |= OHCI_CALL_DONE; |
2991 | usb_syncmem(&last->dma, last->offs, sizeof(last->td), | | 2991 | usb_syncmem(&last->dma, last->offs, sizeof(last->td), |
2992 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2992 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2993 | | | 2993 | |
2994 | DPRINTFN(4, "ed_flags=0x%08jx td_flags=0x%08jx " | | 2994 | DPRINTFN(4, "ed_flags=0x%08jx td_flags=0x%08jx " |
2995 | "td_cbp=0x%08jx td_be=0x%08jx", | | 2995 | "td_cbp=0x%08jx td_be=0x%08jx", |
2996 | (int)O32TOH(sed->ed.ed_flags), | | 2996 | (int)O32TOH(sed->ed.ed_flags), |
2997 | (int)O32TOH(data->td.td_flags), | | 2997 | (int)O32TOH(data->td.td_flags), |
2998 | (int)O32TOH(data->td.td_cbp), | | 2998 | (int)O32TOH(data->td.td_cbp), |
2999 | (int)O32TOH(data->td.td_be)); | | 2999 | (int)O32TOH(data->td.td_be)); |
3000 | | | 3000 | |
3001 | #ifdef OHCI_DEBUG | | 3001 | #ifdef OHCI_DEBUG |
3002 | DPRINTFN(5, "--- dump start ---", 0, 0, 0, 0); | | 3002 | DPRINTFN(5, "--- dump start ---", 0, 0, 0, 0); |
3003 | if (ohcidebug >= 5) { | | 3003 | if (ohcidebug >= 5) { |
3004 | ohci_dump_ed(sc, sed); | | 3004 | ohci_dump_ed(sc, sed); |
3005 | ohci_dump_tds(sc, data); | | 3005 | ohci_dump_tds(sc, data); |
3006 | } | | 3006 | } |
3007 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); | | 3007 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); |
3008 | #endif | | 3008 | #endif |
3009 | | | 3009 | |
3010 | /* Insert ED in schedule */ | | 3010 | /* Insert ED in schedule */ |
3011 | for (tdp = data; tdp != tail; tdp = tdp->nexttd) { | | 3011 | for (tdp = data; tdp != tail; tdp = tdp->nexttd) { |
3012 | KASSERT(tdp->xfer == xfer); | | 3012 | KASSERT(tdp->xfer == xfer); |
3013 | } | | 3013 | } |
3014 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3014 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3015 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3015 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3016 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | | 3016 | sed->ed.ed_tailp = HTOO32(tail->physaddr); |
3017 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | | 3017 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); |
3018 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3018 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3019 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3019 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3020 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); | | 3020 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); |
3021 | usbd_xfer_schedule_timeout(xfer); | | 3021 | usbd_xfer_schedule_timeout(xfer); |
3022 | xfer->ux_status = USBD_IN_PROGRESS; | | 3022 | xfer->ux_status = USBD_IN_PROGRESS; |
3023 | if (!polling) | | 3023 | if (!polling) |
3024 | mutex_exit(&sc->sc_lock); | | 3024 | mutex_exit(&sc->sc_lock); |
3025 | | | 3025 | |
3026 | return USBD_IN_PROGRESS; | | 3026 | return USBD_IN_PROGRESS; |
3027 | } | | 3027 | } |
3028 | | | 3028 | |
3029 | Static void | | 3029 | Static void |
3030 | ohci_device_bulk_abort(struct usbd_xfer *xfer) | | 3030 | ohci_device_bulk_abort(struct usbd_xfer *xfer) |
3031 | { | | 3031 | { |
3032 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | | 3032 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); |
3033 | | | 3033 | |
3034 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3034 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3035 | | | 3035 | |
3036 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3036 | KASSERT(mutex_owned(&sc->sc_lock)); |
3037 | | | 3037 | |
3038 | DPRINTF("xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 3038 | DPRINTF("xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
3039 | usbd_xfer_abort(xfer); | | 3039 | usbd_xfer_abort(xfer); |
3040 | } | | 3040 | } |
3041 | | | 3041 | |
3042 | /* | | 3042 | /* |
3043 | * Close a device bulk pipe. | | 3043 | * Close a device bulk pipe. |
3044 | */ | | 3044 | */ |
3045 | Static void | | 3045 | Static void |
3046 | ohci_device_bulk_close(struct usbd_pipe *pipe) | | 3046 | ohci_device_bulk_close(struct usbd_pipe *pipe) |
3047 | { | | 3047 | { |
3048 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 3048 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
3049 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 3049 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
3050 | | | 3050 | |
3051 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3051 | KASSERT(mutex_owned(&sc->sc_lock)); |
3052 | | | 3052 | |
3053 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3053 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3054 | | | 3054 | |
3055 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); | | 3055 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); |
3056 | ohci_close_pipe(pipe, sc->sc_bulk_head); | | 3056 | ohci_close_pipe(pipe, sc->sc_bulk_head); |
3057 | ohci_free_std_locked(sc, opipe->tail.td); | | 3057 | ohci_free_std_locked(sc, opipe->tail.td); |
3058 | } | | 3058 | } |
3059 | | | 3059 | |
3060 | /************************/ | | 3060 | /************************/ |
3061 | | | 3061 | |
3062 | Static int | | 3062 | Static int |
3063 | ohci_device_intr_init(struct usbd_xfer *xfer) | | 3063 | ohci_device_intr_init(struct usbd_xfer *xfer) |
3064 | { | | 3064 | { |
3065 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3065 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3066 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3066 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3067 | int len = xfer->ux_bufsize; | | 3067 | int len = xfer->ux_bufsize; |
3068 | int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 3068 | int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; |
3069 | int isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 3069 | int isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
3070 | int err; | | 3070 | int err; |
3071 | | | 3071 | |
3072 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3072 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3073 | | | 3073 | |
3074 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); | | 3074 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); |
3075 | KASSERT(len != 0); | | 3075 | KASSERT(len != 0); |
3076 | | | 3076 | |
3077 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, | | 3077 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, |
3078 | len, isread, xfer->ux_flags); | | 3078 | len, isread, xfer->ux_flags); |
3079 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); | | 3079 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); |
3080 | | | 3080 | |
3081 | ox->ox_nstd = 0; | | 3081 | ox->ox_nstd = 0; |
3082 | | | 3082 | |
3083 | err = ohci_alloc_std_chain(sc, xfer, len, isread); | | 3083 | err = ohci_alloc_std_chain(sc, xfer, len, isread); |
3084 | if (err) { | | 3084 | if (err) { |
3085 | return err; | | 3085 | return err; |
3086 | } | | 3086 | } |
3087 | | | 3087 | |
3088 | return 0; | | 3088 | return 0; |
3089 | } | | 3089 | } |
3090 | | | 3090 | |
3091 | Static void | | 3091 | Static void |
3092 | ohci_device_intr_fini(struct usbd_xfer *xfer) | | 3092 | ohci_device_intr_fini(struct usbd_xfer *xfer) |
3093 | { | | 3093 | { |
3094 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3094 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3095 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3095 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3096 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 3096 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
3097 | | | 3097 | |
3098 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3098 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3099 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); | | 3099 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); |
3100 | | | 3100 | |
3101 | mutex_enter(&sc->sc_lock); | | 3101 | mutex_enter(&sc->sc_lock); |
3102 | for (size_t i = 0; i < ox->ox_nstd; i++) { | | 3102 | for (size_t i = 0; i < ox->ox_nstd; i++) { |
3103 | ohci_soft_td_t *std = ox->ox_stds[i]; | | 3103 | ohci_soft_td_t *std = ox->ox_stds[i]; |
3104 | if (std != NULL) | | 3104 | if (std != NULL) |
3105 | break; | | 3105 | break; |
3106 | if (std != opipe->tail.td) | | 3106 | if (std != opipe->tail.td) |
3107 | ohci_free_std_locked(sc, std); | | 3107 | ohci_free_std_locked(sc, std); |
3108 | } | | 3108 | } |
3109 | mutex_exit(&sc->sc_lock); | | 3109 | mutex_exit(&sc->sc_lock); |
3110 | | | 3110 | |
3111 | if (ox->ox_nstd) { | | 3111 | if (ox->ox_nstd) { |
3112 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; | | 3112 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; |
3113 | kmem_free(ox->ox_stds, sz); | | 3113 | kmem_free(ox->ox_stds, sz); |
3114 | } | | 3114 | } |
3115 | } | | 3115 | } |
3116 | | | 3116 | |
3117 | Static usbd_status | | 3117 | Static usbd_status |
3118 | ohci_device_intr_transfer(struct usbd_xfer *xfer) | | 3118 | ohci_device_intr_transfer(struct usbd_xfer *xfer) |
3119 | { | | 3119 | { |
3120 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3120 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3121 | usbd_status err; | | 3121 | usbd_status err; |
3122 | | | 3122 | |
3123 | /* Insert last in queue. */ | | 3123 | /* Insert last in queue. */ |
3124 | mutex_enter(&sc->sc_lock); | | 3124 | mutex_enter(&sc->sc_lock); |
3125 | err = usb_insert_transfer(xfer); | | 3125 | err = usb_insert_transfer(xfer); |
3126 | mutex_exit(&sc->sc_lock); | | 3126 | mutex_exit(&sc->sc_lock); |
3127 | if (err) | | 3127 | if (err) |
3128 | return err; | | 3128 | return err; |
3129 | | | 3129 | |
3130 | /* Pipe isn't running, start first */ | | 3130 | /* Pipe isn't running, start first */ |
3131 | return ohci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 3131 | return ohci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
3132 | } | | 3132 | } |
3133 | | | 3133 | |
3134 | Static usbd_status | | 3134 | Static usbd_status |
3135 | ohci_device_intr_start(struct usbd_xfer *xfer) | | 3135 | ohci_device_intr_start(struct usbd_xfer *xfer) |
3136 | { | | 3136 | { |
3137 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3137 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3138 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 3138 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
3139 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3139 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3140 | ohci_soft_ed_t *sed = opipe->sed; | | 3140 | ohci_soft_ed_t *sed = opipe->sed; |
3141 | ohci_soft_td_t *data, *last, *tail; | | 3141 | ohci_soft_td_t *data, *last, *tail; |
3142 | int len, isread, endpt; | | 3142 | int len, isread, endpt; |
3143 | const bool polling = sc->sc_bus.ub_usepolling; | | 3143 | const bool polling = sc->sc_bus.ub_usepolling; |
3144 | | | 3144 | |
3145 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3145 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3146 | | | 3146 | |
3147 | if (sc->sc_dying) | | 3147 | if (sc->sc_dying) |
3148 | return USBD_IOERROR; | | 3148 | return USBD_IOERROR; |
3149 | | | 3149 | |
3150 | DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd priv=%#jx", (uintptr_t)xfer, | | 3150 | DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd priv=%#jx", (uintptr_t)xfer, |
3151 | xfer->ux_length, xfer->ux_flags, (uintptr_t)xfer->ux_priv); | | 3151 | xfer->ux_length, xfer->ux_flags, (uintptr_t)xfer->ux_priv); |
3152 | | | 3152 | |
3153 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); | | 3153 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); |
3154 | | | 3154 | |
3155 | len = xfer->ux_length; | | 3155 | len = xfer->ux_length; |
3156 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 3156 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; |
3157 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 3157 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
3158 | | | 3158 | |
3159 | if (!polling) | | 3159 | if (!polling) |
3160 | mutex_enter(&sc->sc_lock); | | 3160 | mutex_enter(&sc->sc_lock); |
3161 | | | 3161 | |
3162 | /* | | 3162 | /* |
3163 | * Use the pipe "tail" TD as our first and loan our first TD to the | | 3163 | * Use the pipe "tail" TD as our first and loan our first TD to the |
3164 | * next transfer. | | 3164 | * next transfer. |
3165 | */ | | 3165 | */ |
3166 | data = opipe->tail.td; | | 3166 | data = opipe->tail.td; |
3167 | opipe->tail.td = ox->ox_stds[0]; | | 3167 | opipe->tail.td = ox->ox_stds[0]; |
3168 | ox->ox_stds[0] = data; | | 3168 | ox->ox_stds[0] = data; |
3169 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); | | 3169 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); |
3170 | | | 3170 | |
3171 | /* point at sentinel */ | | 3171 | /* point at sentinel */ |
3172 | tail = opipe->tail.td; | | 3172 | tail = opipe->tail.td; |
3173 | memset(&tail->td, 0, sizeof(tail->td)); | | 3173 | memset(&tail->td, 0, sizeof(tail->td)); |
3174 | tail->nexttd = NULL; | | 3174 | tail->nexttd = NULL; |
3175 | tail->xfer = NULL; | | 3175 | tail->xfer = NULL; |
3176 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), | | 3176 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), |
3177 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3177 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3178 | xfer->ux_hcpriv = data; | | 3178 | xfer->ux_hcpriv = data; |
3179 | | | 3179 | |
3180 | DPRINTFN(8, "data %#jx tail %#jx", (uintptr_t)ox->ox_stds[0], | | 3180 | DPRINTFN(8, "data %#jx tail %#jx", (uintptr_t)ox->ox_stds[0], |
3181 | (uintptr_t)tail, 0, 0); | | 3181 | (uintptr_t)tail, 0, 0); |
3182 | KASSERT(opipe->tail.td == tail); | | 3182 | KASSERT(opipe->tail.td == tail); |
3183 | | | 3183 | |
3184 | /* We want interrupt at the end of the transfer. */ | | 3184 | /* We want interrupt at the end of the transfer. */ |
3185 | last->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); | | 3185 | last->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); |
3186 | last->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); | | 3186 | last->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); |
3187 | | | 3187 | |
3188 | last->td.td_nexttd = HTOO32(tail->physaddr); | | 3188 | last->td.td_nexttd = HTOO32(tail->physaddr); |
3189 | last->nexttd = tail; | | 3189 | last->nexttd = tail; |
3190 | last->flags |= OHCI_CALL_DONE; | | 3190 | last->flags |= OHCI_CALL_DONE; |
3191 | usb_syncmem(&last->dma, last->offs, sizeof(last->td), | | 3191 | usb_syncmem(&last->dma, last->offs, sizeof(last->td), |
3192 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3192 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3193 | | | 3193 | |
3194 | #ifdef OHCI_DEBUG | | 3194 | #ifdef OHCI_DEBUG |
3195 | DPRINTFN(5, "--- dump start ---", 0, 0, 0, 0); | | 3195 | DPRINTFN(5, "--- dump start ---", 0, 0, 0, 0); |
3196 | if (ohcidebug >= 5) { | | 3196 | if (ohcidebug >= 5) { |
3197 | ohci_dump_ed(sc, sed); | | 3197 | ohci_dump_ed(sc, sed); |
3198 | ohci_dump_tds(sc, data); | | 3198 | ohci_dump_tds(sc, data); |
3199 | } | | 3199 | } |
3200 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); | | 3200 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); |
3201 | #endif | | 3201 | #endif |
3202 | | | 3202 | |
3203 | /* Insert ED in schedule */ | | 3203 | /* Insert ED in schedule */ |
3204 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3204 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3205 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3205 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3206 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | | 3206 | sed->ed.ed_tailp = HTOO32(tail->physaddr); |
3207 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | | 3207 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); |
3208 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3208 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3209 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3209 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3210 | | | 3210 | |
3211 | xfer->ux_status = USBD_IN_PROGRESS; | | 3211 | xfer->ux_status = USBD_IN_PROGRESS; |
3212 | if (!polling) | | 3212 | if (!polling) |
3213 | mutex_exit(&sc->sc_lock); | | 3213 | mutex_exit(&sc->sc_lock); |
3214 | | | 3214 | |
3215 | return USBD_IN_PROGRESS; | | 3215 | return USBD_IN_PROGRESS; |
3216 | } | | 3216 | } |
3217 | | | 3217 | |
3218 | /* Abort a device interrupt request. */ | | 3218 | /* Abort a device interrupt request. */ |
3219 | Static void | | 3219 | Static void |
3220 | ohci_device_intr_abort(struct usbd_xfer *xfer) | | 3220 | ohci_device_intr_abort(struct usbd_xfer *xfer) |
3221 | { | | 3221 | { |
3222 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | | 3222 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); |
3223 | | | 3223 | |
3224 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3224 | KASSERT(mutex_owned(&sc->sc_lock)); |
3225 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); | | 3225 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); |
3226 | | | 3226 | |
3227 | usbd_xfer_abort(xfer); | | 3227 | usbd_xfer_abort(xfer); |
3228 | } | | 3228 | } |
3229 | | | 3229 | |
3230 | /* Close a device interrupt pipe. */ | | 3230 | /* Close a device interrupt pipe. */ |
3231 | Static void | | 3231 | Static void |
3232 | ohci_device_intr_close(struct usbd_pipe *pipe) | | 3232 | ohci_device_intr_close(struct usbd_pipe *pipe) |
3233 | { | | 3233 | { |
3234 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 3234 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
3235 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 3235 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
3236 | int nslots = opipe->intr.nslots; | | 3236 | int nslots = opipe->intr.nslots; |
3237 | int pos = opipe->intr.pos; | | 3237 | int pos = opipe->intr.pos; |
3238 | int j; | | 3238 | int j; |
3239 | ohci_soft_ed_t *p, *sed = opipe->sed; | | 3239 | ohci_soft_ed_t *p, *sed = opipe->sed; |
3240 | | | 3240 | |
3241 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3241 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3242 | | | 3242 | |
3243 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3243 | KASSERT(mutex_owned(&sc->sc_lock)); |
3244 | | | 3244 | |
3245 | DPRINTFN(1, "pipe=%#jx nslots=%jd pos=%jd", (uintptr_t)pipe, nslots, | | 3245 | DPRINTFN(1, "pipe=%#jx nslots=%jd pos=%jd", (uintptr_t)pipe, nslots, |
3246 | pos, 0); | | 3246 | pos, 0); |
3247 | usb_syncmem(&sed->dma, sed->offs, | | 3247 | usb_syncmem(&sed->dma, sed->offs, |
3248 | sizeof(sed->ed), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3248 | sizeof(sed->ed), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3249 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 3249 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
3250 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | | 3250 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), |
3251 | sizeof(sed->ed.ed_flags), | | 3251 | sizeof(sed->ed.ed_flags), |
3252 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3252 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3253 | if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) != | | 3253 | if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) != |
3254 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) | | 3254 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) |
3255 | usb_delay_ms_locked(&sc->sc_bus, 2, &sc->sc_lock); | | 3255 | usb_delay_ms_locked(&sc->sc_bus, 2, &sc->sc_lock); |
3256 | | | 3256 | |
3257 | for (p = sc->sc_eds[pos]; p && p->next != sed; p = p->next) | | 3257 | for (p = sc->sc_eds[pos]; p && p->next != sed; p = p->next) |
3258 | continue; | | 3258 | continue; |
3259 | KASSERT(p); | | 3259 | KASSERT(p); |
3260 | p->next = sed->next; | | 3260 | p->next = sed->next; |
3261 | p->ed.ed_nexted = sed->ed.ed_nexted; | | 3261 | p->ed.ed_nexted = sed->ed.ed_nexted; |
3262 | usb_syncmem(&p->dma, p->offs + offsetof(ohci_ed_t, ed_nexted), | | 3262 | usb_syncmem(&p->dma, p->offs + offsetof(ohci_ed_t, ed_nexted), |
3263 | sizeof(p->ed.ed_nexted), | | 3263 | sizeof(p->ed.ed_nexted), |
3264 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3264 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3265 | | | 3265 | |
3266 | for (j = 0; j < nslots; j++) | | 3266 | for (j = 0; j < nslots; j++) |
3267 | --sc->sc_bws[(pos * nslots + j) % OHCI_NO_INTRS]; | | 3267 | --sc->sc_bws[(pos * nslots + j) % OHCI_NO_INTRS]; |
3268 | | | 3268 | |
3269 | ohci_free_std_locked(sc, opipe->tail.td); | | 3269 | ohci_free_std_locked(sc, opipe->tail.td); |
3270 | ohci_free_sed_locked(sc, opipe->sed); | | 3270 | ohci_free_sed_locked(sc, opipe->sed); |
3271 | } | | 3271 | } |
3272 | | | 3272 | |
3273 | Static usbd_status | | 3273 | Static usbd_status |
3274 | ohci_device_setintr(ohci_softc_t *sc, struct ohci_pipe *opipe, int ival) | | 3274 | ohci_device_setintr(ohci_softc_t *sc, struct ohci_pipe *opipe, int ival) |
3275 | { | | 3275 | { |
3276 | int i, j, best; | | 3276 | int i, j, best; |
3277 | u_int npoll, slow, shigh, nslots; | | 3277 | u_int npoll, slow, shigh, nslots; |
3278 | u_int bestbw, bw; | | 3278 | u_int bestbw, bw; |
3279 | ohci_soft_ed_t *hsed, *sed = opipe->sed; | | 3279 | ohci_soft_ed_t *hsed, *sed = opipe->sed; |
3280 | | | 3280 | |
3281 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3281 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3282 | | | 3282 | |
3283 | DPRINTFN(2, "pipe=%#jx", (uintptr_t)opipe, 0, 0, 0); | | 3283 | DPRINTFN(2, "pipe=%#jx", (uintptr_t)opipe, 0, 0, 0); |
3284 | if (ival == 0) { | | 3284 | if (ival == 0) { |
3285 | printf("ohci_setintr: 0 interval\n"); | | 3285 | printf("ohci_setintr: 0 interval\n"); |
3286 | return USBD_INVAL; | | 3286 | return USBD_INVAL; |
3287 | } | | 3287 | } |
3288 | | | 3288 | |
3289 | npoll = OHCI_NO_INTRS; | | 3289 | npoll = OHCI_NO_INTRS; |
3290 | while (npoll > ival) | | 3290 | while (npoll > ival) |
3291 | npoll /= 2; | | 3291 | npoll /= 2; |
3292 | DPRINTFN(2, "ival=%jd npoll=%jd", ival, npoll, 0, 0); | | 3292 | DPRINTFN(2, "ival=%jd npoll=%jd", ival, npoll, 0, 0); |
3293 | | | 3293 | |
3294 | /* | | 3294 | /* |
3295 | * We now know which level in the tree the ED must go into. | | 3295 | * We now know which level in the tree the ED must go into. |
3296 | * Figure out which slot has most bandwidth left over. | | 3296 | * Figure out which slot has most bandwidth left over. |
3297 | * Slots to examine: | | 3297 | * Slots to examine: |
3298 | * npoll | | 3298 | * npoll |
3299 | * 1 0 | | 3299 | * 1 0 |
3300 | * 2 1 2 | | 3300 | * 2 1 2 |
3301 | * 4 3 4 5 6 | | 3301 | * 4 3 4 5 6 |
3302 | * 8 7 8 9 10 11 12 13 14 | | 3302 | * 8 7 8 9 10 11 12 13 14 |
3303 | * N (N-1) .. (N-1+N-1) | | 3303 | * N (N-1) .. (N-1+N-1) |
3304 | */ | | 3304 | */ |
3305 | slow = npoll-1; | | 3305 | slow = npoll-1; |
3306 | shigh = slow + npoll; | | 3306 | shigh = slow + npoll; |
3307 | nslots = OHCI_NO_INTRS / npoll; | | 3307 | nslots = OHCI_NO_INTRS / npoll; |
3308 | for (best = i = slow, bestbw = ~0; i < shigh; i++) { | | 3308 | for (best = i = slow, bestbw = ~0; i < shigh; i++) { |
3309 | bw = 0; | | 3309 | bw = 0; |
3310 | for (j = 0; j < nslots; j++) | | 3310 | for (j = 0; j < nslots; j++) |
3311 | bw += sc->sc_bws[(i * nslots + j) % OHCI_NO_INTRS]; | | 3311 | bw += sc->sc_bws[(i * nslots + j) % OHCI_NO_INTRS]; |
3312 | if (bw < bestbw) { | | 3312 | if (bw < bestbw) { |
3313 | best = i; | | 3313 | best = i; |
3314 | bestbw = bw; | | 3314 | bestbw = bw; |
3315 | } | | 3315 | } |
3316 | } | | 3316 | } |
3317 | DPRINTFN(2, "best=%jd(%jd..%jd) bestbw=%jd", best, slow, shigh, bestbw); | | 3317 | DPRINTFN(2, "best=%jd(%jd..%jd) bestbw=%jd", best, slow, shigh, bestbw); |
3318 | | | 3318 | |
3319 | mutex_enter(&sc->sc_lock); | | 3319 | mutex_enter(&sc->sc_lock); |
3320 | hsed = sc->sc_eds[best]; | | 3320 | hsed = sc->sc_eds[best]; |
3321 | sed->next = hsed->next; | | 3321 | sed->next = hsed->next; |
3322 | usb_syncmem(&hsed->dma, hsed->offs + offsetof(ohci_ed_t, ed_flags), | | 3322 | usb_syncmem(&hsed->dma, hsed->offs + offsetof(ohci_ed_t, ed_flags), |
3323 | sizeof(hsed->ed.ed_flags), | | 3323 | sizeof(hsed->ed.ed_flags), |
3324 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3324 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3325 | sed->ed.ed_nexted = hsed->ed.ed_nexted; | | 3325 | sed->ed.ed_nexted = hsed->ed.ed_nexted; |
3326 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | | 3326 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), |
3327 | sizeof(sed->ed.ed_flags), | | 3327 | sizeof(sed->ed.ed_flags), |
3328 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3328 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3329 | hsed->next = sed; | | 3329 | hsed->next = sed; |
3330 | hsed->ed.ed_nexted = HTOO32(sed->physaddr); | | 3330 | hsed->ed.ed_nexted = HTOO32(sed->physaddr); |
3331 | usb_syncmem(&hsed->dma, hsed->offs + offsetof(ohci_ed_t, ed_flags), | | 3331 | usb_syncmem(&hsed->dma, hsed->offs + offsetof(ohci_ed_t, ed_flags), |
3332 | sizeof(hsed->ed.ed_flags), | | 3332 | sizeof(hsed->ed.ed_flags), |
3333 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3333 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3334 | mutex_exit(&sc->sc_lock); | | 3334 | mutex_exit(&sc->sc_lock); |
3335 | | | 3335 | |
3336 | for (j = 0; j < nslots; j++) | | 3336 | for (j = 0; j < nslots; j++) |
3337 | ++sc->sc_bws[(best * nslots + j) % OHCI_NO_INTRS]; | | 3337 | ++sc->sc_bws[(best * nslots + j) % OHCI_NO_INTRS]; |
3338 | opipe->intr.nslots = nslots; | | 3338 | opipe->intr.nslots = nslots; |
3339 | opipe->intr.pos = best; | | 3339 | opipe->intr.pos = best; |
3340 | | | 3340 | |
3341 | DPRINTFN(5, "returns %#jx", (uintptr_t)opipe, 0, 0, 0); | | 3341 | DPRINTFN(5, "returns %#jx", (uintptr_t)opipe, 0, 0, 0); |
3342 | return USBD_NORMAL_COMPLETION; | | 3342 | return USBD_NORMAL_COMPLETION; |
3343 | } | | 3343 | } |
3344 | | | 3344 | |
3345 | /***********************/ | | 3345 | /***********************/ |
3346 | | | 3346 | |
3347 | Static int | | 3347 | Static int |
3348 | ohci_device_isoc_init(struct usbd_xfer *xfer) | | 3348 | ohci_device_isoc_init(struct usbd_xfer *xfer) |
3349 | { | | 3349 | { |
3350 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3350 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3351 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3351 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3352 | ohci_soft_itd_t *sitd; | | 3352 | ohci_soft_itd_t *sitd; |
3353 | size_t i; | | 3353 | size_t i; |
3354 | int err; | | 3354 | int err; |
3355 | | | 3355 | |
3356 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3356 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3357 | | | 3357 | |
3358 | DPRINTFN(1, "xfer %#jx len %jd flags %jd", (uintptr_t)xfer, | | 3358 | DPRINTFN(1, "xfer %#jx len %jd flags %jd", (uintptr_t)xfer, |
3359 | xfer->ux_length, xfer->ux_flags, 0); | | 3359 | xfer->ux_length, xfer->ux_flags, 0); |
3360 | | | 3360 | |
3361 | const size_t nfsitd = | | 3361 | const size_t nfsitd = howmany(xfer->ux_nframes, OHCI_ITD_NOFFSET); |
3362 | (xfer->ux_nframes + OHCI_ITD_NOFFSET - 1) / OHCI_ITD_NOFFSET; | | | |
3363 | const size_t nbsitd = xfer->ux_bufsize / OHCI_PAGE_SIZE; | | 3362 | const size_t nbsitd = xfer->ux_bufsize / OHCI_PAGE_SIZE; |
3364 | const size_t nsitd = MAX(nfsitd, nbsitd) + 1; | | 3363 | const size_t nsitd = MAX(nfsitd, nbsitd) + 1; |
3365 | | | 3364 | |
3366 | ox->ox_sitds = kmem_zalloc(sizeof(ohci_soft_itd_t *) * nsitd, | | 3365 | ox->ox_sitds = kmem_zalloc(sizeof(ohci_soft_itd_t *) * nsitd, |
3367 | KM_SLEEP); | | 3366 | KM_SLEEP); |
3368 | ox->ox_nsitd = nsitd; | | 3367 | ox->ox_nsitd = nsitd; |
3369 | | | 3368 | |
3370 | for (i = 0; i < nsitd; i++) { | | 3369 | for (i = 0; i < nsitd; i++) { |
3371 | /* Allocate next ITD */ | | 3370 | /* Allocate next ITD */ |
3372 | sitd = ohci_alloc_sitd(sc); | | 3371 | sitd = ohci_alloc_sitd(sc); |
3373 | if (sitd == NULL) { | | 3372 | if (sitd == NULL) { |
3374 | err = ENOMEM; | | 3373 | err = ENOMEM; |
3375 | goto fail; | | 3374 | goto fail; |
3376 | } | | 3375 | } |
3377 | ox->ox_sitds[i] = sitd; | | 3376 | ox->ox_sitds[i] = sitd; |
3378 | sitd->xfer = xfer; | | 3377 | sitd->xfer = xfer; |
3379 | sitd->flags = 0; | | 3378 | sitd->flags = 0; |
3380 | } | | 3379 | } |
3381 | | | 3380 | |
3382 | return 0; | | 3381 | return 0; |
3383 | fail: | | 3382 | fail: |
3384 | for (; i > 0;) { | | 3383 | for (; i > 0;) { |
3385 | ohci_free_sitd(sc, ox->ox_sitds[--i]); | | 3384 | ohci_free_sitd(sc, ox->ox_sitds[--i]); |
3386 | } | | 3385 | } |
3387 | return err; | | 3386 | return err; |
3388 | } | | 3387 | } |
3389 | | | 3388 | |
3390 | Static void | | 3389 | Static void |
3391 | ohci_device_isoc_fini(struct usbd_xfer *xfer) | | 3390 | ohci_device_isoc_fini(struct usbd_xfer *xfer) |
3392 | { | | 3391 | { |
3393 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3392 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3394 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3393 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3395 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 3394 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
3396 | | | 3395 | |
3397 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3396 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3398 | | | 3397 | |
3399 | mutex_enter(&sc->sc_lock); | | 3398 | mutex_enter(&sc->sc_lock); |
3400 | for (size_t i = 0; i < ox->ox_nsitd; i++) { | | 3399 | for (size_t i = 0; i < ox->ox_nsitd; i++) { |
3401 | if (ox->ox_sitds[i] != opipe->tail.itd) { | | 3400 | if (ox->ox_sitds[i] != opipe->tail.itd) { |
3402 | ohci_free_sitd_locked(sc, ox->ox_sitds[i]); | | 3401 | ohci_free_sitd_locked(sc, ox->ox_sitds[i]); |
3403 | } | | 3402 | } |
3404 | } | | 3403 | } |
3405 | mutex_exit(&sc->sc_lock); | | 3404 | mutex_exit(&sc->sc_lock); |
3406 | | | 3405 | |
3407 | if (ox->ox_nsitd) { | | 3406 | if (ox->ox_nsitd) { |
3408 | const size_t sz = sizeof(ohci_soft_itd_t *) * ox->ox_nsitd; | | 3407 | const size_t sz = sizeof(ohci_soft_itd_t *) * ox->ox_nsitd; |
3409 | kmem_free(ox->ox_sitds, sz); | | 3408 | kmem_free(ox->ox_sitds, sz); |
3410 | } | | 3409 | } |
3411 | } | | 3410 | } |
3412 | | | 3411 | |
3413 | | | 3412 | |
3414 | usbd_status | | 3413 | usbd_status |
3415 | ohci_device_isoc_transfer(struct usbd_xfer *xfer) | | 3414 | ohci_device_isoc_transfer(struct usbd_xfer *xfer) |
3416 | { | | 3415 | { |
3417 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3416 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3418 | usbd_status __diagused err; | | 3417 | usbd_status __diagused err; |
3419 | | | 3418 | |
3420 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3419 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3421 | | | 3420 | |
3422 | DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 3421 | DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
3423 | | | 3422 | |
3424 | /* Put it on our queue, */ | | 3423 | /* Put it on our queue, */ |
3425 | mutex_enter(&sc->sc_lock); | | 3424 | mutex_enter(&sc->sc_lock); |
3426 | err = usb_insert_transfer(xfer); | | 3425 | err = usb_insert_transfer(xfer); |
3427 | mutex_exit(&sc->sc_lock); | | 3426 | mutex_exit(&sc->sc_lock); |
3428 | | | 3427 | |
3429 | KASSERT(err == USBD_NORMAL_COMPLETION); | | 3428 | KASSERT(err == USBD_NORMAL_COMPLETION); |
3430 | | | 3429 | |
3431 | /* insert into schedule, */ | | 3430 | /* insert into schedule, */ |
3432 | ohci_device_isoc_enter(xfer); | | 3431 | ohci_device_isoc_enter(xfer); |
3433 | | | 3432 | |
3434 | /* and start if the pipe wasn't running */ | | 3433 | /* and start if the pipe wasn't running */ |
3435 | return USBD_IN_PROGRESS; | | 3434 | return USBD_IN_PROGRESS; |
3436 | } | | 3435 | } |
3437 | | | 3436 | |
3438 | void | | 3437 | void |
3439 | ohci_device_isoc_enter(struct usbd_xfer *xfer) | | 3438 | ohci_device_isoc_enter(struct usbd_xfer *xfer) |
3440 | { | | 3439 | { |
3441 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3440 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3442 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 3441 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
3443 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3442 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3444 | ohci_soft_ed_t *sed = opipe->sed; | | 3443 | ohci_soft_ed_t *sed = opipe->sed; |
3445 | ohci_soft_itd_t *sitd, *nsitd, *tail; | | 3444 | ohci_soft_itd_t *sitd, *nsitd, *tail; |
3446 | ohci_physaddr_t buf, offs, noffs, bp0; | | 3445 | ohci_physaddr_t buf, offs, noffs, bp0; |
3447 | int i, ncur, nframes; | | 3446 | int i, ncur, nframes; |
3448 | | | 3447 | |
3449 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3448 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3450 | DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 3449 | DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
3451 | | | 3450 | |
3452 | mutex_enter(&sc->sc_lock); | | 3451 | mutex_enter(&sc->sc_lock); |
3453 | | | 3452 | |
3454 | if (sc->sc_dying) { | | 3453 | if (sc->sc_dying) { |
3455 | mutex_exit(&sc->sc_lock); | | 3454 | mutex_exit(&sc->sc_lock); |
3456 | return; | | 3455 | return; |
3457 | } | | 3456 | } |
3458 | | | 3457 | |
3459 | struct isoc *isoc = &opipe->isoc; | | 3458 | struct isoc *isoc = &opipe->isoc; |
3460 | | | 3459 | |
3461 | DPRINTFN(1, "used=%jd next=%jd xfer=%#jx nframes=%jd", | | 3460 | DPRINTFN(1, "used=%jd next=%jd xfer=%#jx nframes=%jd", |
3462 | isoc->inuse, isoc->next, (uintptr_t)xfer, xfer->ux_nframes); | | 3461 | isoc->inuse, isoc->next, (uintptr_t)xfer, xfer->ux_nframes); |
3463 | | | 3462 | |
3464 | if (isoc->next == -1) { | | 3463 | if (isoc->next == -1) { |
3465 | /* Not in use yet, schedule it a few frames ahead. */ | | 3464 | /* Not in use yet, schedule it a few frames ahead. */ |
3466 | isoc->next = O32TOH(sc->sc_hcca->hcca_frame_number) + 5; | | 3465 | isoc->next = O32TOH(sc->sc_hcca->hcca_frame_number) + 5; |
3467 | DPRINTFN(2,"start next=%jd", isoc->next, 0, 0, 0); | | 3466 | DPRINTFN(2,"start next=%jd", isoc->next, 0, 0, 0); |
3468 | } | | 3467 | } |
3469 | | | 3468 | |
3470 | sitd = opipe->tail.itd; | | 3469 | sitd = opipe->tail.itd; |
3471 | opipe->tail.itd = ox->ox_sitds[0]; | | 3470 | opipe->tail.itd = ox->ox_sitds[0]; |
3472 | ox->ox_sitds[0] = sitd; | | 3471 | ox->ox_sitds[0] = sitd; |
3473 | | | 3472 | |
3474 | buf = DMAADDR(&xfer->ux_dmabuf, 0); | | 3473 | buf = DMAADDR(&xfer->ux_dmabuf, 0); |
3475 | bp0 = OHCI_PAGE(buf); | | 3474 | bp0 = OHCI_PAGE(buf); |
3476 | offs = OHCI_PAGE_OFFSET(buf); | | 3475 | offs = OHCI_PAGE_OFFSET(buf); |
3477 | nframes = xfer->ux_nframes; | | 3476 | nframes = xfer->ux_nframes; |
3478 | xfer->ux_hcpriv = sitd; | | 3477 | xfer->ux_hcpriv = sitd; |
3479 | size_t j = 1; | | 3478 | size_t j = 1; |
3480 | for (i = ncur = 0; i < nframes; i++, ncur++) { | | 3479 | for (i = ncur = 0; i < nframes; i++, ncur++) { |
3481 | noffs = offs + xfer->ux_frlengths[i]; | | 3480 | noffs = offs + xfer->ux_frlengths[i]; |
3482 | if (ncur == OHCI_ITD_NOFFSET || /* all offsets used */ | | 3481 | if (ncur == OHCI_ITD_NOFFSET || /* all offsets used */ |
3483 | OHCI_PAGE(buf + noffs) > bp0 + OHCI_PAGE_SIZE) { /* too many page crossings */ | | 3482 | OHCI_PAGE(buf + noffs) > bp0 + OHCI_PAGE_SIZE) { /* too many page crossings */ |
3484 | | | 3483 | |
3485 | /* Allocate next ITD */ | | 3484 | /* Allocate next ITD */ |
3486 | nsitd = ox->ox_sitds[j++]; | | 3485 | nsitd = ox->ox_sitds[j++]; |
3487 | KASSERT(nsitd != NULL); | | 3486 | KASSERT(nsitd != NULL); |
3488 | KASSERT(j < ox->ox_nsitd); | | 3487 | KASSERT(j < ox->ox_nsitd); |
3489 | | | 3488 | |
3490 | /* Fill current ITD */ | | 3489 | /* Fill current ITD */ |
3491 | sitd->itd.itd_flags = HTOO32( | | 3490 | sitd->itd.itd_flags = HTOO32( |
3492 | OHCI_ITD_NOCC | | | 3491 | OHCI_ITD_NOCC | |
3493 | OHCI_ITD_SET_SF(isoc->next) | | | 3492 | OHCI_ITD_SET_SF(isoc->next) | |
3494 | OHCI_ITD_SET_DI(6) | /* delay intr a little */ | | 3493 | OHCI_ITD_SET_DI(6) | /* delay intr a little */ |
3495 | OHCI_ITD_SET_FC(ncur)); | | 3494 | OHCI_ITD_SET_FC(ncur)); |
3496 | sitd->itd.itd_bp0 = HTOO32(bp0); | | 3495 | sitd->itd.itd_bp0 = HTOO32(bp0); |
3497 | sitd->itd.itd_nextitd = HTOO32(nsitd->physaddr); | | 3496 | sitd->itd.itd_nextitd = HTOO32(nsitd->physaddr); |
3498 | sitd->itd.itd_be = HTOO32(bp0 + offs - 1); | | 3497 | sitd->itd.itd_be = HTOO32(bp0 + offs - 1); |
3499 | sitd->nextitd = nsitd; | | 3498 | sitd->nextitd = nsitd; |
3500 | sitd->xfer = xfer; | | 3499 | sitd->xfer = xfer; |
3501 | sitd->flags = 0; | | 3500 | sitd->flags = 0; |
3502 | #ifdef DIAGNOSTIC | | 3501 | #ifdef DIAGNOSTIC |
3503 | sitd->isdone = false; | | 3502 | sitd->isdone = false; |
3504 | #endif | | 3503 | #endif |
3505 | ohci_hash_add_itd(sc, sitd); | | 3504 | ohci_hash_add_itd(sc, sitd); |
3506 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), | | 3505 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), |
3507 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3506 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3508 | | | 3507 | |
3509 | sitd = nsitd; | | 3508 | sitd = nsitd; |
3510 | isoc->next = isoc->next + ncur; | | 3509 | isoc->next = isoc->next + ncur; |
3511 | bp0 = OHCI_PAGE(buf + offs); | | 3510 | bp0 = OHCI_PAGE(buf + offs); |
3512 | ncur = 0; | | 3511 | ncur = 0; |
3513 | } | | 3512 | } |
3514 | sitd->itd.itd_offset[ncur] = HTOO16(OHCI_ITD_MK_OFFS(offs)); | | 3513 | sitd->itd.itd_offset[ncur] = HTOO16(OHCI_ITD_MK_OFFS(offs)); |
3515 | offs = noffs; | | 3514 | offs = noffs; |
3516 | } | | 3515 | } |
3517 | KASSERT(j <= ox->ox_nsitd); | | 3516 | KASSERT(j <= ox->ox_nsitd); |
3518 | | | 3517 | |
3519 | /* point at sentinel */ | | 3518 | /* point at sentinel */ |
3520 | tail = opipe->tail.itd; | | 3519 | tail = opipe->tail.itd; |
3521 | memset(&tail->itd, 0, sizeof(tail->itd)); | | 3520 | memset(&tail->itd, 0, sizeof(tail->itd)); |
3522 | tail->nextitd = NULL; | | 3521 | tail->nextitd = NULL; |
3523 | tail->xfer = NULL; | | 3522 | tail->xfer = NULL; |
3524 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->itd), | | 3523 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->itd), |
3525 | BUS_DMASYNC_PREWRITE); | | 3524 | BUS_DMASYNC_PREWRITE); |
3526 | | | 3525 | |
3527 | /* Fixup last used ITD */ | | 3526 | /* Fixup last used ITD */ |
3528 | sitd->itd.itd_flags = HTOO32( | | 3527 | sitd->itd.itd_flags = HTOO32( |
3529 | OHCI_ITD_NOCC | | | 3528 | OHCI_ITD_NOCC | |
3530 | OHCI_ITD_SET_SF(isoc->next) | | | 3529 | OHCI_ITD_SET_SF(isoc->next) | |
3531 | OHCI_ITD_SET_DI(0) | | | 3530 | OHCI_ITD_SET_DI(0) | |
3532 | OHCI_ITD_SET_FC(ncur)); | | 3531 | OHCI_ITD_SET_FC(ncur)); |
3533 | sitd->itd.itd_bp0 = HTOO32(bp0); | | 3532 | sitd->itd.itd_bp0 = HTOO32(bp0); |
3534 | sitd->itd.itd_nextitd = HTOO32(tail->physaddr); | | 3533 | sitd->itd.itd_nextitd = HTOO32(tail->physaddr); |
3535 | sitd->itd.itd_be = HTOO32(bp0 + offs - 1); | | 3534 | sitd->itd.itd_be = HTOO32(bp0 + offs - 1); |
3536 | sitd->nextitd = tail; | | 3535 | sitd->nextitd = tail; |
3537 | sitd->xfer = xfer; | | 3536 | sitd->xfer = xfer; |
3538 | sitd->flags = OHCI_CALL_DONE; | | 3537 | sitd->flags = OHCI_CALL_DONE; |
3539 | #ifdef DIAGNOSTIC | | 3538 | #ifdef DIAGNOSTIC |
3540 | sitd->isdone = false; | | 3539 | sitd->isdone = false; |
3541 | #endif | | 3540 | #endif |
3542 | ohci_hash_add_itd(sc, sitd); | | 3541 | ohci_hash_add_itd(sc, sitd); |
3543 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), | | 3542 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), |
3544 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3543 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3545 | | | 3544 | |
3546 | isoc->next = isoc->next + ncur; | | 3545 | isoc->next = isoc->next + ncur; |
3547 | isoc->inuse += nframes; | | 3546 | isoc->inuse += nframes; |
3548 | | | 3547 | |
3549 | /* XXX pretend we did it all */ | | 3548 | /* XXX pretend we did it all */ |
3550 | xfer->ux_actlen = offs; | | 3549 | xfer->ux_actlen = offs; |
3551 | xfer->ux_status = USBD_IN_PROGRESS; | | 3550 | xfer->ux_status = USBD_IN_PROGRESS; |
3552 | | | 3551 | |
3553 | #ifdef OHCI_DEBUG | | 3552 | #ifdef OHCI_DEBUG |
3554 | if (ohcidebug >= 5) { | | 3553 | if (ohcidebug >= 5) { |
3555 | DPRINTF("frame=%jd", O32TOH(sc->sc_hcca->hcca_frame_number), | | 3554 | DPRINTF("frame=%jd", O32TOH(sc->sc_hcca->hcca_frame_number), |
3556 | 0, 0, 0); | | 3555 | 0, 0, 0); |
3557 | ohci_dump_itds(sc, xfer->ux_hcpriv); | | 3556 | ohci_dump_itds(sc, xfer->ux_hcpriv); |
3558 | ohci_dump_ed(sc, sed); | | 3557 | ohci_dump_ed(sc, sed); |
3559 | } | | 3558 | } |
3560 | #endif | | 3559 | #endif |
3561 | | | 3560 | |
3562 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3561 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3563 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3562 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3564 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | | 3563 | sed->ed.ed_tailp = HTOO32(tail->physaddr); |
3565 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | | 3564 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); |
3566 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | | 3565 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), |
3567 | sizeof(sed->ed.ed_flags), | | 3566 | sizeof(sed->ed.ed_flags), |
3568 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3567 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3569 | mutex_exit(&sc->sc_lock); | | 3568 | mutex_exit(&sc->sc_lock); |
3570 | } | | 3569 | } |
3571 | | | 3570 | |
3572 | void | | 3571 | void |
3573 | ohci_device_isoc_abort(struct usbd_xfer *xfer) | | 3572 | ohci_device_isoc_abort(struct usbd_xfer *xfer) |
3574 | { | | 3573 | { |
3575 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 3574 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
3576 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3575 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3577 | ohci_soft_ed_t *sed; | | 3576 | ohci_soft_ed_t *sed; |
3578 | ohci_soft_itd_t *sitd; | | 3577 | ohci_soft_itd_t *sitd; |
3579 | | | 3578 | |
3580 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3579 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3581 | DPRINTFN(1, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 3580 | DPRINTFN(1, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
3582 | | | 3581 | |
3583 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3582 | KASSERT(mutex_owned(&sc->sc_lock)); |
3584 | | | 3583 | |
3585 | /* Transfer is already done. */ | | 3584 | /* Transfer is already done. */ |
3586 | if (xfer->ux_status != USBD_NOT_STARTED && | | 3585 | if (xfer->ux_status != USBD_NOT_STARTED && |
3587 | xfer->ux_status != USBD_IN_PROGRESS) { | | 3586 | xfer->ux_status != USBD_IN_PROGRESS) { |
3588 | printf("ohci_device_isoc_abort: early return\n"); | | 3587 | printf("ohci_device_isoc_abort: early return\n"); |
3589 | goto done; | | 3588 | goto done; |
3590 | } | | 3589 | } |
3591 | | | 3590 | |
3592 | /* Give xfer the requested abort code. */ | | 3591 | /* Give xfer the requested abort code. */ |
3593 | xfer->ux_status = USBD_CANCELLED; | | 3592 | xfer->ux_status = USBD_CANCELLED; |
3594 | | | 3593 | |
3595 | sed = opipe->sed; | | 3594 | sed = opipe->sed; |
3596 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3595 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3597 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3596 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3598 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); /* force hardware skip */ | | 3597 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); /* force hardware skip */ |
3599 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | | 3598 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), |
3600 | sizeof(sed->ed.ed_flags), | | 3599 | sizeof(sed->ed.ed_flags), |
3601 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3600 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3602 | | | 3601 | |
3603 | sitd = xfer->ux_hcpriv; | | 3602 | sitd = xfer->ux_hcpriv; |
3604 | KASSERT(sitd); | | 3603 | KASSERT(sitd); |
3605 | | | 3604 | |
3606 | usb_delay_ms_locked(&sc->sc_bus, OHCI_ITD_NOFFSET, &sc->sc_lock); | | 3605 | usb_delay_ms_locked(&sc->sc_bus, OHCI_ITD_NOFFSET, &sc->sc_lock); |
3607 | | | 3606 | |
3608 | for (; sitd->xfer == xfer; sitd = sitd->nextitd) { | | 3607 | for (; sitd->xfer == xfer; sitd = sitd->nextitd) { |
3609 | ohci_hash_rem_itd(sc, sitd); | | 3608 | ohci_hash_rem_itd(sc, sitd); |
3610 | #ifdef DIAGNOSTIC | | 3609 | #ifdef DIAGNOSTIC |
3611 | DPRINTFN(1, "abort sets done sitd=%#jx", (uintptr_t)sitd, | | 3610 | DPRINTFN(1, "abort sets done sitd=%#jx", (uintptr_t)sitd, |
3612 | 0, 0, 0); | | 3611 | 0, 0, 0); |
3613 | sitd->isdone = true; | | 3612 | sitd->isdone = true; |
3614 | #endif | | 3613 | #endif |
3615 | } | | 3614 | } |
3616 | | | 3615 | |
3617 | /* Run callback. */ | | 3616 | /* Run callback. */ |
3618 | usb_transfer_complete(xfer); | | 3617 | usb_transfer_complete(xfer); |
3619 | | | 3618 | |
3620 | sed->ed.ed_headp = HTOO32(sitd->physaddr); /* unlink TDs */ | | 3619 | sed->ed.ed_headp = HTOO32(sitd->physaddr); /* unlink TDs */ |
3621 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); /* remove hardware skip */ | | 3620 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); /* remove hardware skip */ |
3622 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3621 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3623 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3622 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3624 | | | 3623 | |
3625 | done: | | 3624 | done: |
3626 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3625 | KASSERT(mutex_owned(&sc->sc_lock)); |
3627 | } | | 3626 | } |
3628 | | | 3627 | |
3629 | void | | 3628 | void |
3630 | ohci_device_isoc_done(struct usbd_xfer *xfer) | | 3629 | ohci_device_isoc_done(struct usbd_xfer *xfer) |
3631 | { | | 3630 | { |
3632 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3631 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3633 | DPRINTFN(1, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 3632 | DPRINTFN(1, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
3634 | } | | 3633 | } |
3635 | | | 3634 | |
3636 | usbd_status | | 3635 | usbd_status |
3637 | ohci_setup_isoc(struct usbd_pipe *pipe) | | 3636 | ohci_setup_isoc(struct usbd_pipe *pipe) |
3638 | { | | 3637 | { |
3639 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 3638 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
3640 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 3639 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
3641 | struct isoc *isoc = &opipe->isoc; | | 3640 | struct isoc *isoc = &opipe->isoc; |
3642 | | | 3641 | |
3643 | isoc->next = -1; | | 3642 | isoc->next = -1; |
3644 | isoc->inuse = 0; | | 3643 | isoc->inuse = 0; |
3645 | | | 3644 | |
3646 | mutex_enter(&sc->sc_lock); | | 3645 | mutex_enter(&sc->sc_lock); |
3647 | ohci_add_ed(sc, opipe->sed, sc->sc_isoc_head); | | 3646 | ohci_add_ed(sc, opipe->sed, sc->sc_isoc_head); |
3648 | mutex_exit(&sc->sc_lock); | | 3647 | mutex_exit(&sc->sc_lock); |
3649 | | | 3648 | |
3650 | return USBD_NORMAL_COMPLETION; | | 3649 | return USBD_NORMAL_COMPLETION; |
3651 | } | | 3650 | } |
3652 | | | 3651 | |
3653 | void | | 3652 | void |
3654 | ohci_device_isoc_close(struct usbd_pipe *pipe) | | 3653 | ohci_device_isoc_close(struct usbd_pipe *pipe) |
3655 | { | | 3654 | { |
3656 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 3655 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
3657 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 3656 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
3658 | | | 3657 | |
3659 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3658 | KASSERT(mutex_owned(&sc->sc_lock)); |
3660 | | | 3659 | |
3661 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3660 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3662 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); | | 3661 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); |
3663 | ohci_close_pipe(pipe, sc->sc_isoc_head); | | 3662 | ohci_close_pipe(pipe, sc->sc_isoc_head); |
3664 | #ifdef DIAGNOSTIC | | 3663 | #ifdef DIAGNOSTIC |
3665 | opipe->tail.itd->isdone = true; | | 3664 | opipe->tail.itd->isdone = true; |
3666 | #endif | | 3665 | #endif |
3667 | ohci_free_sitd_locked(sc, opipe->tail.itd); | | 3666 | ohci_free_sitd_locked(sc, opipe->tail.itd); |
3668 | } | | 3667 | } |