| @@ -1,1226 +1,1227 @@ | | | @@ -1,1226 +1,1227 @@ |
1 | /* $NetBSD: ehci.c,v 1.234.2.54 2015/10/11 09:17:51 skrll Exp $ */ | | 1 | /* $NetBSD: ehci.c,v 1.234.2.55 2015/10/16 17:00:15 skrll Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2004-2012 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2004-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), Charles M. Hannum, | | 8 | * by Lennart Augustsson (lennart@augustsson.net), Charles M. Hannum, |
9 | * Jeremy Morse (jeremy.morse@gmail.com), Jared D. McNeill | | 9 | * Jeremy Morse (jeremy.morse@gmail.com), Jared D. McNeill |
10 | * (jmcneill@invisible.ca) and Matthew R. Green (mrg@eterna.com.au). | | 10 | * (jmcneill@invisible.ca) and Matthew R. Green (mrg@eterna.com.au). |
11 | * | | 11 | * |
12 | * Redistribution and use in source and binary forms, with or without | | 12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions | | 13 | * modification, are permitted provided that the following conditions |
14 | * are met: | | 14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright | | 15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. | | 16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright | | 17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the | | 18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. | | 19 | * documentation and/or other materials provided with the distribution. |
20 | * | | 20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | * POSSIBILITY OF SUCH DAMAGE. | | 31 | * POSSIBILITY OF SUCH DAMAGE. |
32 | */ | | 32 | */ |
33 | | | 33 | |
34 | /* | | 34 | /* |
35 | * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. | | 35 | * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. |
36 | * | | 36 | * |
37 | * The EHCI 1.0 spec can be found at | | 37 | * The EHCI 1.0 spec can be found at |
38 | * http://www.intel.com/technology/usb/spec.htm | | 38 | * http://www.intel.com/technology/usb/spec.htm |
39 | * and the USB 2.0 spec at | | 39 | * and the USB 2.0 spec at |
40 | * http://www.usb.org/developers/docs/ | | 40 | * http://www.usb.org/developers/docs/ |
41 | * | | 41 | * |
42 | */ | | 42 | */ |
43 | | | 43 | |
44 | /* | | 44 | /* |
45 | * TODO: | | 45 | * TODO: |
46 | * 1) hold off explorations by companion controllers until ehci has started. | | 46 | * 1) hold off explorations by companion controllers until ehci has started. |
47 | * | | 47 | * |
48 | * 2) The hub driver needs to handle and schedule the transaction translator, | | 48 | * 2) The hub driver needs to handle and schedule the transaction translator, |
49 | * to assign place in frame where different devices get to go. See chapter | | 49 | * to assign place in frame where different devices get to go. See chapter |
50 | * on hubs in USB 2.0 for details. | | 50 | * on hubs in USB 2.0 for details. |
51 | * | | 51 | * |
52 | * 3) Command failures are not recovered correctly. | | 52 | * 3) Command failures are not recovered correctly. |
53 | */ | | 53 | */ |
54 | | | 54 | |
55 | #include <sys/cdefs.h> | | 55 | #include <sys/cdefs.h> |
56 | __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.54 2015/10/11 09:17:51 skrll Exp $"); | | 56 | __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.55 2015/10/16 17:00:15 skrll Exp $"); |
57 | | | 57 | |
58 | #include "ohci.h" | | 58 | #include "ohci.h" |
59 | #include "uhci.h" | | 59 | #include "uhci.h" |
60 | | | 60 | |
61 | #ifdef _KERNEL_OPT | | 61 | #ifdef _KERNEL_OPT |
62 | #include "opt_usb.h" | | 62 | #include "opt_usb.h" |
63 | #endif | | 63 | #endif |
64 | | | 64 | |
65 | #include <sys/param.h> | | 65 | #include <sys/param.h> |
66 | | | 66 | |
67 | #include <sys/bus.h> | | 67 | #include <sys/bus.h> |
68 | #include <sys/cpu.h> | | 68 | #include <sys/cpu.h> |
69 | #include <sys/device.h> | | 69 | #include <sys/device.h> |
70 | #include <sys/kernel.h> | | 70 | #include <sys/kernel.h> |
71 | #include <sys/kmem.h> | | 71 | #include <sys/kmem.h> |
72 | #include <sys/mutex.h> | | 72 | #include <sys/mutex.h> |
73 | #include <sys/proc.h> | | 73 | #include <sys/proc.h> |
74 | #include <sys/queue.h> | | 74 | #include <sys/queue.h> |
75 | #include <sys/select.h> | | 75 | #include <sys/select.h> |
76 | #include <sys/sysctl.h> | | 76 | #include <sys/sysctl.h> |
77 | #include <sys/systm.h> | | 77 | #include <sys/systm.h> |
78 | | | 78 | |
79 | #include <machine/endian.h> | | 79 | #include <machine/endian.h> |
80 | | | 80 | |
81 | #include <dev/usb/usb.h> | | 81 | #include <dev/usb/usb.h> |
82 | #include <dev/usb/usbdi.h> | | 82 | #include <dev/usb/usbdi.h> |
83 | #include <dev/usb/usbdivar.h> | | 83 | #include <dev/usb/usbdivar.h> |
84 | #include <dev/usb/usbhist.h> | | 84 | #include <dev/usb/usbhist.h> |
85 | #include <dev/usb/usb_mem.h> | | 85 | #include <dev/usb/usb_mem.h> |
86 | #include <dev/usb/usb_quirks.h> | | 86 | #include <dev/usb/usb_quirks.h> |
87 | | | 87 | |
88 | #include <dev/usb/ehcireg.h> | | 88 | #include <dev/usb/ehcireg.h> |
89 | #include <dev/usb/ehcivar.h> | | 89 | #include <dev/usb/ehcivar.h> |
90 | #include <dev/usb/usbroothub.h> | | 90 | #include <dev/usb/usbroothub.h> |
91 | | | 91 | |
92 | | | 92 | |
93 | #ifdef USB_DEBUG | | 93 | #ifdef USB_DEBUG |
94 | #ifndef EHCI_DEBUG | | 94 | #ifndef EHCI_DEBUG |
95 | #define ehcidebug 0 | | 95 | #define ehcidebug 0 |
96 | #else | | 96 | #else |
97 | static int ehcidebug = 0; | | 97 | static int ehcidebug = 0; |
98 | | | 98 | |
99 | SYSCTL_SETUP(sysctl_hw_ehci_setup, "sysctl hw.ehci setup") | | 99 | SYSCTL_SETUP(sysctl_hw_ehci_setup, "sysctl hw.ehci setup") |
100 | { | | 100 | { |
101 | int err; | | 101 | int err; |
102 | const struct sysctlnode *rnode; | | 102 | const struct sysctlnode *rnode; |
103 | const struct sysctlnode *cnode; | | 103 | const struct sysctlnode *cnode; |
104 | | | 104 | |
105 | err = sysctl_createv(clog, 0, NULL, &rnode, | | 105 | err = sysctl_createv(clog, 0, NULL, &rnode, |
106 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "ehci", | | 106 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "ehci", |
107 | SYSCTL_DESCR("ehci global controls"), | | 107 | SYSCTL_DESCR("ehci global controls"), |
108 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | | 108 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); |
109 | | | 109 | |
110 | if (err) | | 110 | if (err) |
111 | goto fail; | | 111 | goto fail; |
112 | | | 112 | |
113 | /* control debugging printfs */ | | 113 | /* control debugging printfs */ |
114 | err = sysctl_createv(clog, 0, &rnode, &cnode, | | 114 | err = sysctl_createv(clog, 0, &rnode, &cnode, |
115 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | | 115 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
116 | "debug", SYSCTL_DESCR("Enable debugging output"), | | 116 | "debug", SYSCTL_DESCR("Enable debugging output"), |
117 | NULL, 0, &ehcidebug, sizeof(ehcidebug), CTL_CREATE, CTL_EOL); | | 117 | NULL, 0, &ehcidebug, sizeof(ehcidebug), CTL_CREATE, CTL_EOL); |
118 | if (err) | | 118 | if (err) |
119 | goto fail; | | 119 | goto fail; |
120 | | | 120 | |
121 | return; | | 121 | return; |
122 | fail: | | 122 | fail: |
123 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | | 123 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); |
124 | } | | 124 | } |
125 | | | 125 | |
126 | #endif /* EHCI_DEBUG */ | | 126 | #endif /* EHCI_DEBUG */ |
127 | #endif /* USB_DEBUG */ | | 127 | #endif /* USB_DEBUG */ |
128 | | | 128 | |
129 | struct ehci_pipe { | | 129 | struct ehci_pipe { |
130 | struct usbd_pipe pipe; | | 130 | struct usbd_pipe pipe; |
131 | int nexttoggle; | | 131 | int nexttoggle; |
132 | | | 132 | |
133 | ehci_soft_qh_t *sqh; | | 133 | ehci_soft_qh_t *sqh; |
134 | union { | | 134 | union { |
135 | /* Control pipe */ | | 135 | /* Control pipe */ |
136 | struct { | | 136 | struct { |
137 | usb_dma_t reqdma; | | 137 | usb_dma_t reqdma; |
138 | } ctrl; | | 138 | } ctrl; |
139 | /* Interrupt pipe */ | | 139 | /* Interrupt pipe */ |
140 | struct { | | 140 | struct { |
141 | u_int length; | | 141 | u_int length; |
142 | } intr; | | 142 | } intr; |
143 | /* Iso pipe */ | | 143 | /* Iso pipe */ |
144 | struct { | | 144 | struct { |
145 | u_int next_frame; | | 145 | u_int next_frame; |
146 | u_int cur_xfers; | | 146 | u_int cur_xfers; |
147 | } isoc; | | 147 | } isoc; |
148 | }; | | 148 | }; |
149 | }; | | 149 | }; |
150 | | | 150 | |
151 | Static usbd_status ehci_open(struct usbd_pipe *); | | 151 | Static usbd_status ehci_open(struct usbd_pipe *); |
152 | Static void ehci_poll(struct usbd_bus *); | | 152 | Static void ehci_poll(struct usbd_bus *); |
153 | Static void ehci_softintr(void *); | | 153 | Static void ehci_softintr(void *); |
154 | Static int ehci_intr1(ehci_softc_t *); | | 154 | Static int ehci_intr1(ehci_softc_t *); |
155 | Static void ehci_waitintr(ehci_softc_t *, struct usbd_xfer *); | | 155 | Static void ehci_waitintr(ehci_softc_t *, struct usbd_xfer *); |
156 | Static void ehci_check_intr(ehci_softc_t *, struct ehci_xfer *); | | 156 | Static void ehci_check_intr(ehci_softc_t *, struct ehci_xfer *); |
157 | Static void ehci_check_qh_intr(ehci_softc_t *, struct ehci_xfer *); | | 157 | Static void ehci_check_qh_intr(ehci_softc_t *, struct ehci_xfer *); |
158 | Static void ehci_check_itd_intr(ehci_softc_t *, struct ehci_xfer *); | | 158 | Static void ehci_check_itd_intr(ehci_softc_t *, struct ehci_xfer *); |
159 | Static void ehci_check_sitd_intr(ehci_softc_t *, struct ehci_xfer *); | | 159 | Static void ehci_check_sitd_intr(ehci_softc_t *, struct ehci_xfer *); |
160 | Static void ehci_idone(struct ehci_xfer *); | | 160 | Static void ehci_idone(struct ehci_xfer *); |
161 | Static void ehci_timeout(void *); | | 161 | Static void ehci_timeout(void *); |
162 | Static void ehci_timeout_task(void *); | | 162 | Static void ehci_timeout_task(void *); |
163 | Static void ehci_intrlist_timeout(void *); | | 163 | Static void ehci_intrlist_timeout(void *); |
164 | Static void ehci_doorbell(void *); | | 164 | Static void ehci_doorbell(void *); |
165 | Static void ehci_pcd(void *); | | 165 | Static void ehci_pcd(void *); |
166 | | | 166 | |
167 | Static struct usbd_xfer * | | 167 | Static struct usbd_xfer * |
168 | ehci_allocx(struct usbd_bus *, unsigned int); | | 168 | ehci_allocx(struct usbd_bus *, unsigned int); |
169 | Static void ehci_freex(struct usbd_bus *, struct usbd_xfer *); | | 169 | Static void ehci_freex(struct usbd_bus *, struct usbd_xfer *); |
170 | Static void ehci_get_lock(struct usbd_bus *, kmutex_t **); | | 170 | Static void ehci_get_lock(struct usbd_bus *, kmutex_t **); |
171 | Static int ehci_roothub_ctrl(struct usbd_bus *, | | 171 | Static int ehci_roothub_ctrl(struct usbd_bus *, |
172 | usb_device_request_t *, void *, int); | | 172 | usb_device_request_t *, void *, int); |
173 | | | 173 | |
174 | Static usbd_status ehci_root_intr_transfer(struct usbd_xfer *); | | 174 | Static usbd_status ehci_root_intr_transfer(struct usbd_xfer *); |
175 | Static usbd_status ehci_root_intr_start(struct usbd_xfer *); | | 175 | Static usbd_status ehci_root_intr_start(struct usbd_xfer *); |
176 | Static void ehci_root_intr_abort(struct usbd_xfer *); | | 176 | Static void ehci_root_intr_abort(struct usbd_xfer *); |
177 | Static void ehci_root_intr_close(struct usbd_pipe *); | | 177 | Static void ehci_root_intr_close(struct usbd_pipe *); |
178 | Static void ehci_root_intr_done(struct usbd_xfer *); | | 178 | Static void ehci_root_intr_done(struct usbd_xfer *); |
179 | | | 179 | |
180 | Static usbd_status ehci_device_ctrl_transfer(struct usbd_xfer *); | | 180 | Static usbd_status ehci_device_ctrl_transfer(struct usbd_xfer *); |
181 | Static usbd_status ehci_device_ctrl_start(struct usbd_xfer *); | | 181 | Static usbd_status ehci_device_ctrl_start(struct usbd_xfer *); |
182 | Static void ehci_device_ctrl_abort(struct usbd_xfer *); | | 182 | Static void ehci_device_ctrl_abort(struct usbd_xfer *); |
183 | Static void ehci_device_ctrl_close(struct usbd_pipe *); | | 183 | Static void ehci_device_ctrl_close(struct usbd_pipe *); |
184 | Static void ehci_device_ctrl_done(struct usbd_xfer *); | | 184 | Static void ehci_device_ctrl_done(struct usbd_xfer *); |
185 | | | 185 | |
186 | Static usbd_status ehci_device_bulk_transfer(struct usbd_xfer *); | | 186 | Static usbd_status ehci_device_bulk_transfer(struct usbd_xfer *); |
187 | Static usbd_status ehci_device_bulk_start(struct usbd_xfer *); | | 187 | Static usbd_status ehci_device_bulk_start(struct usbd_xfer *); |
188 | Static void ehci_device_bulk_abort(struct usbd_xfer *); | | 188 | Static void ehci_device_bulk_abort(struct usbd_xfer *); |
189 | Static void ehci_device_bulk_close(struct usbd_pipe *); | | 189 | Static void ehci_device_bulk_close(struct usbd_pipe *); |
190 | Static void ehci_device_bulk_done(struct usbd_xfer *); | | 190 | Static void ehci_device_bulk_done(struct usbd_xfer *); |
191 | | | 191 | |
192 | Static usbd_status ehci_device_intr_transfer(struct usbd_xfer *); | | 192 | Static usbd_status ehci_device_intr_transfer(struct usbd_xfer *); |
193 | Static usbd_status ehci_device_intr_start(struct usbd_xfer *); | | 193 | Static usbd_status ehci_device_intr_start(struct usbd_xfer *); |
194 | Static void ehci_device_intr_abort(struct usbd_xfer *); | | 194 | Static void ehci_device_intr_abort(struct usbd_xfer *); |
195 | Static void ehci_device_intr_close(struct usbd_pipe *); | | 195 | Static void ehci_device_intr_close(struct usbd_pipe *); |
196 | Static void ehci_device_intr_done(struct usbd_xfer *); | | 196 | Static void ehci_device_intr_done(struct usbd_xfer *); |
197 | | | 197 | |
198 | Static usbd_status ehci_device_isoc_transfer(struct usbd_xfer *); | | 198 | Static usbd_status ehci_device_isoc_transfer(struct usbd_xfer *); |
199 | Static usbd_status ehci_device_isoc_start(struct usbd_xfer *); | | 199 | Static usbd_status ehci_device_isoc_start(struct usbd_xfer *); |
200 | Static void ehci_device_isoc_abort(struct usbd_xfer *); | | 200 | Static void ehci_device_isoc_abort(struct usbd_xfer *); |
201 | Static void ehci_device_isoc_close(struct usbd_pipe *); | | 201 | Static void ehci_device_isoc_close(struct usbd_pipe *); |
202 | Static void ehci_device_isoc_done(struct usbd_xfer *); | | 202 | Static void ehci_device_isoc_done(struct usbd_xfer *); |
203 | | | 203 | |
204 | Static usbd_status ehci_device_fs_isoc_transfer(struct usbd_xfer *); | | 204 | Static usbd_status ehci_device_fs_isoc_transfer(struct usbd_xfer *); |
205 | Static usbd_status ehci_device_fs_isoc_start(struct usbd_xfer *); | | 205 | Static usbd_status ehci_device_fs_isoc_start(struct usbd_xfer *); |
206 | Static void ehci_device_fs_isoc_abort(struct usbd_xfer *); | | 206 | Static void ehci_device_fs_isoc_abort(struct usbd_xfer *); |
207 | Static void ehci_device_fs_isoc_close(struct usbd_pipe *); | | 207 | Static void ehci_device_fs_isoc_close(struct usbd_pipe *); |
208 | Static void ehci_device_fs_isoc_done(struct usbd_xfer *); | | 208 | Static void ehci_device_fs_isoc_done(struct usbd_xfer *); |
209 | | | 209 | |
210 | Static void ehci_device_clear_toggle(struct usbd_pipe *); | | 210 | Static void ehci_device_clear_toggle(struct usbd_pipe *); |
211 | Static void ehci_noop(struct usbd_pipe *); | | 211 | Static void ehci_noop(struct usbd_pipe *); |
212 | | | 212 | |
213 | Static void ehci_disown(ehci_softc_t *, int, int); | | 213 | Static void ehci_disown(ehci_softc_t *, int, int); |
214 | | | 214 | |
215 | Static ehci_soft_qh_t *ehci_alloc_sqh(ehci_softc_t *); | | 215 | Static ehci_soft_qh_t * ehci_alloc_sqh(ehci_softc_t *); |
216 | Static void ehci_free_sqh(ehci_softc_t *, ehci_soft_qh_t *); | | 216 | Static void ehci_free_sqh(ehci_softc_t *, ehci_soft_qh_t *); |
217 | | | 217 | |
218 | Static ehci_soft_qtd_t *ehci_alloc_sqtd(ehci_softc_t *); | | 218 | Static ehci_soft_qtd_t *ehci_alloc_sqtd(ehci_softc_t *); |
219 | Static void ehci_free_sqtd(ehci_softc_t *, ehci_soft_qtd_t *); | | 219 | Static void ehci_free_sqtd(ehci_softc_t *, ehci_soft_qtd_t *); |
220 | Static usbd_status ehci_alloc_sqtd_chain(struct ehci_pipe *, | | 220 | Static usbd_status ehci_alloc_sqtd_chain(struct ehci_pipe *, |
221 | ehci_softc_t *, int, int, struct usbd_xfer *, | | 221 | ehci_softc_t *, int, int, struct usbd_xfer *, |
222 | ehci_soft_qtd_t **, ehci_soft_qtd_t **); | | 222 | ehci_soft_qtd_t **, ehci_soft_qtd_t **); |
223 | Static void ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qtd_t *, | | 223 | Static void ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qtd_t *, |
224 | ehci_soft_qtd_t *); | | 224 | ehci_soft_qtd_t *); |
225 | | | 225 | |
226 | Static ehci_soft_itd_t *ehci_alloc_itd(ehci_softc_t *); | | 226 | Static ehci_soft_itd_t *ehci_alloc_itd(ehci_softc_t *); |
227 | Static ehci_soft_sitd_t *ehci_alloc_sitd(ehci_softc_t *); | | 227 | Static ehci_soft_sitd_t * |
| | | 228 | ehci_alloc_sitd(ehci_softc_t *); |
228 | Static void ehci_free_itd(ehci_softc_t *, ehci_soft_itd_t *); | | 229 | Static void ehci_free_itd(ehci_softc_t *, ehci_soft_itd_t *); |
229 | Static void ehci_free_sitd(ehci_softc_t *, ehci_soft_sitd_t *); | | 230 | Static void ehci_free_sitd(ehci_softc_t *, ehci_soft_sitd_t *); |
230 | Static void ehci_rem_free_itd_chain(ehci_softc_t *, | | 231 | Static void ehci_rem_free_itd_chain(ehci_softc_t *, |
231 | struct ehci_xfer *); | | 232 | struct ehci_xfer *); |
232 | Static void ehci_rem_free_sitd_chain(ehci_softc_t *, | | 233 | Static void ehci_rem_free_sitd_chain(ehci_softc_t *, |
233 | struct ehci_xfer *); | | 234 | struct ehci_xfer *); |
234 | Static void ehci_abort_isoc_xfer(struct usbd_xfer *, | | 235 | Static void ehci_abort_isoc_xfer(struct usbd_xfer *, |
235 | usbd_status); | | 236 | usbd_status); |
236 | | | 237 | |
237 | Static usbd_status ehci_device_request(struct usbd_xfer *); | | 238 | Static usbd_status ehci_device_request(struct usbd_xfer *); |
238 | | | 239 | |
239 | Static usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *, | | 240 | Static usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *, |
240 | int); | | 241 | int); |
241 | | | 242 | |
242 | Static void ehci_add_qh(ehci_softc_t *, ehci_soft_qh_t *, | | 243 | Static void ehci_add_qh(ehci_softc_t *, ehci_soft_qh_t *, |
243 | ehci_soft_qh_t *); | | 244 | ehci_soft_qh_t *); |
244 | Static void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *, | | 245 | Static void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *, |
245 | ehci_soft_qh_t *); | | 246 | ehci_soft_qh_t *); |
246 | Static void ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *); | | 247 | Static void ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *); |
247 | Static void ehci_sync_hc(ehci_softc_t *); | | 248 | Static void ehci_sync_hc(ehci_softc_t *); |
248 | | | 249 | |
249 | Static void ehci_close_pipe(struct usbd_pipe *, ehci_soft_qh_t *); | | 250 | Static void ehci_close_pipe(struct usbd_pipe *, ehci_soft_qh_t *); |
250 | Static void ehci_abort_xfer(struct usbd_xfer *, usbd_status); | | 251 | Static void ehci_abort_xfer(struct usbd_xfer *, usbd_status); |
251 | | | 252 | |
252 | #ifdef EHCI_DEBUG | | 253 | #ifdef EHCI_DEBUG |
253 | Static ehci_softc_t *theehci; | | 254 | Static ehci_softc_t *theehci; |
254 | void ehci_dump(void); | | 255 | void ehci_dump(void); |
255 | #endif | | 256 | #endif |
256 | | | 257 | |
257 | #ifdef EHCI_DEBUG | | 258 | #ifdef EHCI_DEBUG |
258 | Static void ehci_dump_regs(ehci_softc_t *); | | 259 | Static void ehci_dump_regs(ehci_softc_t *); |
259 | Static void ehci_dump_sqtds(ehci_soft_qtd_t *); | | 260 | Static void ehci_dump_sqtds(ehci_soft_qtd_t *); |
260 | Static void ehci_dump_sqtd(ehci_soft_qtd_t *); | | 261 | Static void ehci_dump_sqtd(ehci_soft_qtd_t *); |
261 | Static void ehci_dump_qtd(ehci_qtd_t *); | | 262 | Static void ehci_dump_qtd(ehci_qtd_t *); |
262 | Static void ehci_dump_sqh(ehci_soft_qh_t *); | | 263 | Static void ehci_dump_sqh(ehci_soft_qh_t *); |
263 | Static void ehci_dump_sitd(struct ehci_soft_itd *); | | 264 | Static void ehci_dump_sitd(struct ehci_soft_itd *); |
264 | Static void ehci_dump_itd(struct ehci_soft_itd *); | | 265 | Static void ehci_dump_itd(struct ehci_soft_itd *); |
265 | Static void ehci_dump_exfer(struct ehci_xfer *); | | 266 | Static void ehci_dump_exfer(struct ehci_xfer *); |
266 | #endif | | 267 | #endif |
267 | | | 268 | |
268 | #define EHCI_NULL htole32(EHCI_LINK_TERMINATE) | | 269 | #define EHCI_NULL htole32(EHCI_LINK_TERMINATE) |
269 | | | 270 | |
270 | #define ehci_add_intr_list(sc, ex) \ | | 271 | #define ehci_add_intr_list(sc, ex) \ |
271 | TAILQ_INSERT_TAIL(&(sc)->sc_intrhead, (ex), ex_next); | | 272 | TAILQ_INSERT_TAIL(&(sc)->sc_intrhead, (ex), ex_next); |
272 | #define ehci_del_intr_list(sc, ex) \ | | 273 | #define ehci_del_intr_list(sc, ex) \ |
273 | do { \ | | 274 | do { \ |
274 | TAILQ_REMOVE(&sc->sc_intrhead, (ex), ex_next); \ | | 275 | TAILQ_REMOVE(&sc->sc_intrhead, (ex), ex_next); \ |
275 | (ex)->ex_next.tqe_prev = NULL; \ | | 276 | (ex)->ex_next.tqe_prev = NULL; \ |
276 | } while (0) | | 277 | } while (0) |
277 | #define ehci_active_intr_list(ex) ((ex)->ex_next.tqe_prev != NULL) | | 278 | #define ehci_active_intr_list(ex) ((ex)->ex_next.tqe_prev != NULL) |
278 | | | 279 | |
279 | Static const struct usbd_bus_methods ehci_bus_methods = { | | 280 | Static const struct usbd_bus_methods ehci_bus_methods = { |
280 | .ubm_open = ehci_open, | | 281 | .ubm_open = ehci_open, |
281 | .ubm_softint = ehci_softintr, | | 282 | .ubm_softint = ehci_softintr, |
282 | .ubm_dopoll = ehci_poll, | | 283 | .ubm_dopoll = ehci_poll, |
283 | .ubm_allocx = ehci_allocx, | | 284 | .ubm_allocx = ehci_allocx, |
284 | .ubm_freex = ehci_freex, | | 285 | .ubm_freex = ehci_freex, |
285 | .ubm_getlock = ehci_get_lock, | | 286 | .ubm_getlock = ehci_get_lock, |
286 | .ubm_rhctrl = ehci_roothub_ctrl, | | 287 | .ubm_rhctrl = ehci_roothub_ctrl, |
287 | }; | | 288 | }; |
288 | | | 289 | |
289 | Static const struct usbd_pipe_methods ehci_root_intr_methods = { | | 290 | Static const struct usbd_pipe_methods ehci_root_intr_methods = { |
290 | .upm_transfer = ehci_root_intr_transfer, | | 291 | .upm_transfer = ehci_root_intr_transfer, |
291 | .upm_start = ehci_root_intr_start, | | 292 | .upm_start = ehci_root_intr_start, |
292 | .upm_abort = ehci_root_intr_abort, | | 293 | .upm_abort = ehci_root_intr_abort, |
293 | .upm_close = ehci_root_intr_close, | | 294 | .upm_close = ehci_root_intr_close, |
294 | .upm_cleartoggle = ehci_noop, | | 295 | .upm_cleartoggle = ehci_noop, |
295 | .upm_done = ehci_root_intr_done, | | 296 | .upm_done = ehci_root_intr_done, |
296 | }; | | 297 | }; |
297 | | | 298 | |
298 | Static const struct usbd_pipe_methods ehci_device_ctrl_methods = { | | 299 | Static const struct usbd_pipe_methods ehci_device_ctrl_methods = { |
299 | .upm_transfer = ehci_device_ctrl_transfer, | | 300 | .upm_transfer = ehci_device_ctrl_transfer, |
300 | .upm_start = ehci_device_ctrl_start, | | 301 | .upm_start = ehci_device_ctrl_start, |
301 | .upm_abort = ehci_device_ctrl_abort, | | 302 | .upm_abort = ehci_device_ctrl_abort, |
302 | .upm_close = ehci_device_ctrl_close, | | 303 | .upm_close = ehci_device_ctrl_close, |
303 | .upm_cleartoggle = ehci_noop, | | 304 | .upm_cleartoggle = ehci_noop, |
304 | .upm_done = ehci_device_ctrl_done, | | 305 | .upm_done = ehci_device_ctrl_done, |
305 | }; | | 306 | }; |
306 | | | 307 | |
307 | Static const struct usbd_pipe_methods ehci_device_intr_methods = { | | 308 | Static const struct usbd_pipe_methods ehci_device_intr_methods = { |
308 | .upm_transfer = ehci_device_intr_transfer, | | 309 | .upm_transfer = ehci_device_intr_transfer, |
309 | .upm_start = ehci_device_intr_start, | | 310 | .upm_start = ehci_device_intr_start, |
310 | .upm_abort = ehci_device_intr_abort, | | 311 | .upm_abort = ehci_device_intr_abort, |
311 | .upm_close = ehci_device_intr_close, | | 312 | .upm_close = ehci_device_intr_close, |
312 | .upm_cleartoggle = ehci_device_clear_toggle, | | 313 | .upm_cleartoggle = ehci_device_clear_toggle, |
313 | .upm_done = ehci_device_intr_done, | | 314 | .upm_done = ehci_device_intr_done, |
314 | }; | | 315 | }; |
315 | | | 316 | |
316 | Static const struct usbd_pipe_methods ehci_device_bulk_methods = { | | 317 | Static const struct usbd_pipe_methods ehci_device_bulk_methods = { |
317 | .upm_transfer = ehci_device_bulk_transfer, | | 318 | .upm_transfer = ehci_device_bulk_transfer, |
318 | .upm_start = ehci_device_bulk_start, | | 319 | .upm_start = ehci_device_bulk_start, |
319 | .upm_abort = ehci_device_bulk_abort, | | 320 | .upm_abort = ehci_device_bulk_abort, |
320 | .upm_close = ehci_device_bulk_close, | | 321 | .upm_close = ehci_device_bulk_close, |
321 | .upm_cleartoggle = ehci_device_clear_toggle, | | 322 | .upm_cleartoggle = ehci_device_clear_toggle, |
322 | .upm_done = ehci_device_bulk_done, | | 323 | .upm_done = ehci_device_bulk_done, |
323 | }; | | 324 | }; |
324 | | | 325 | |
325 | Static const struct usbd_pipe_methods ehci_device_isoc_methods = { | | 326 | Static const struct usbd_pipe_methods ehci_device_isoc_methods = { |
326 | .upm_transfer = ehci_device_isoc_transfer, | | 327 | .upm_transfer = ehci_device_isoc_transfer, |
327 | .upm_start = ehci_device_isoc_start, | | 328 | .upm_start = ehci_device_isoc_start, |
328 | .upm_abort = ehci_device_isoc_abort, | | 329 | .upm_abort = ehci_device_isoc_abort, |
329 | .upm_close = ehci_device_isoc_close, | | 330 | .upm_close = ehci_device_isoc_close, |
330 | .upm_cleartoggle = ehci_noop, | | 331 | .upm_cleartoggle = ehci_noop, |
331 | .upm_done = ehci_device_isoc_done, | | 332 | .upm_done = ehci_device_isoc_done, |
332 | }; | | 333 | }; |
333 | | | 334 | |
334 | Static const struct usbd_pipe_methods ehci_device_fs_isoc_methods = { | | 335 | Static const struct usbd_pipe_methods ehci_device_fs_isoc_methods = { |
335 | .upm_transfer = ehci_device_fs_isoc_transfer, | | 336 | .upm_transfer = ehci_device_fs_isoc_transfer, |
336 | .upm_start = ehci_device_fs_isoc_start, | | 337 | .upm_start = ehci_device_fs_isoc_start, |
337 | .upm_abort = ehci_device_fs_isoc_abort, | | 338 | .upm_abort = ehci_device_fs_isoc_abort, |
338 | .upm_close = ehci_device_fs_isoc_close, | | 339 | .upm_close = ehci_device_fs_isoc_close, |
339 | .upm_cleartoggle = ehci_noop, | | 340 | .upm_cleartoggle = ehci_noop, |
340 | .upm_done = ehci_device_fs_isoc_done, | | 341 | .upm_done = ehci_device_fs_isoc_done, |
341 | }; | | 342 | }; |
342 | | | 343 | |
343 | static const uint8_t revbits[EHCI_MAX_POLLRATE] = { | | 344 | static const uint8_t revbits[EHCI_MAX_POLLRATE] = { |
344 | 0x00,0x40,0x20,0x60,0x10,0x50,0x30,0x70,0x08,0x48,0x28,0x68,0x18,0x58,0x38,0x78, | | 345 | 0x00,0x40,0x20,0x60,0x10,0x50,0x30,0x70,0x08,0x48,0x28,0x68,0x18,0x58,0x38,0x78, |
345 | 0x04,0x44,0x24,0x64,0x14,0x54,0x34,0x74,0x0c,0x4c,0x2c,0x6c,0x1c,0x5c,0x3c,0x7c, | | 346 | 0x04,0x44,0x24,0x64,0x14,0x54,0x34,0x74,0x0c,0x4c,0x2c,0x6c,0x1c,0x5c,0x3c,0x7c, |
346 | 0x02,0x42,0x22,0x62,0x12,0x52,0x32,0x72,0x0a,0x4a,0x2a,0x6a,0x1a,0x5a,0x3a,0x7a, | | 347 | 0x02,0x42,0x22,0x62,0x12,0x52,0x32,0x72,0x0a,0x4a,0x2a,0x6a,0x1a,0x5a,0x3a,0x7a, |
347 | 0x06,0x46,0x26,0x66,0x16,0x56,0x36,0x76,0x0e,0x4e,0x2e,0x6e,0x1e,0x5e,0x3e,0x7e, | | 348 | 0x06,0x46,0x26,0x66,0x16,0x56,0x36,0x76,0x0e,0x4e,0x2e,0x6e,0x1e,0x5e,0x3e,0x7e, |
348 | 0x01,0x41,0x21,0x61,0x11,0x51,0x31,0x71,0x09,0x49,0x29,0x69,0x19,0x59,0x39,0x79, | | 349 | 0x01,0x41,0x21,0x61,0x11,0x51,0x31,0x71,0x09,0x49,0x29,0x69,0x19,0x59,0x39,0x79, |
349 | 0x05,0x45,0x25,0x65,0x15,0x55,0x35,0x75,0x0d,0x4d,0x2d,0x6d,0x1d,0x5d,0x3d,0x7d, | | 350 | 0x05,0x45,0x25,0x65,0x15,0x55,0x35,0x75,0x0d,0x4d,0x2d,0x6d,0x1d,0x5d,0x3d,0x7d, |
350 | 0x03,0x43,0x23,0x63,0x13,0x53,0x33,0x73,0x0b,0x4b,0x2b,0x6b,0x1b,0x5b,0x3b,0x7b, | | 351 | 0x03,0x43,0x23,0x63,0x13,0x53,0x33,0x73,0x0b,0x4b,0x2b,0x6b,0x1b,0x5b,0x3b,0x7b, |
351 | 0x07,0x47,0x27,0x67,0x17,0x57,0x37,0x77,0x0f,0x4f,0x2f,0x6f,0x1f,0x5f,0x3f,0x7f, | | 352 | 0x07,0x47,0x27,0x67,0x17,0x57,0x37,0x77,0x0f,0x4f,0x2f,0x6f,0x1f,0x5f,0x3f,0x7f, |
352 | }; | | 353 | }; |
353 | | | 354 | |
354 | int | | 355 | int |
355 | ehci_init(ehci_softc_t *sc) | | 356 | ehci_init(ehci_softc_t *sc) |
356 | { | | 357 | { |
357 | uint32_t vers, sparams, cparams, hcr; | | 358 | uint32_t vers, sparams, cparams, hcr; |
358 | u_int i; | | 359 | u_int i; |
359 | usbd_status err; | | 360 | usbd_status err; |
360 | ehci_soft_qh_t *sqh; | | 361 | ehci_soft_qh_t *sqh; |
361 | u_int ncomp; | | 362 | u_int ncomp; |
362 | | | 363 | |
363 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); | | 364 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); |
364 | #ifdef EHCI_DEBUG | | 365 | #ifdef EHCI_DEBUG |
365 | theehci = sc; | | 366 | theehci = sc; |
366 | #endif | | 367 | #endif |
367 | | | 368 | |
368 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | | 369 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); |
369 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | | 370 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); |
370 | cv_init(&sc->sc_softwake_cv, "ehciab"); | | 371 | cv_init(&sc->sc_softwake_cv, "ehciab"); |
371 | cv_init(&sc->sc_doorbell, "ehcidi"); | | 372 | cv_init(&sc->sc_doorbell, "ehcidi"); |
372 | | | 373 | |
373 | sc->sc_xferpool = pool_cache_init(sizeof(struct ehci_xfer), 0, 0, 0, | | 374 | sc->sc_xferpool = pool_cache_init(sizeof(struct ehci_xfer), 0, 0, 0, |
374 | "ehcixfer", NULL, IPL_USB, NULL, NULL, NULL); | | 375 | "ehcixfer", NULL, IPL_USB, NULL, NULL, NULL); |
375 | | | 376 | |
376 | sc->sc_doorbell_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | | 377 | sc->sc_doorbell_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, |
377 | ehci_doorbell, sc); | | 378 | ehci_doorbell, sc); |
378 | KASSERT(sc->sc_doorbell_si != NULL); | | 379 | KASSERT(sc->sc_doorbell_si != NULL); |
379 | sc->sc_pcd_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | | 380 | sc->sc_pcd_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, |
380 | ehci_pcd, sc); | | 381 | ehci_pcd, sc); |
381 | KASSERT(sc->sc_pcd_si != NULL); | | 382 | KASSERT(sc->sc_pcd_si != NULL); |
382 | | | 383 | |
383 | sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); | | 384 | sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); |
384 | | | 385 | |
385 | vers = EREAD2(sc, EHCI_HCIVERSION); | | 386 | vers = EREAD2(sc, EHCI_HCIVERSION); |
386 | aprint_verbose("%s: EHCI version %x.%x\n", device_xname(sc->sc_dev), | | 387 | aprint_verbose("%s: EHCI version %x.%x\n", device_xname(sc->sc_dev), |
387 | vers >> 8, vers & 0xff); | | 388 | vers >> 8, vers & 0xff); |
388 | | | 389 | |
389 | sparams = EREAD4(sc, EHCI_HCSPARAMS); | | 390 | sparams = EREAD4(sc, EHCI_HCSPARAMS); |
390 | USBHIST_LOG(ehcidebug, "sparams=%#x", sparams, 0, 0, 0); | | 391 | USBHIST_LOG(ehcidebug, "sparams=%#x", sparams, 0, 0, 0); |
391 | sc->sc_npcomp = EHCI_HCS_N_PCC(sparams); | | 392 | sc->sc_npcomp = EHCI_HCS_N_PCC(sparams); |
392 | ncomp = EHCI_HCS_N_CC(sparams); | | 393 | ncomp = EHCI_HCS_N_CC(sparams); |
393 | if (ncomp != sc->sc_ncomp) { | | 394 | if (ncomp != sc->sc_ncomp) { |
394 | aprint_verbose("%s: wrong number of companions (%d != %d)\n", | | 395 | aprint_verbose("%s: wrong number of companions (%d != %d)\n", |
395 | device_xname(sc->sc_dev), ncomp, sc->sc_ncomp); | | 396 | device_xname(sc->sc_dev), ncomp, sc->sc_ncomp); |
396 | #if NOHCI == 0 || NUHCI == 0 | | 397 | #if NOHCI == 0 || NUHCI == 0 |
397 | aprint_error("%s: ohci or uhci probably not configured\n", | | 398 | aprint_error("%s: ohci or uhci probably not configured\n", |
398 | device_xname(sc->sc_dev)); | | 399 | device_xname(sc->sc_dev)); |
399 | #endif | | 400 | #endif |
400 | if (ncomp < sc->sc_ncomp) | | 401 | if (ncomp < sc->sc_ncomp) |
401 | sc->sc_ncomp = ncomp; | | 402 | sc->sc_ncomp = ncomp; |
402 | } | | 403 | } |
403 | if (sc->sc_ncomp > 0) { | | 404 | if (sc->sc_ncomp > 0) { |
404 | KASSERT(!(sc->sc_flags & EHCIF_ETTF)); | | 405 | KASSERT(!(sc->sc_flags & EHCIF_ETTF)); |
405 | aprint_normal("%s: companion controller%s, %d port%s each:", | | 406 | aprint_normal("%s: companion controller%s, %d port%s each:", |
406 | device_xname(sc->sc_dev), sc->sc_ncomp!=1 ? "s" : "", | | 407 | device_xname(sc->sc_dev), sc->sc_ncomp!=1 ? "s" : "", |
407 | EHCI_HCS_N_PCC(sparams), | | 408 | EHCI_HCS_N_PCC(sparams), |
408 | EHCI_HCS_N_PCC(sparams)!=1 ? "s" : ""); | | 409 | EHCI_HCS_N_PCC(sparams)!=1 ? "s" : ""); |
409 | for (i = 0; i < sc->sc_ncomp; i++) | | 410 | for (i = 0; i < sc->sc_ncomp; i++) |
410 | aprint_normal(" %s", device_xname(sc->sc_comps[i])); | | 411 | aprint_normal(" %s", device_xname(sc->sc_comps[i])); |
411 | aprint_normal("\n"); | | 412 | aprint_normal("\n"); |
412 | } | | 413 | } |
413 | sc->sc_noport = EHCI_HCS_N_PORTS(sparams); | | 414 | sc->sc_noport = EHCI_HCS_N_PORTS(sparams); |
414 | cparams = EREAD4(sc, EHCI_HCCPARAMS); | | 415 | cparams = EREAD4(sc, EHCI_HCCPARAMS); |
415 | USBHIST_LOG(ehcidebug, "cparams=%#x", cparams, 0, 0, 0); | | 416 | USBHIST_LOG(ehcidebug, "cparams=%#x", cparams, 0, 0, 0); |
416 | sc->sc_hasppc = EHCI_HCS_PPC(sparams); | | 417 | sc->sc_hasppc = EHCI_HCS_PPC(sparams); |
417 | | | 418 | |
418 | if (EHCI_HCC_64BIT(cparams)) { | | 419 | if (EHCI_HCC_64BIT(cparams)) { |
419 | /* MUST clear segment register if 64 bit capable. */ | | 420 | /* MUST clear segment register if 64 bit capable. */ |
420 | EOWRITE4(sc, EHCI_CTRLDSSEGMENT, 0); | | 421 | EOWRITE4(sc, EHCI_CTRLDSSEGMENT, 0); |
421 | } | | 422 | } |
422 | | | 423 | |
423 | sc->sc_bus.ub_revision = USBREV_2_0; | | 424 | sc->sc_bus.ub_revision = USBREV_2_0; |
424 | sc->sc_bus.ub_usedma = true; | | 425 | sc->sc_bus.ub_usedma = true; |
425 | sc->sc_bus.ub_dmaflags = USBMALLOC_MULTISEG; | | 426 | sc->sc_bus.ub_dmaflags = USBMALLOC_MULTISEG; |
426 | | | 427 | |
427 | /* Reset the controller */ | | 428 | /* Reset the controller */ |
428 | USBHIST_LOG(ehcidebug, "resetting", 0, 0, 0, 0); | | 429 | USBHIST_LOG(ehcidebug, "resetting", 0, 0, 0, 0); |
429 | EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ | | 430 | EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ |
430 | usb_delay_ms(&sc->sc_bus, 1); | | 431 | usb_delay_ms(&sc->sc_bus, 1); |
431 | EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); | | 432 | EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); |
432 | for (i = 0; i < 100; i++) { | | 433 | for (i = 0; i < 100; i++) { |
433 | usb_delay_ms(&sc->sc_bus, 1); | | 434 | usb_delay_ms(&sc->sc_bus, 1); |
434 | hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET; | | 435 | hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET; |
435 | if (!hcr) | | 436 | if (!hcr) |
436 | break; | | 437 | break; |
437 | } | | 438 | } |
438 | if (hcr) { | | 439 | if (hcr) { |
439 | aprint_error("%s: reset timeout\n", device_xname(sc->sc_dev)); | | 440 | aprint_error("%s: reset timeout\n", device_xname(sc->sc_dev)); |
440 | return EIO; | | 441 | return EIO; |
441 | } | | 442 | } |
442 | if (sc->sc_vendor_init) | | 443 | if (sc->sc_vendor_init) |
443 | sc->sc_vendor_init(sc); | | 444 | sc->sc_vendor_init(sc); |
444 | | | 445 | |
445 | /* XXX need proper intr scheduling */ | | 446 | /* XXX need proper intr scheduling */ |
446 | sc->sc_rand = 96; | | 447 | sc->sc_rand = 96; |
447 | | | 448 | |
448 | /* frame list size at default, read back what we got and use that */ | | 449 | /* frame list size at default, read back what we got and use that */ |
449 | switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) { | | 450 | switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) { |
450 | case 0: sc->sc_flsize = 1024; break; | | 451 | case 0: sc->sc_flsize = 1024; break; |
451 | case 1: sc->sc_flsize = 512; break; | | 452 | case 1: sc->sc_flsize = 512; break; |
452 | case 2: sc->sc_flsize = 256; break; | | 453 | case 2: sc->sc_flsize = 256; break; |
453 | case 3: return EIO; | | 454 | case 3: return EIO; |
454 | } | | 455 | } |
455 | err = usb_allocmem(&sc->sc_bus, sc->sc_flsize * sizeof(ehci_link_t), | | 456 | err = usb_allocmem(&sc->sc_bus, sc->sc_flsize * sizeof(ehci_link_t), |
456 | EHCI_FLALIGN_ALIGN, &sc->sc_fldma); | | 457 | EHCI_FLALIGN_ALIGN, &sc->sc_fldma); |
457 | if (err) | | 458 | if (err) |
458 | return err; | | 459 | return err; |
459 | USBHIST_LOG(ehcidebug, "flsize=%d", sc->sc_flsize, 0, 0, 0); | | 460 | USBHIST_LOG(ehcidebug, "flsize=%d", sc->sc_flsize, 0, 0, 0); |
460 | sc->sc_flist = KERNADDR(&sc->sc_fldma, 0); | | 461 | sc->sc_flist = KERNADDR(&sc->sc_fldma, 0); |
461 | | | 462 | |
462 | for (i = 0; i < sc->sc_flsize; i++) { | | 463 | for (i = 0; i < sc->sc_flsize; i++) { |
463 | sc->sc_flist[i] = EHCI_NULL; | | 464 | sc->sc_flist[i] = EHCI_NULL; |
464 | } | | 465 | } |
465 | | | 466 | |
466 | EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); | | 467 | EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); |
467 | | | 468 | |
468 | sc->sc_softitds = kmem_zalloc(sc->sc_flsize * sizeof(ehci_soft_itd_t *), | | 469 | sc->sc_softitds = kmem_zalloc(sc->sc_flsize * sizeof(ehci_soft_itd_t *), |
469 | KM_SLEEP); | | 470 | KM_SLEEP); |
470 | if (sc->sc_softitds == NULL) | | 471 | if (sc->sc_softitds == NULL) |
471 | return ENOMEM; | | 472 | return ENOMEM; |
472 | LIST_INIT(&sc->sc_freeitds); | | 473 | LIST_INIT(&sc->sc_freeitds); |
473 | LIST_INIT(&sc->sc_freesitds); | | 474 | LIST_INIT(&sc->sc_freesitds); |
474 | TAILQ_INIT(&sc->sc_intrhead); | | 475 | TAILQ_INIT(&sc->sc_intrhead); |
475 | | | 476 | |
476 | /* Set up the bus struct. */ | | 477 | /* Set up the bus struct. */ |
477 | sc->sc_bus.ub_methods = &ehci_bus_methods; | | 478 | sc->sc_bus.ub_methods = &ehci_bus_methods; |
478 | sc->sc_bus.ub_pipesize= sizeof(struct ehci_pipe); | | 479 | sc->sc_bus.ub_pipesize= sizeof(struct ehci_pipe); |
479 | | | 480 | |
480 | sc->sc_eintrs = EHCI_NORMAL_INTRS; | | 481 | sc->sc_eintrs = EHCI_NORMAL_INTRS; |
481 | | | 482 | |
482 | /* | | 483 | /* |
483 | * Allocate the interrupt dummy QHs. These are arranged to give poll | | 484 | * Allocate the interrupt dummy QHs. These are arranged to give poll |
484 | * intervals that are powers of 2 times 1ms. | | 485 | * intervals that are powers of 2 times 1ms. |
485 | */ | | 486 | */ |
486 | for (i = 0; i < EHCI_INTRQHS; i++) { | | 487 | for (i = 0; i < EHCI_INTRQHS; i++) { |
487 | sqh = ehci_alloc_sqh(sc); | | 488 | sqh = ehci_alloc_sqh(sc); |
488 | if (sqh == NULL) { | | 489 | if (sqh == NULL) { |
489 | err = ENOMEM; | | 490 | err = ENOMEM; |
490 | goto bad1; | | 491 | goto bad1; |
491 | } | | 492 | } |
492 | sc->sc_islots[i].sqh = sqh; | | 493 | sc->sc_islots[i].sqh = sqh; |
493 | } | | 494 | } |
494 | for (i = 0; i < EHCI_INTRQHS; i++) { | | 495 | for (i = 0; i < EHCI_INTRQHS; i++) { |
495 | sqh = sc->sc_islots[i].sqh; | | 496 | sqh = sc->sc_islots[i].sqh; |
496 | if (i == 0) { | | 497 | if (i == 0) { |
497 | /* The last (1ms) QH terminates. */ | | 498 | /* The last (1ms) QH terminates. */ |
498 | sqh->qh.qh_link = EHCI_NULL; | | 499 | sqh->qh.qh_link = EHCI_NULL; |
499 | sqh->next = NULL; | | 500 | sqh->next = NULL; |
500 | } else { | | 501 | } else { |
501 | /* Otherwise the next QH has half the poll interval */ | | 502 | /* Otherwise the next QH has half the poll interval */ |
502 | sqh->next = sc->sc_islots[(i + 1) / 2 - 1].sqh; | | 503 | sqh->next = sc->sc_islots[(i + 1) / 2 - 1].sqh; |
503 | sqh->qh.qh_link = htole32(sqh->next->physaddr | | | 504 | sqh->qh.qh_link = htole32(sqh->next->physaddr | |
504 | EHCI_LINK_QH); | | 505 | EHCI_LINK_QH); |
505 | } | | 506 | } |
506 | sqh->qh.qh_endp = htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH)); | | 507 | sqh->qh.qh_endp = htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH)); |
507 | sqh->qh.qh_endphub = htole32(EHCI_QH_SET_MULT(1)); | | 508 | sqh->qh.qh_endphub = htole32(EHCI_QH_SET_MULT(1)); |
508 | sqh->qh.qh_curqtd = EHCI_NULL; | | 509 | sqh->qh.qh_curqtd = EHCI_NULL; |
509 | sqh->qh.qh_qtd.qtd_next = EHCI_NULL; | | 510 | sqh->qh.qh_qtd.qtd_next = EHCI_NULL; |
510 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; | | 511 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; |
511 | sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); | | 512 | sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); |
512 | sqh->sqtd = NULL; | | 513 | sqh->sqtd = NULL; |
513 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | | 514 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), |
514 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 515 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
515 | } | | 516 | } |
516 | /* Point the frame list at the last level (128ms). */ | | 517 | /* Point the frame list at the last level (128ms). */ |
517 | for (i = 0; i < sc->sc_flsize; i++) { | | 518 | for (i = 0; i < sc->sc_flsize; i++) { |
518 | int j; | | 519 | int j; |
519 | | | 520 | |
520 | j = (i & ~(EHCI_MAX_POLLRATE-1)) | | | 521 | j = (i & ~(EHCI_MAX_POLLRATE-1)) | |
521 | revbits[i & (EHCI_MAX_POLLRATE-1)]; | | 522 | revbits[i & (EHCI_MAX_POLLRATE-1)]; |
522 | sc->sc_flist[j] = htole32(EHCI_LINK_QH | | | 523 | sc->sc_flist[j] = htole32(EHCI_LINK_QH | |
523 | sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1, | | 524 | sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1, |
524 | i)].sqh->physaddr); | | 525 | i)].sqh->physaddr); |
525 | } | | 526 | } |
526 | usb_syncmem(&sc->sc_fldma, 0, sc->sc_flsize * sizeof(ehci_link_t), | | 527 | usb_syncmem(&sc->sc_fldma, 0, sc->sc_flsize * sizeof(ehci_link_t), |
527 | BUS_DMASYNC_PREWRITE); | | 528 | BUS_DMASYNC_PREWRITE); |
528 | | | 529 | |
529 | /* Allocate dummy QH that starts the async list. */ | | 530 | /* Allocate dummy QH that starts the async list. */ |
530 | sqh = ehci_alloc_sqh(sc); | | 531 | sqh = ehci_alloc_sqh(sc); |
531 | if (sqh == NULL) { | | 532 | if (sqh == NULL) { |
532 | err = ENOMEM; | | 533 | err = ENOMEM; |
533 | goto bad1; | | 534 | goto bad1; |
534 | } | | 535 | } |
535 | /* Fill the QH */ | | 536 | /* Fill the QH */ |
536 | sqh->qh.qh_endp = | | 537 | sqh->qh.qh_endp = |
537 | htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL); | | 538 | htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL); |
538 | sqh->qh.qh_link = | | 539 | sqh->qh.qh_link = |
539 | htole32(sqh->physaddr | EHCI_LINK_QH); | | 540 | htole32(sqh->physaddr | EHCI_LINK_QH); |
540 | sqh->qh.qh_curqtd = EHCI_NULL; | | 541 | sqh->qh.qh_curqtd = EHCI_NULL; |
541 | sqh->next = NULL; | | 542 | sqh->next = NULL; |
542 | /* Fill the overlay qTD */ | | 543 | /* Fill the overlay qTD */ |
543 | sqh->qh.qh_qtd.qtd_next = EHCI_NULL; | | 544 | sqh->qh.qh_qtd.qtd_next = EHCI_NULL; |
544 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; | | 545 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; |
545 | sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); | | 546 | sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); |
546 | sqh->sqtd = NULL; | | 547 | sqh->sqtd = NULL; |
547 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | | 548 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), |
548 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 549 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
549 | #ifdef EHCI_DEBUG | | 550 | #ifdef EHCI_DEBUG |
550 | USBHIST_LOGN(ehcidebug, 5, "--- dump start ---", 0, 0, 0, 0); | | 551 | USBHIST_LOGN(ehcidebug, 5, "--- dump start ---", 0, 0, 0, 0); |
551 | ehci_dump_sqh(sqh); | | 552 | ehci_dump_sqh(sqh); |
552 | USBHIST_LOGN(ehcidebug, 5, "--- dump end ---", 0, 0, 0, 0); | | 553 | USBHIST_LOGN(ehcidebug, 5, "--- dump end ---", 0, 0, 0, 0); |
553 | #endif | | 554 | #endif |
554 | | | 555 | |
555 | /* Point to async list */ | | 556 | /* Point to async list */ |
556 | sc->sc_async_head = sqh; | | 557 | sc->sc_async_head = sqh; |
557 | EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH); | | 558 | EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH); |
558 | | | 559 | |
559 | callout_init(&sc->sc_tmo_intrlist, CALLOUT_MPSAFE); | | 560 | callout_init(&sc->sc_tmo_intrlist, CALLOUT_MPSAFE); |
560 | | | 561 | |
561 | /* Turn on controller */ | | 562 | /* Turn on controller */ |
562 | EOWRITE4(sc, EHCI_USBCMD, | | 563 | EOWRITE4(sc, EHCI_USBCMD, |
563 | EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */ | | 564 | EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */ |
564 | (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) | | | 565 | (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) | |
565 | EHCI_CMD_ASE | | | 566 | EHCI_CMD_ASE | |
566 | EHCI_CMD_PSE | | | 567 | EHCI_CMD_PSE | |
567 | EHCI_CMD_RS); | | 568 | EHCI_CMD_RS); |
568 | | | 569 | |
569 | /* Take over port ownership */ | | 570 | /* Take over port ownership */ |
570 | EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF); | | 571 | EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF); |
571 | | | 572 | |
572 | for (i = 0; i < 100; i++) { | | 573 | for (i = 0; i < 100; i++) { |
573 | usb_delay_ms(&sc->sc_bus, 1); | | 574 | usb_delay_ms(&sc->sc_bus, 1); |
574 | hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; | | 575 | hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; |
575 | if (!hcr) | | 576 | if (!hcr) |
576 | break; | | 577 | break; |
577 | } | | 578 | } |
578 | if (hcr) { | | 579 | if (hcr) { |
579 | aprint_error("%s: run timeout\n", device_xname(sc->sc_dev)); | | 580 | aprint_error("%s: run timeout\n", device_xname(sc->sc_dev)); |
580 | return EIO; | | 581 | return EIO; |
581 | } | | 582 | } |
582 | | | 583 | |
583 | /* Enable interrupts */ | | 584 | /* Enable interrupts */ |
584 | USBHIST_LOG(ehcidebug, "enabling interupts", 0, 0, 0, 0); | | 585 | USBHIST_LOG(ehcidebug, "enabling interupts", 0, 0, 0, 0); |
585 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); | | 586 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); |
586 | | | 587 | |
587 | return 0; | | 588 | return 0; |
588 | | | 589 | |
589 | #if 0 | | 590 | #if 0 |
590 | bad2: | | 591 | bad2: |
591 | ehci_free_sqh(sc, sc->sc_async_head); | | 592 | ehci_free_sqh(sc, sc->sc_async_head); |
592 | #endif | | 593 | #endif |
593 | bad1: | | 594 | bad1: |
594 | usb_freemem(&sc->sc_bus, &sc->sc_fldma); | | 595 | usb_freemem(&sc->sc_bus, &sc->sc_fldma); |
595 | return err; | | 596 | return err; |
596 | } | | 597 | } |
597 | | | 598 | |
598 | int | | 599 | int |
599 | ehci_intr(void *v) | | 600 | ehci_intr(void *v) |
600 | { | | 601 | { |
601 | ehci_softc_t *sc = v; | | 602 | ehci_softc_t *sc = v; |
602 | int ret = 0; | | 603 | int ret = 0; |
603 | | | 604 | |
604 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); | | 605 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); |
605 | | | 606 | |
606 | if (sc == NULL) | | 607 | if (sc == NULL) |
607 | return 0; | | 608 | return 0; |
608 | | | 609 | |
609 | mutex_spin_enter(&sc->sc_intr_lock); | | 610 | mutex_spin_enter(&sc->sc_intr_lock); |
610 | | | 611 | |
611 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) | | 612 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) |
612 | goto done; | | 613 | goto done; |
613 | | | 614 | |
614 | /* If we get an interrupt while polling, then just ignore it. */ | | 615 | /* If we get an interrupt while polling, then just ignore it. */ |
615 | if (sc->sc_bus.ub_usepolling) { | | 616 | if (sc->sc_bus.ub_usepolling) { |
616 | uint32_t intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); | | 617 | uint32_t intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); |
617 | | | 618 | |
618 | if (intrs) | | 619 | if (intrs) |
619 | EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ | | 620 | EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ |
620 | USBHIST_LOGN(ehcidebug, 16, | | 621 | USBHIST_LOGN(ehcidebug, 16, |
621 | "ignored interrupt while polling", 0, 0, 0, 0); | | 622 | "ignored interrupt while polling", 0, 0, 0, 0); |
622 | goto done; | | 623 | goto done; |
623 | } | | 624 | } |
624 | | | 625 | |
625 | ret = ehci_intr1(sc); | | 626 | ret = ehci_intr1(sc); |
626 | | | 627 | |
627 | done: | | 628 | done: |
628 | mutex_spin_exit(&sc->sc_intr_lock); | | 629 | mutex_spin_exit(&sc->sc_intr_lock); |
629 | return ret; | | 630 | return ret; |
630 | } | | 631 | } |
631 | | | 632 | |
632 | Static int | | 633 | Static int |
633 | ehci_intr1(ehci_softc_t *sc) | | 634 | ehci_intr1(ehci_softc_t *sc) |
634 | { | | 635 | { |
635 | uint32_t intrs, eintrs; | | 636 | uint32_t intrs, eintrs; |
636 | | | 637 | |
637 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); | | 638 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); |
638 | | | 639 | |
639 | /* In case the interrupt occurs before initialization has completed. */ | | 640 | /* In case the interrupt occurs before initialization has completed. */ |
640 | if (sc == NULL) { | | 641 | if (sc == NULL) { |
641 | #ifdef DIAGNOSTIC | | 642 | #ifdef DIAGNOSTIC |
642 | printf("ehci_intr1: sc == NULL\n"); | | 643 | printf("ehci_intr1: sc == NULL\n"); |
643 | #endif | | 644 | #endif |
644 | return 0; | | 645 | return 0; |
645 | } | | 646 | } |
646 | | | 647 | |
647 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | | 648 | KASSERT(mutex_owned(&sc->sc_intr_lock)); |
648 | | | 649 | |
649 | intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); | | 650 | intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); |
650 | if (!intrs) | | 651 | if (!intrs) |
651 | return 0; | | 652 | return 0; |
652 | | | 653 | |
653 | eintrs = intrs & sc->sc_eintrs; | | 654 | eintrs = intrs & sc->sc_eintrs; |
654 | USBHIST_LOG(ehcidebug, "sc=%p intrs=%#x(%#x) eintrs=%#x", | | 655 | USBHIST_LOG(ehcidebug, "sc=%p intrs=%#x(%#x) eintrs=%#x", |
655 | sc, intrs, EOREAD4(sc, EHCI_USBSTS), eintrs); | | 656 | sc, intrs, EOREAD4(sc, EHCI_USBSTS), eintrs); |
656 | if (!eintrs) | | 657 | if (!eintrs) |
657 | return 0; | | 658 | return 0; |
658 | | | 659 | |
659 | EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ | | 660 | EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ |
660 | if (eintrs & EHCI_STS_IAA) { | | 661 | if (eintrs & EHCI_STS_IAA) { |
661 | USBHIST_LOG(ehcidebug, "door bell", 0, 0, 0, 0); | | 662 | USBHIST_LOG(ehcidebug, "door bell", 0, 0, 0, 0); |
662 | kpreempt_disable(); | | 663 | kpreempt_disable(); |
663 | KASSERT(sc->sc_doorbell_si != NULL); | | 664 | KASSERT(sc->sc_doorbell_si != NULL); |
664 | softint_schedule(sc->sc_doorbell_si); | | 665 | softint_schedule(sc->sc_doorbell_si); |
665 | kpreempt_enable(); | | 666 | kpreempt_enable(); |
666 | eintrs &= ~EHCI_STS_IAA; | | 667 | eintrs &= ~EHCI_STS_IAA; |
667 | } | | 668 | } |
668 | if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) { | | 669 | if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) { |
669 | USBHIST_LOG(ehcidebug, "INT=%d ERRINT=%d", | | 670 | USBHIST_LOG(ehcidebug, "INT=%d ERRINT=%d", |
670 | eintrs & EHCI_STS_INT ? 1 : 0, | | 671 | eintrs & EHCI_STS_INT ? 1 : 0, |
671 | eintrs & EHCI_STS_ERRINT ? 1 : 0, 0, 0); | | 672 | eintrs & EHCI_STS_ERRINT ? 1 : 0, 0, 0); |
672 | usb_schedsoftintr(&sc->sc_bus); | | 673 | usb_schedsoftintr(&sc->sc_bus); |
673 | eintrs &= ~(EHCI_STS_INT | EHCI_STS_ERRINT); | | 674 | eintrs &= ~(EHCI_STS_INT | EHCI_STS_ERRINT); |
674 | } | | 675 | } |
675 | if (eintrs & EHCI_STS_HSE) { | | 676 | if (eintrs & EHCI_STS_HSE) { |
676 | printf("%s: unrecoverable error, controller halted\n", | | 677 | printf("%s: unrecoverable error, controller halted\n", |
677 | device_xname(sc->sc_dev)); | | 678 | device_xname(sc->sc_dev)); |
678 | /* XXX what else */ | | 679 | /* XXX what else */ |
679 | } | | 680 | } |
680 | if (eintrs & EHCI_STS_PCD) { | | 681 | if (eintrs & EHCI_STS_PCD) { |
681 | kpreempt_disable(); | | 682 | kpreempt_disable(); |
682 | KASSERT(sc->sc_pcd_si != NULL); | | 683 | KASSERT(sc->sc_pcd_si != NULL); |
683 | softint_schedule(sc->sc_pcd_si); | | 684 | softint_schedule(sc->sc_pcd_si); |
684 | kpreempt_enable(); | | 685 | kpreempt_enable(); |
685 | eintrs &= ~EHCI_STS_PCD; | | 686 | eintrs &= ~EHCI_STS_PCD; |
686 | } | | 687 | } |
687 | | | 688 | |
688 | if (eintrs != 0) { | | 689 | if (eintrs != 0) { |
689 | /* Block unprocessed interrupts. */ | | 690 | /* Block unprocessed interrupts. */ |
690 | sc->sc_eintrs &= ~eintrs; | | 691 | sc->sc_eintrs &= ~eintrs; |
691 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); | | 692 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); |
692 | printf("%s: blocking intrs 0x%x\n", | | 693 | printf("%s: blocking intrs 0x%x\n", |
693 | device_xname(sc->sc_dev), eintrs); | | 694 | device_xname(sc->sc_dev), eintrs); |
694 | } | | 695 | } |
695 | | | 696 | |
696 | return 1; | | 697 | return 1; |
697 | } | | 698 | } |
698 | | | 699 | |
699 | Static void | | 700 | Static void |
700 | ehci_doorbell(void *addr) | | 701 | ehci_doorbell(void *addr) |
701 | { | | 702 | { |
702 | ehci_softc_t *sc = addr; | | 703 | ehci_softc_t *sc = addr; |
703 | | | 704 | |
704 | mutex_enter(&sc->sc_lock); | | 705 | mutex_enter(&sc->sc_lock); |
705 | cv_broadcast(&sc->sc_doorbell); | | 706 | cv_broadcast(&sc->sc_doorbell); |
706 | mutex_exit(&sc->sc_lock); | | 707 | mutex_exit(&sc->sc_lock); |
707 | } | | 708 | } |
708 | | | 709 | |
709 | Static void | | 710 | Static void |
710 | ehci_pcd(void *addr) | | 711 | ehci_pcd(void *addr) |
711 | { | | 712 | { |
712 | ehci_softc_t *sc = addr; | | 713 | ehci_softc_t *sc = addr; |
713 | struct usbd_xfer *xfer; | | 714 | struct usbd_xfer *xfer; |
714 | u_char *p; | | 715 | u_char *p; |
715 | int i, m; | | 716 | int i, m; |
716 | | | 717 | |
717 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); | | 718 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); |
718 | | | 719 | |
719 | mutex_enter(&sc->sc_lock); | | 720 | mutex_enter(&sc->sc_lock); |
720 | xfer = sc->sc_intrxfer; | | 721 | xfer = sc->sc_intrxfer; |
721 | | | 722 | |
722 | if (xfer == NULL) { | | 723 | if (xfer == NULL) { |
723 | /* Just ignore the change. */ | | 724 | /* Just ignore the change. */ |
724 | goto done; | | 725 | goto done; |
725 | } | | 726 | } |
726 | | | 727 | |
727 | p = xfer->ux_buf; | | 728 | p = xfer->ux_buf; |
728 | m = min(sc->sc_noport, xfer->ux_length * 8 - 1); | | 729 | m = min(sc->sc_noport, xfer->ux_length * 8 - 1); |
729 | memset(p, 0, xfer->ux_length); | | 730 | memset(p, 0, xfer->ux_length); |
730 | for (i = 1; i <= m; i++) { | | 731 | for (i = 1; i <= m; i++) { |
731 | /* Pick out CHANGE bits from the status reg. */ | | 732 | /* Pick out CHANGE bits from the status reg. */ |
732 | if (EOREAD4(sc, EHCI_PORTSC(i)) & EHCI_PS_CLEAR) | | 733 | if (EOREAD4(sc, EHCI_PORTSC(i)) & EHCI_PS_CLEAR) |
733 | p[i/8] |= 1 << (i%8); | | 734 | p[i/8] |= 1 << (i%8); |
734 | if (i % 8 == 7) | | 735 | if (i % 8 == 7) |
735 | USBHIST_LOG(ehcidebug, "change(%d)=0x%02x", i / 8, | | 736 | USBHIST_LOG(ehcidebug, "change(%d)=0x%02x", i / 8, |
736 | p[i/8], 0, 0); | | 737 | p[i/8], 0, 0); |
737 | } | | 738 | } |
738 | xfer->ux_actlen = xfer->ux_length; | | 739 | xfer->ux_actlen = xfer->ux_length; |
739 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 740 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
740 | | | 741 | |
741 | usb_transfer_complete(xfer); | | 742 | usb_transfer_complete(xfer); |
742 | | | 743 | |
743 | done: | | 744 | done: |
744 | mutex_exit(&sc->sc_lock); | | 745 | mutex_exit(&sc->sc_lock); |
745 | } | | 746 | } |
746 | | | 747 | |
747 | Static void | | 748 | Static void |
748 | ehci_softintr(void *v) | | 749 | ehci_softintr(void *v) |
749 | { | | 750 | { |
750 | struct usbd_bus *bus = v; | | 751 | struct usbd_bus *bus = v; |
751 | ehci_softc_t *sc = bus->ub_hcpriv; | | 752 | ehci_softc_t *sc = bus->ub_hcpriv; |
752 | struct ehci_xfer *ex, *nextex; | | 753 | struct ehci_xfer *ex, *nextex; |
753 | | | 754 | |
754 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 755 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
755 | | | 756 | |
756 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); | | 757 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); |
757 | | | 758 | |
758 | /* | | 759 | /* |
759 | * The only explanation I can think of for why EHCI is as brain dead | | 760 | * The only explanation I can think of for why EHCI is as brain dead |
760 | * as UHCI interrupt-wise is that Intel was involved in both. | | 761 | * as UHCI interrupt-wise is that Intel was involved in both. |
761 | * An interrupt just tells us that something is done, we have no | | 762 | * An interrupt just tells us that something is done, we have no |
762 | * clue what, so we need to scan through all active transfers. :-( | | 763 | * clue what, so we need to scan through all active transfers. :-( |
763 | */ | | 764 | */ |
764 | for (ex = TAILQ_FIRST(&sc->sc_intrhead); ex; ex = nextex) { | | 765 | for (ex = TAILQ_FIRST(&sc->sc_intrhead); ex; ex = nextex) { |
765 | nextex = TAILQ_NEXT(ex, ex_next); | | 766 | nextex = TAILQ_NEXT(ex, ex_next); |
766 | ehci_check_intr(sc, ex); | | 767 | ehci_check_intr(sc, ex); |
767 | } | | 768 | } |
768 | | | 769 | |
769 | /* Schedule a callout to catch any dropped transactions. */ | | 770 | /* Schedule a callout to catch any dropped transactions. */ |
770 | if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) && | | 771 | if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) && |
771 | !TAILQ_EMPTY(&sc->sc_intrhead)) | | 772 | !TAILQ_EMPTY(&sc->sc_intrhead)) |
772 | callout_reset(&sc->sc_tmo_intrlist, | | 773 | callout_reset(&sc->sc_tmo_intrlist, |
773 | hz, ehci_intrlist_timeout, sc); | | 774 | hz, ehci_intrlist_timeout, sc); |
774 | | | 775 | |
775 | if (sc->sc_softwake) { | | 776 | if (sc->sc_softwake) { |
776 | sc->sc_softwake = 0; | | 777 | sc->sc_softwake = 0; |
777 | cv_broadcast(&sc->sc_softwake_cv); | | 778 | cv_broadcast(&sc->sc_softwake_cv); |
778 | } | | 779 | } |
779 | } | | 780 | } |
780 | | | 781 | |
781 | /* Check for an interrupt. */ | | 782 | /* Check for an interrupt. */ |
782 | Static void | | 783 | Static void |
783 | ehci_check_intr(ehci_softc_t *sc, struct ehci_xfer *ex) | | 784 | ehci_check_intr(ehci_softc_t *sc, struct ehci_xfer *ex) |
784 | { | | 785 | { |
785 | struct usbd_device *dev = ex->ex_xfer.ux_pipe->up_dev; | | 786 | struct usbd_device *dev = ex->ex_xfer.ux_pipe->up_dev; |
786 | int attr; | | 787 | int attr; |
787 | | | 788 | |
788 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); | | 789 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); |
789 | USBHIST_LOG(ehcidebug, "ex = %p", ex, 0, 0, 0); | | 790 | USBHIST_LOG(ehcidebug, "ex = %p", ex, 0, 0, 0); |
790 | | | 791 | |
791 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 792 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
792 | | | 793 | |
793 | attr = ex->ex_xfer.ux_pipe->up_endpoint->ue_edesc->bmAttributes; | | 794 | attr = ex->ex_xfer.ux_pipe->up_endpoint->ue_edesc->bmAttributes; |
794 | if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS) { | | 795 | if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS) { |
795 | if (dev->ud_speed == USB_SPEED_HIGH) | | 796 | if (dev->ud_speed == USB_SPEED_HIGH) |
796 | ehci_check_itd_intr(sc, ex); | | 797 | ehci_check_itd_intr(sc, ex); |
797 | else | | 798 | else |
798 | ehci_check_sitd_intr(sc, ex); | | 799 | ehci_check_sitd_intr(sc, ex); |
799 | } else | | 800 | } else |
800 | ehci_check_qh_intr(sc, ex); | | 801 | ehci_check_qh_intr(sc, ex); |
801 | | | 802 | |
802 | return; | | 803 | return; |
803 | } | | 804 | } |
804 | | | 805 | |
805 | Static void | | 806 | Static void |
806 | ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex) | | 807 | ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex) |
807 | { | | 808 | { |
808 | ehci_soft_qtd_t *sqtd, *lsqtd; | | 809 | ehci_soft_qtd_t *sqtd, *lsqtd; |
809 | uint32_t status; | | 810 | uint32_t status; |
810 | | | 811 | |
811 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); | | 812 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); |
812 | | | 813 | |
813 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 814 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
814 | | | 815 | |
815 | if (ex->ex_sqtdstart == NULL) { | | 816 | if (ex->ex_sqtdstart == NULL) { |
816 | printf("ehci_check_qh_intr: not valid sqtd\n"); | | 817 | printf("ehci_check_qh_intr: not valid sqtd\n"); |
817 | return; | | 818 | return; |
818 | } | | 819 | } |
819 | | | 820 | |
820 | lsqtd = ex->ex_sqtdend; | | 821 | lsqtd = ex->ex_sqtdend; |
821 | #ifdef DIAGNOSTIC | | 822 | #ifdef DIAGNOSTIC |
822 | if (lsqtd == NULL) { | | 823 | if (lsqtd == NULL) { |
823 | printf("ehci_check_qh_intr: lsqtd==0\n"); | | 824 | printf("ehci_check_qh_intr: lsqtd==0\n"); |
824 | return; | | 825 | return; |
825 | } | | 826 | } |
826 | #endif | | 827 | #endif |
827 | /* | | 828 | /* |
828 | * If the last TD is still active we need to check whether there | | 829 | * If the last TD is still active we need to check whether there |
829 | * is an error somewhere in the middle, or whether there was a | | 830 | * is an error somewhere in the middle, or whether there was a |
830 | * short packet (SPD and not ACTIVE). | | 831 | * short packet (SPD and not ACTIVE). |
831 | */ | | 832 | */ |
832 | usb_syncmem(&lsqtd->dma, | | 833 | usb_syncmem(&lsqtd->dma, |
833 | lsqtd->offs + offsetof(ehci_qtd_t, qtd_status), | | 834 | lsqtd->offs + offsetof(ehci_qtd_t, qtd_status), |
834 | sizeof(lsqtd->qtd.qtd_status), | | 835 | sizeof(lsqtd->qtd.qtd_status), |
835 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 836 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
836 | status = le32toh(lsqtd->qtd.qtd_status); | | 837 | status = le32toh(lsqtd->qtd.qtd_status); |
837 | usb_syncmem(&lsqtd->dma, | | 838 | usb_syncmem(&lsqtd->dma, |
838 | lsqtd->offs + offsetof(ehci_qtd_t, qtd_status), | | 839 | lsqtd->offs + offsetof(ehci_qtd_t, qtd_status), |
839 | sizeof(lsqtd->qtd.qtd_status), BUS_DMASYNC_PREREAD); | | 840 | sizeof(lsqtd->qtd.qtd_status), BUS_DMASYNC_PREREAD); |
840 | if (status & EHCI_QTD_ACTIVE) { | | 841 | if (status & EHCI_QTD_ACTIVE) { |
841 | USBHIST_LOGN(ehcidebug, 10, "active ex=%p", ex, 0, 0, 0); | | 842 | USBHIST_LOGN(ehcidebug, 10, "active ex=%p", ex, 0, 0, 0); |
842 | for (sqtd = ex->ex_sqtdstart; sqtd != lsqtd; | | 843 | for (sqtd = ex->ex_sqtdstart; sqtd != lsqtd; |
843 | sqtd = sqtd->nextqtd) { | | 844 | sqtd = sqtd->nextqtd) { |
844 | usb_syncmem(&sqtd->dma, | | 845 | usb_syncmem(&sqtd->dma, |
845 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | | 846 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), |
846 | sizeof(sqtd->qtd.qtd_status), | | 847 | sizeof(sqtd->qtd.qtd_status), |
847 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 848 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
848 | status = le32toh(sqtd->qtd.qtd_status); | | 849 | status = le32toh(sqtd->qtd.qtd_status); |
849 | usb_syncmem(&sqtd->dma, | | 850 | usb_syncmem(&sqtd->dma, |
850 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | | 851 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), |
851 | sizeof(sqtd->qtd.qtd_status), BUS_DMASYNC_PREREAD); | | 852 | sizeof(sqtd->qtd.qtd_status), BUS_DMASYNC_PREREAD); |
852 | /* If there's an active QTD the xfer isn't done. */ | | 853 | /* If there's an active QTD the xfer isn't done. */ |
853 | if (status & EHCI_QTD_ACTIVE) | | 854 | if (status & EHCI_QTD_ACTIVE) |
854 | break; | | 855 | break; |
855 | /* Any kind of error makes the xfer done. */ | | 856 | /* Any kind of error makes the xfer done. */ |
856 | if (status & EHCI_QTD_HALTED) | | 857 | if (status & EHCI_QTD_HALTED) |
857 | goto done; | | 858 | goto done; |
858 | /* Handle short packets */ | | 859 | /* Handle short packets */ |
859 | if (EHCI_QTD_GET_BYTES(status) != 0) { | | 860 | if (EHCI_QTD_GET_BYTES(status) != 0) { |
860 | struct usbd_pipe *pipe = ex->ex_xfer.ux_pipe; | | 861 | struct usbd_pipe *pipe = ex->ex_xfer.ux_pipe; |
861 | usb_endpoint_descriptor_t *ed = | | 862 | usb_endpoint_descriptor_t *ed = |
862 | pipe->up_endpoint->ue_edesc; | | 863 | pipe->up_endpoint->ue_edesc; |
863 | uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes); | | 864 | uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes); |
864 | | | 865 | |
865 | /* | | 866 | /* |
866 | * If we get here for a control transfer then | | 867 | * If we get here for a control transfer then |
867 | * we need to let the hardware complete the | | 868 | * we need to let the hardware complete the |
868 | * status phase. That is, we're not done | | 869 | * status phase. That is, we're not done |
869 | * quite yet. | | 870 | * quite yet. |
870 | * | | 871 | * |
871 | * Otherwise, we're done. | | 872 | * Otherwise, we're done. |
872 | */ | | 873 | */ |
873 | if (xt == UE_CONTROL) { | | 874 | if (xt == UE_CONTROL) { |
874 | break; | | 875 | break; |
875 | } | | 876 | } |
876 | goto done; | | 877 | goto done; |
877 | } | | 878 | } |
878 | } | | 879 | } |
879 | USBHIST_LOGN(ehcidebug, 10, "ex=%p std=%p still active", | | 880 | USBHIST_LOGN(ehcidebug, 10, "ex=%p std=%p still active", |
880 | ex, ex->ex_sqtdstart, 0, 0); | | 881 | ex, ex->ex_sqtdstart, 0, 0); |
881 | #ifdef EHCI_DEBUG | | 882 | #ifdef EHCI_DEBUG |
882 | USBHIST_LOGN(ehcidebug, 5, "--- still active start ---", 0, 0, | | 883 | USBHIST_LOGN(ehcidebug, 5, "--- still active start ---", 0, 0, |
883 | 0, 0); | | 884 | 0, 0); |
884 | ehci_dump_sqtds(ex->ex_sqtdstart); | | 885 | ehci_dump_sqtds(ex->ex_sqtdstart); |
885 | USBHIST_LOGN(ehcidebug, 5, "--- still active end ---", 0, 0, 0, | | 886 | USBHIST_LOGN(ehcidebug, 5, "--- still active end ---", 0, 0, 0, |
886 | 0); | | 887 | 0); |
887 | #endif | | 888 | #endif |
888 | return; | | 889 | return; |
889 | } | | 890 | } |
890 | done: | | 891 | done: |
891 | USBHIST_LOGN(ehcidebug, 10, "ex=%p done", ex, 0, 0, 0); | | 892 | USBHIST_LOGN(ehcidebug, 10, "ex=%p done", ex, 0, 0, 0); |
892 | callout_stop(&ex->ex_xfer.ux_callout); | | 893 | callout_stop(&ex->ex_xfer.ux_callout); |
893 | ehci_idone(ex); | | 894 | ehci_idone(ex); |
894 | } | | 895 | } |
895 | | | 896 | |
896 | Static void | | 897 | Static void |
897 | ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) | | 898 | ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) |
898 | { | | 899 | { |
899 | ehci_soft_itd_t *itd; | | 900 | ehci_soft_itd_t *itd; |
900 | int i; | | 901 | int i; |
901 | | | 902 | |
902 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); | | 903 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); |
903 | | | 904 | |
904 | KASSERT(mutex_owned(&sc->sc_lock)); | | 905 | KASSERT(mutex_owned(&sc->sc_lock)); |
905 | | | 906 | |
906 | if (&ex->ex_xfer != SIMPLEQ_FIRST(&ex->ex_xfer.ux_pipe->up_queue)) | | 907 | if (&ex->ex_xfer != SIMPLEQ_FIRST(&ex->ex_xfer.ux_pipe->up_queue)) |
907 | return; | | 908 | return; |
908 | | | 909 | |
909 | if (ex->ex_itdstart == NULL) { | | 910 | if (ex->ex_itdstart == NULL) { |
910 | printf("ehci_check_itd_intr: not valid itd\n"); | | 911 | printf("ehci_check_itd_intr: not valid itd\n"); |
911 | return; | | 912 | return; |
912 | } | | 913 | } |
913 | | | 914 | |
914 | itd = ex->ex_itdend; | | 915 | itd = ex->ex_itdend; |
915 | #ifdef DIAGNOSTIC | | 916 | #ifdef DIAGNOSTIC |
916 | if (itd == NULL) { | | 917 | if (itd == NULL) { |
917 | printf("ehci_check_itd_intr: itdend == 0\n"); | | 918 | printf("ehci_check_itd_intr: itdend == 0\n"); |
918 | return; | | 919 | return; |
919 | } | | 920 | } |
920 | #endif | | 921 | #endif |
921 | | | 922 | |
922 | /* | | 923 | /* |
923 | * check no active transfers in last itd, meaning we're finished | | 924 | * check no active transfers in last itd, meaning we're finished |
924 | */ | | 925 | */ |
925 | | | 926 | |
926 | usb_syncmem(&itd->dma, itd->offs + offsetof(ehci_itd_t, itd_ctl), | | 927 | usb_syncmem(&itd->dma, itd->offs + offsetof(ehci_itd_t, itd_ctl), |
927 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_POSTWRITE | | | 928 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_POSTWRITE | |
928 | BUS_DMASYNC_POSTREAD); | | 929 | BUS_DMASYNC_POSTREAD); |
929 | | | 930 | |
930 | for (i = 0; i < EHCI_ITD_NUFRAMES; i++) { | | 931 | for (i = 0; i < EHCI_ITD_NUFRAMES; i++) { |
931 | if (le32toh(itd->itd.itd_ctl[i]) & EHCI_ITD_ACTIVE) | | 932 | if (le32toh(itd->itd.itd_ctl[i]) & EHCI_ITD_ACTIVE) |
932 | break; | | 933 | break; |
933 | } | | 934 | } |
934 | | | 935 | |
935 | if (i == EHCI_ITD_NUFRAMES) { | | 936 | if (i == EHCI_ITD_NUFRAMES) { |
936 | goto done; /* All 8 descriptors inactive, it's done */ | | 937 | goto done; /* All 8 descriptors inactive, it's done */ |
937 | } | | 938 | } |
938 | | | 939 | |
939 | usb_syncmem(&itd->dma, itd->offs + offsetof(ehci_itd_t, itd_ctl), | | 940 | usb_syncmem(&itd->dma, itd->offs + offsetof(ehci_itd_t, itd_ctl), |
940 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_PREREAD); | | 941 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_PREREAD); |
941 | | | 942 | |
942 | USBHIST_LOGN(ehcidebug, 10, "ex %p itd %p still active", ex, | | 943 | USBHIST_LOGN(ehcidebug, 10, "ex %p itd %p still active", ex, |
943 | ex->ex_itdstart, 0, 0); | | 944 | ex->ex_itdstart, 0, 0); |
944 | return; | | 945 | return; |
945 | done: | | 946 | done: |
946 | USBHIST_LOG(ehcidebug, "ex %p done", ex, 0, 0, 0); | | 947 | USBHIST_LOG(ehcidebug, "ex %p done", ex, 0, 0, 0); |
947 | callout_stop(&ex->ex_xfer.ux_callout); | | 948 | callout_stop(&ex->ex_xfer.ux_callout); |
948 | ehci_idone(ex); | | 949 | ehci_idone(ex); |
949 | } | | 950 | } |
950 | | | 951 | |
951 | void | | 952 | void |
952 | ehci_check_sitd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) | | 953 | ehci_check_sitd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) |
953 | { | | 954 | { |
954 | ehci_soft_sitd_t *sitd; | | 955 | ehci_soft_sitd_t *sitd; |
955 | | | 956 | |
956 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); | | 957 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); |
957 | | | 958 | |
958 | KASSERT(mutex_owned(&sc->sc_lock)); | | 959 | KASSERT(mutex_owned(&sc->sc_lock)); |
959 | | | 960 | |
960 | if (&ex->ex_xfer != SIMPLEQ_FIRST(&ex->ex_xfer.ux_pipe->up_queue)) | | 961 | if (&ex->ex_xfer != SIMPLEQ_FIRST(&ex->ex_xfer.ux_pipe->up_queue)) |
961 | return; | | 962 | return; |
962 | | | 963 | |
963 | if (ex->ex_sitdstart == NULL) { | | 964 | if (ex->ex_sitdstart == NULL) { |
964 | printf("ehci_check_sitd_intr: not valid sitd\n"); | | 965 | printf("ehci_check_sitd_intr: not valid sitd\n"); |
965 | return; | | 966 | return; |
966 | } | | 967 | } |
967 | | | 968 | |
968 | sitd = ex->ex_sitdend; | | 969 | sitd = ex->ex_sitdend; |
969 | #ifdef DIAGNOSTIC | | 970 | #ifdef DIAGNOSTIC |
970 | if (sitd == NULL) { | | 971 | if (sitd == NULL) { |
971 | printf("ehci_check_sitd_intr: sitdend == 0\n"); | | 972 | printf("ehci_check_sitd_intr: sitdend == 0\n"); |
972 | return; | | 973 | return; |
973 | } | | 974 | } |
974 | #endif | | 975 | #endif |
975 | | | 976 | |
976 | /* | | 977 | /* |
977 | * check no active transfers in last sitd, meaning we're finished | | 978 | * check no active transfers in last sitd, meaning we're finished |
978 | */ | | 979 | */ |
979 | | | 980 | |
980 | usb_syncmem(&sitd->dma, sitd->offs + offsetof(ehci_sitd_t, sitd_trans), | | 981 | usb_syncmem(&sitd->dma, sitd->offs + offsetof(ehci_sitd_t, sitd_trans), |
981 | sizeof(sitd->sitd.sitd_trans), BUS_DMASYNC_POSTWRITE | | | 982 | sizeof(sitd->sitd.sitd_trans), BUS_DMASYNC_POSTWRITE | |
982 | BUS_DMASYNC_POSTREAD); | | 983 | BUS_DMASYNC_POSTREAD); |
983 | | | 984 | |
984 | if (le32toh(sitd->sitd.sitd_trans) & EHCI_SITD_ACTIVE) | | 985 | if (le32toh(sitd->sitd.sitd_trans) & EHCI_SITD_ACTIVE) |
985 | return; | | 986 | return; |
986 | | | 987 | |
987 | usb_syncmem(&sitd->dma, sitd->offs + offsetof(ehci_sitd_t, sitd_trans), | | 988 | usb_syncmem(&sitd->dma, sitd->offs + offsetof(ehci_sitd_t, sitd_trans), |
988 | sizeof(sitd->sitd.sitd_trans), BUS_DMASYNC_PREREAD); | | 989 | sizeof(sitd->sitd.sitd_trans), BUS_DMASYNC_PREREAD); |
989 | | | 990 | |
990 | USBHIST_LOGN(ehcidebug, 10, "ex=%p done", ex, 0, 0, 0); | | 991 | USBHIST_LOGN(ehcidebug, 10, "ex=%p done", ex, 0, 0, 0); |
991 | callout_stop(&(ex->ex_xfer.ux_callout)); | | 992 | callout_stop(&(ex->ex_xfer.ux_callout)); |
992 | ehci_idone(ex); | | 993 | ehci_idone(ex); |
993 | } | | 994 | } |
994 | | | 995 | |
995 | | | 996 | |
996 | Static void | | 997 | Static void |
997 | ehci_idone(struct ehci_xfer *ex) | | 998 | ehci_idone(struct ehci_xfer *ex) |
998 | { | | 999 | { |
999 | struct usbd_xfer *xfer = &ex->ex_xfer; | | 1000 | struct usbd_xfer *xfer = &ex->ex_xfer; |
1000 | struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer); | | 1001 | struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer); |
1001 | struct ehci_softc *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv; | | 1002 | struct ehci_softc *sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv; |
1002 | ehci_soft_qtd_t *sqtd, *lsqtd; | | 1003 | ehci_soft_qtd_t *sqtd, *lsqtd; |
1003 | uint32_t status = 0, nstatus = 0; | | 1004 | uint32_t status = 0, nstatus = 0; |
1004 | int actlen; | | 1005 | int actlen; |
1005 | | | 1006 | |
1006 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); | | 1007 | USBHIST_FUNC(); USBHIST_CALLED(ehcidebug); |
1007 | | | 1008 | |
1008 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 1009 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
1009 | | | 1010 | |
1010 | USBHIST_LOG(ehcidebug, "ex=%p", ex, 0, 0, 0); | | 1011 | USBHIST_LOG(ehcidebug, "ex=%p", ex, 0, 0, 0); |
1011 | | | 1012 | |
1012 | #ifdef DIAGNOSTIC | | 1013 | #ifdef DIAGNOSTIC |
1013 | #ifdef EHCI_DEBUG | | 1014 | #ifdef EHCI_DEBUG |
1014 | if (ex->ex_isdone) { | | 1015 | if (ex->ex_isdone) { |
1015 | USBHIST_LOGN(ehcidebug, 5, "--- dump start ---", 0, 0, 0, 0); | | 1016 | USBHIST_LOGN(ehcidebug, 5, "--- dump start ---", 0, 0, 0, 0); |
1016 | ehci_dump_exfer(ex); | | 1017 | ehci_dump_exfer(ex); |
1017 | USBHIST_LOGN(ehcidebug, 5, "--- dump end ---", 0, 0, 0, 0); | | 1018 | USBHIST_LOGN(ehcidebug, 5, "--- dump end ---", 0, 0, 0, 0); |
1018 | } | | 1019 | } |
1019 | #endif | | 1020 | #endif |
1020 | KASSERT(!ex->ex_isdone); | | 1021 | KASSERT(!ex->ex_isdone); |
1021 | ex->ex_isdone = true; | | 1022 | ex->ex_isdone = true; |
1022 | #endif | | 1023 | #endif |
1023 | | | 1024 | |
1024 | if (xfer->ux_status == USBD_CANCELLED || | | 1025 | if (xfer->ux_status == USBD_CANCELLED || |
1025 | xfer->ux_status == USBD_TIMEOUT) { | | 1026 | xfer->ux_status == USBD_TIMEOUT) { |
1026 | USBHIST_LOG(ehcidebug, "aborted xfer=%p", xfer, 0, 0, 0); | | 1027 | USBHIST_LOG(ehcidebug, "aborted xfer=%p", xfer, 0, 0, 0); |
1027 | return; | | 1028 | return; |
1028 | } | | 1029 | } |
1029 | | | 1030 | |
1030 | USBHIST_LOG(ehcidebug, "xfer=%p, pipe=%p ready", xfer, epipe, 0, 0); | | 1031 | USBHIST_LOG(ehcidebug, "xfer=%p, pipe=%p ready", xfer, epipe, 0, 0); |
1031 | | | 1032 | |
1032 | /* The transfer is done, compute actual length and status. */ | | 1033 | /* The transfer is done, compute actual length and status. */ |
1033 | | | 1034 | |
1034 | u_int xfertype, speed; | | 1035 | u_int xfertype, speed; |
1035 | | | 1036 | |
1036 | xfertype = UE_GET_XFERTYPE(xfer->ux_pipe->up_endpoint->ue_edesc->bmAttributes); | | 1037 | xfertype = UE_GET_XFERTYPE(xfer->ux_pipe->up_endpoint->ue_edesc->bmAttributes); |
1037 | speed = xfer->ux_pipe->up_dev->ud_speed; | | 1038 | speed = xfer->ux_pipe->up_dev->ud_speed; |
1038 | if (xfertype == UE_ISOCHRONOUS && speed == USB_SPEED_HIGH) { | | 1039 | if (xfertype == UE_ISOCHRONOUS && speed == USB_SPEED_HIGH) { |
1039 | /* HS isoc transfer */ | | 1040 | /* HS isoc transfer */ |
1040 | | | 1041 | |
1041 | struct ehci_soft_itd *itd; | | 1042 | struct ehci_soft_itd *itd; |
1042 | int i, nframes, len, uframes; | | 1043 | int i, nframes, len, uframes; |
1043 | | | 1044 | |
1044 | nframes = 0; | | 1045 | nframes = 0; |
1045 | actlen = 0; | | 1046 | actlen = 0; |
1046 | | | 1047 | |
1047 | i = xfer->ux_pipe->up_endpoint->ue_edesc->bInterval; | | 1048 | i = xfer->ux_pipe->up_endpoint->ue_edesc->bInterval; |
1048 | uframes = min(1 << (i - 1), USB_UFRAMES_PER_FRAME); | | 1049 | uframes = min(1 << (i - 1), USB_UFRAMES_PER_FRAME); |
1049 | | | 1050 | |
1050 | for (itd = ex->ex_itdstart; itd != NULL; itd = itd->xfer_next) { | | 1051 | for (itd = ex->ex_itdstart; itd != NULL; itd = itd->xfer_next) { |
1051 | usb_syncmem(&itd->dma, | | 1052 | usb_syncmem(&itd->dma, |
1052 | itd->offs + offsetof(ehci_itd_t,itd_ctl), | | 1053 | itd->offs + offsetof(ehci_itd_t,itd_ctl), |
1053 | sizeof(itd->itd.itd_ctl), | | 1054 | sizeof(itd->itd.itd_ctl), |
1054 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1055 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1055 | | | 1056 | |
1056 | for (i = 0; i < EHCI_ITD_NUFRAMES; i += uframes) { | | 1057 | for (i = 0; i < EHCI_ITD_NUFRAMES; i += uframes) { |
1057 | /* | | 1058 | /* |
1058 | * XXX - driver didn't fill in the frame full | | 1059 | * XXX - driver didn't fill in the frame full |
1059 | * of uframes. This leads to scheduling | | 1060 | * of uframes. This leads to scheduling |
1060 | * inefficiencies, but working around | | 1061 | * inefficiencies, but working around |
1061 | * this doubles complexity of tracking | | 1062 | * this doubles complexity of tracking |
1062 | * an xfer. | | 1063 | * an xfer. |
1063 | */ | | 1064 | */ |
1064 | if (nframes >= xfer->ux_nframes) | | 1065 | if (nframes >= xfer->ux_nframes) |
1065 | break; | | 1066 | break; |
1066 | | | 1067 | |
1067 | status = le32toh(itd->itd.itd_ctl[i]); | | 1068 | status = le32toh(itd->itd.itd_ctl[i]); |
1068 | len = EHCI_ITD_GET_LEN(status); | | 1069 | len = EHCI_ITD_GET_LEN(status); |
1069 | if (EHCI_ITD_GET_STATUS(status) != 0) | | 1070 | if (EHCI_ITD_GET_STATUS(status) != 0) |
1070 | len = 0; /*No valid data on error*/ | | 1071 | len = 0; /*No valid data on error*/ |
1071 | | | 1072 | |
1072 | xfer->ux_frlengths[nframes++] = len; | | 1073 | xfer->ux_frlengths[nframes++] = len; |
1073 | actlen += len; | | 1074 | actlen += len; |
1074 | } | | 1075 | } |
1075 | usb_syncmem(&itd->dma, | | 1076 | usb_syncmem(&itd->dma, |
1076 | itd->offs + offsetof(ehci_itd_t,itd_ctl), | | 1077 | itd->offs + offsetof(ehci_itd_t,itd_ctl), |
1077 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_PREREAD); | | 1078 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_PREREAD); |
1078 | | | 1079 | |
1079 | if (nframes >= xfer->ux_nframes) | | 1080 | if (nframes >= xfer->ux_nframes) |
1080 | break; | | 1081 | break; |
1081 | } | | 1082 | } |
1082 | | | 1083 | |
1083 | xfer->ux_actlen = actlen; | | 1084 | xfer->ux_actlen = actlen; |
1084 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 1085 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
1085 | goto end; | | 1086 | goto end; |
1086 | } | | 1087 | } |
1087 | | | 1088 | |
1088 | if (xfertype == UE_ISOCHRONOUS && speed == USB_SPEED_FULL) { | | 1089 | if (xfertype == UE_ISOCHRONOUS && speed == USB_SPEED_FULL) { |
1089 | /* FS isoc transfer */ | | 1090 | /* FS isoc transfer */ |
1090 | struct ehci_soft_sitd *sitd; | | 1091 | struct ehci_soft_sitd *sitd; |
1091 | int nframes, len; | | 1092 | int nframes, len; |
1092 | | | 1093 | |
1093 | nframes = 0; | | 1094 | nframes = 0; |
1094 | actlen = 0; | | 1095 | actlen = 0; |
1095 | | | 1096 | |
1096 | for (sitd = ex->ex_sitdstart; sitd != NULL; | | 1097 | for (sitd = ex->ex_sitdstart; sitd != NULL; |
1097 | sitd = sitd->xfer_next) { | | 1098 | sitd = sitd->xfer_next) { |
1098 | usb_syncmem(&sitd->dma, | | 1099 | usb_syncmem(&sitd->dma, |
1099 | sitd->offs + offsetof(ehci_sitd_t, sitd_trans), | | 1100 | sitd->offs + offsetof(ehci_sitd_t, sitd_trans), |
1100 | sizeof(sitd->sitd.sitd_trans), | | 1101 | sizeof(sitd->sitd.sitd_trans), |
1101 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1102 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1102 | | | 1103 | |
1103 | /* | | 1104 | /* |
1104 | * XXX - driver didn't fill in the frame full | | 1105 | * XXX - driver didn't fill in the frame full |
1105 | * of uframes. This leads to scheduling | | 1106 | * of uframes. This leads to scheduling |
1106 | * inefficiencies, but working around | | 1107 | * inefficiencies, but working around |
1107 | * this doubles complexity of tracking | | 1108 | * this doubles complexity of tracking |
1108 | * an xfer. | | 1109 | * an xfer. |
1109 | */ | | 1110 | */ |
1110 | if (nframes >= xfer->ux_nframes) | | 1111 | if (nframes >= xfer->ux_nframes) |
1111 | break; | | 1112 | break; |
1112 | | | 1113 | |
1113 | status = le32toh(sitd->sitd.sitd_trans); | | 1114 | status = le32toh(sitd->sitd.sitd_trans); |
1114 | usb_syncmem(&sitd->dma, | | 1115 | usb_syncmem(&sitd->dma, |
1115 | sitd->offs + offsetof(ehci_sitd_t, sitd_trans), | | 1116 | sitd->offs + offsetof(ehci_sitd_t, sitd_trans), |
1116 | sizeof(sitd->sitd.sitd_trans), BUS_DMASYNC_PREREAD); | | 1117 | sizeof(sitd->sitd.sitd_trans), BUS_DMASYNC_PREREAD); |
1117 | | | 1118 | |
1118 | len = EHCI_SITD_GET_LEN(status); | | 1119 | len = EHCI_SITD_GET_LEN(status); |
1119 | if (status & (EHCI_SITD_ERR|EHCI_SITD_BUFERR| | | 1120 | if (status & (EHCI_SITD_ERR|EHCI_SITD_BUFERR| |
1120 | EHCI_SITD_BABBLE|EHCI_SITD_XACTERR|EHCI_SITD_MISS)) { | | 1121 | EHCI_SITD_BABBLE|EHCI_SITD_XACTERR|EHCI_SITD_MISS)) { |
1121 | /* No valid data on error */ | | 1122 | /* No valid data on error */ |
1122 | len = xfer->ux_frlengths[nframes]; | | 1123 | len = xfer->ux_frlengths[nframes]; |
1123 | } | | 1124 | } |
1124 | | | 1125 | |
1125 | /* | | 1126 | /* |
1126 | * frlengths[i]: # of bytes to send | | 1127 | * frlengths[i]: # of bytes to send |
1127 | * len: # of bytes host didn't send | | 1128 | * len: # of bytes host didn't send |
1128 | */ | | 1129 | */ |
1129 | xfer->ux_frlengths[nframes] -= len; | | 1130 | xfer->ux_frlengths[nframes] -= len; |
1130 | /* frlengths[i]: # of bytes host sent */ | | 1131 | /* frlengths[i]: # of bytes host sent */ |
1131 | actlen += xfer->ux_frlengths[nframes++]; | | 1132 | actlen += xfer->ux_frlengths[nframes++]; |
1132 | | | 1133 | |
1133 | if (nframes >= xfer->ux_nframes) | | 1134 | if (nframes >= xfer->ux_nframes) |
1134 | break; | | 1135 | break; |
1135 | } | | 1136 | } |
1136 | | | 1137 | |
1137 | xfer->ux_actlen = actlen; | | 1138 | xfer->ux_actlen = actlen; |
1138 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 1139 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
1139 | goto end; | | 1140 | goto end; |
1140 | } | | 1141 | } |
1141 | KASSERT(xfertype != UE_ISOCHRONOUS); | | 1142 | KASSERT(xfertype != UE_ISOCHRONOUS); |
1142 | | | 1143 | |
1143 | /* Continue processing xfers using queue heads */ | | 1144 | /* Continue processing xfers using queue heads */ |
1144 | | | 1145 | |
1145 | #ifdef EHCI_DEBUG | | 1146 | #ifdef EHCI_DEBUG |
1146 | USBHIST_LOGN(ehcidebug, 5, "--- dump start ---", 0, 0, 0, 0); | | 1147 | USBHIST_LOGN(ehcidebug, 5, "--- dump start ---", 0, 0, 0, 0); |
1147 | ehci_dump_sqtds(ex->ex_sqtdstart); | | 1148 | ehci_dump_sqtds(ex->ex_sqtdstart); |
1148 | USBHIST_LOGN(ehcidebug, 5, "--- dump end ---", 0, 0, 0, 0); | | 1149 | USBHIST_LOGN(ehcidebug, 5, "--- dump end ---", 0, 0, 0, 0); |
1149 | #endif | | 1150 | #endif |
1150 | | | 1151 | |
1151 | lsqtd = ex->ex_sqtdend; | | 1152 | lsqtd = ex->ex_sqtdend; |
1152 | actlen = 0; | | 1153 | actlen = 0; |
1153 | for (sqtd = ex->ex_sqtdstart; sqtd != lsqtd->nextqtd; | | 1154 | for (sqtd = ex->ex_sqtdstart; sqtd != lsqtd->nextqtd; |
1154 | sqtd = sqtd->nextqtd) { | | 1155 | sqtd = sqtd->nextqtd) { |
1155 | usb_syncmem(&sqtd->dma, sqtd->offs, sizeof(sqtd->qtd), | | 1156 | usb_syncmem(&sqtd->dma, sqtd->offs, sizeof(sqtd->qtd), |
1156 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1157 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1157 | nstatus = le32toh(sqtd->qtd.qtd_status); | | 1158 | nstatus = le32toh(sqtd->qtd.qtd_status); |
1158 | usb_syncmem(&sqtd->dma, sqtd->offs, sizeof(sqtd->qtd), | | 1159 | usb_syncmem(&sqtd->dma, sqtd->offs, sizeof(sqtd->qtd), |
1159 | BUS_DMASYNC_PREREAD); | | 1160 | BUS_DMASYNC_PREREAD); |
1160 | if (nstatus & EHCI_QTD_ACTIVE) | | 1161 | if (nstatus & EHCI_QTD_ACTIVE) |
1161 | break; | | 1162 | break; |
1162 | | | 1163 | |
1163 | status = nstatus; | | 1164 | status = nstatus; |
1164 | if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP) | | 1165 | if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP) |
1165 | actlen += sqtd->len - EHCI_QTD_GET_BYTES(status); | | 1166 | actlen += sqtd->len - EHCI_QTD_GET_BYTES(status); |
1166 | } | | 1167 | } |
1167 | | | 1168 | |
1168 | /* | | 1169 | /* |
1169 | * If there are left over TDs we need to update the toggle. | | 1170 | * If there are left over TDs we need to update the toggle. |
1170 | * The default pipe doesn't need it since control transfers | | 1171 | * The default pipe doesn't need it since control transfers |
1171 | * start the toggle at 0 every time. | | 1172 | * start the toggle at 0 every time. |
1172 | * For a short transfer we need to update the toggle for the missing | | 1173 | * For a short transfer we need to update the toggle for the missing |
1173 | * packets within the qTD. | | 1174 | * packets within the qTD. |
1174 | */ | | 1175 | */ |
1175 | if ((sqtd != lsqtd->nextqtd || EHCI_QTD_GET_BYTES(status)) && | | 1176 | if ((sqtd != lsqtd->nextqtd || EHCI_QTD_GET_BYTES(status)) && |
1176 | xfer->ux_pipe->up_dev->ud_pipe0 != xfer->ux_pipe) { | | 1177 | xfer->ux_pipe->up_dev->ud_pipe0 != xfer->ux_pipe) { |
1177 | USBHIST_LOG(ehcidebug, | | 1178 | USBHIST_LOG(ehcidebug, |
1178 | "toggle update status=0x%08x nstatus=0x%08x", | | 1179 | "toggle update status=0x%08x nstatus=0x%08x", |
1179 | status, nstatus, 0, 0); | | 1180 | status, nstatus, 0, 0); |
1180 | #if 0 | | 1181 | #if 0 |
1181 | ehci_dump_sqh(epipe->sqh); | | 1182 | ehci_dump_sqh(epipe->sqh); |
1182 | ehci_dump_sqtds(ex->ex_sqtdstart); | | 1183 | ehci_dump_sqtds(ex->ex_sqtdstart); |
1183 | #endif | | 1184 | #endif |
1184 | epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(nstatus); | | 1185 | epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(nstatus); |
1185 | } | | 1186 | } |
1186 | | | 1187 | |
1187 | USBHIST_LOG(ehcidebug, "len=%d actlen=%d status=0x%08x", xfer->ux_length, | | 1188 | USBHIST_LOG(ehcidebug, "len=%d actlen=%d status=0x%08x", xfer->ux_length, |
1188 | actlen, status, 0); | | 1189 | actlen, status, 0); |
1189 | xfer->ux_actlen = actlen; | | 1190 | xfer->ux_actlen = actlen; |
1190 | if (status & EHCI_QTD_HALTED) { | | 1191 | if (status & EHCI_QTD_HALTED) { |
1191 | #ifdef EHCI_DEBUG | | 1192 | #ifdef EHCI_DEBUG |
1192 | USBHIST_LOG(ehcidebug, "halted addr=%d endpt=0x%02x", | | 1193 | USBHIST_LOG(ehcidebug, "halted addr=%d endpt=0x%02x", |
1193 | xfer->ux_pipe->up_dev->ud_addr, | | 1194 | xfer->ux_pipe->up_dev->ud_addr, |
1194 | xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress, 0, 0); | | 1195 | xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress, 0, 0); |
1195 | USBHIST_LOG(ehcidebug, "cerr=%d pid=%d", | | 1196 | USBHIST_LOG(ehcidebug, "cerr=%d pid=%d", |
1196 | EHCI_QTD_GET_CERR(status), EHCI_QTD_GET_PID(status), | | 1197 | EHCI_QTD_GET_CERR(status), EHCI_QTD_GET_PID(status), |
1197 | 0, 0); | | 1198 | 0, 0); |
1198 | USBHIST_LOG(ehcidebug, | | 1199 | USBHIST_LOG(ehcidebug, |
1199 | "active =%d halted=%d buferr=%d babble=%d", | | 1200 | "active =%d halted=%d buferr=%d babble=%d", |
1200 | status & EHCI_QTD_ACTIVE ? 1 : 0, | | 1201 | status & EHCI_QTD_ACTIVE ? 1 : 0, |
1201 | status & EHCI_QTD_HALTED ? 1 : 0, | | 1202 | status & EHCI_QTD_HALTED ? 1 : 0, |
1202 | status & EHCI_QTD_BUFERR ? 1 : 0, | | 1203 | status & EHCI_QTD_BUFERR ? 1 : 0, |
1203 | status & EHCI_QTD_BABBLE ? 1 : 0); | | 1204 | status & EHCI_QTD_BABBLE ? 1 : 0); |
1204 | | | 1205 | |
1205 | USBHIST_LOG(ehcidebug, | | 1206 | USBHIST_LOG(ehcidebug, |
1206 | "xacterr=%d missed=%d split =%d ping =%d", | | 1207 | "xacterr=%d missed=%d split =%d ping =%d", |
1207 | status & EHCI_QTD_XACTERR ? 1 : 0, | | 1208 | status & EHCI_QTD_XACTERR ? 1 : 0, |
1208 | status & EHCI_QTD_MISSEDMICRO ? 1 : 0, | | 1209 | status & EHCI_QTD_MISSEDMICRO ? 1 : 0, |
1209 | status & EHCI_QTD_SPLITXSTATE ? 1 : 0, | | 1210 | status & EHCI_QTD_SPLITXSTATE ? 1 : 0, |
1210 | status & EHCI_QTD_PINGSTATE ? 1 : 0); | | 1211 | status & EHCI_QTD_PINGSTATE ? 1 : 0); |
1211 | | | 1212 | |
1212 | USBHIST_LOGN(ehcidebug, 5, "--- dump start ---", 0, 0, 0, 0); | | 1213 | USBHIST_LOGN(ehcidebug, 5, "--- dump start ---", 0, 0, 0, 0); |
1213 | ehci_dump_sqh(epipe->sqh); | | 1214 | ehci_dump_sqh(epipe->sqh); |
1214 | ehci_dump_sqtds(ex->ex_sqtdstart); | | 1215 | ehci_dump_sqtds(ex->ex_sqtdstart); |
1215 | USBHIST_LOGN(ehcidebug, 5, "--- dump end ---", 0, 0, 0, 0); | | 1216 | USBHIST_LOGN(ehcidebug, 5, "--- dump end ---", 0, 0, 0, 0); |
1216 | #endif | | 1217 | #endif |
1217 | /* low&full speed has an extra error flag */ | | 1218 | /* low&full speed has an extra error flag */ |
1218 | if (EHCI_QH_GET_EPS(epipe->sqh->qh.qh_endp) != | | 1219 | if (EHCI_QH_GET_EPS(epipe->sqh->qh.qh_endp) != |
1219 | EHCI_QH_SPEED_HIGH) | | 1220 | EHCI_QH_SPEED_HIGH) |
1220 | status &= EHCI_QTD_STATERRS | EHCI_QTD_PINGSTATE; | | 1221 | status &= EHCI_QTD_STATERRS | EHCI_QTD_PINGSTATE; |
1221 | else | | 1222 | else |
1222 | status &= EHCI_QTD_STATERRS; | | 1223 | status &= EHCI_QTD_STATERRS; |
1223 | if (status == 0) /* no other errors means a stall */ { | | 1224 | if (status == 0) /* no other errors means a stall */ { |
1224 | xfer->ux_status = USBD_STALLED; | | 1225 | xfer->ux_status = USBD_STALLED; |
1225 | } else { | | 1226 | } else { |
1226 | xfer->ux_status = USBD_IOERROR; /* more info XXX */ | | 1227 | xfer->ux_status = USBD_IOERROR; /* more info XXX */ |