| @@ -1,2042 +1,2043 @@ | | | @@ -1,2042 +1,2043 @@ |
1 | /* $NetBSD: uhci.c,v 1.227 2009/05/02 22:09:39 martin Exp $ */ | | 1 | /* $NetBSD: uhci.c,v 1.228 2009/05/02 22:28:41 martin Exp $ */ |
2 | /* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */ | | 2 | /* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. | | 5 | * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * This code is derived from software contributed to The NetBSD Foundation | | 8 | * This code is derived from software contributed to The NetBSD Foundation |
9 | * by Lennart Augustsson (lennart@augustsson.net) at | | 9 | * by Lennart Augustsson (lennart@augustsson.net) at |
10 | * Carlstedt Research & Technology. | | 10 | * Carlstedt Research & Technology. |
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 Universal Host Controller driver. | | 35 | * USB Universal Host Controller driver. |
36 | * Handles e.g. PIIX3 and PIIX4. | | 36 | * Handles e.g. PIIX3 and PIIX4. |
37 | * | | 37 | * |
38 | * UHCI spec: http://developer.intel.com/design/USB/UHCI11D.htm | | 38 | * UHCI spec: http://developer.intel.com/design/USB/UHCI11D.htm |
39 | * USB spec: http://www.usb.org/developers/docs/usbspec.zip | | 39 | * USB spec: http://www.usb.org/developers/docs/usbspec.zip |
40 | * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf | | 40 | * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf |
41 | * ftp://download.intel.com/design/intarch/datashts/29056201.pdf | | 41 | * ftp://download.intel.com/design/intarch/datashts/29056201.pdf |
42 | */ | | 42 | */ |
43 | | | 43 | |
44 | #include <sys/cdefs.h> | | 44 | #include <sys/cdefs.h> |
45 | __KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.227 2009/05/02 22:09:39 martin Exp $"); | | 45 | __KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.228 2009/05/02 22:28:41 martin Exp $"); |
46 | | | 46 | |
47 | #include <sys/param.h> | | 47 | #include <sys/param.h> |
48 | #include <sys/systm.h> | | 48 | #include <sys/systm.h> |
49 | #include <sys/kernel.h> | | 49 | #include <sys/kernel.h> |
50 | #include <sys/malloc.h> | | 50 | #include <sys/malloc.h> |
51 | #if defined(__NetBSD__) || defined(__OpenBSD__) | | 51 | #if defined(__NetBSD__) || defined(__OpenBSD__) |
52 | #include <sys/device.h> | | 52 | #include <sys/device.h> |
53 | #include <sys/select.h> | | 53 | #include <sys/select.h> |
54 | #include <sys/extent.h> | | 54 | #include <sys/extent.h> |
55 | #include <uvm/uvm_extern.h> | | 55 | #include <uvm/uvm_extern.h> |
56 | #elif defined(__FreeBSD__) | | 56 | #elif defined(__FreeBSD__) |
57 | #include <sys/module.h> | | 57 | #include <sys/module.h> |
58 | #include <sys/bus.h> | | 58 | #include <sys/bus.h> |
59 | #include <machine/bus_pio.h> | | 59 | #include <machine/bus_pio.h> |
60 | #if defined(DIAGNOSTIC) && defined(__i386__) | | 60 | #if defined(DIAGNOSTIC) && defined(__i386__) |
61 | #include <sys/cpu.h> | | 61 | #include <sys/cpu.h> |
62 | #endif | | 62 | #endif |
63 | #endif | | 63 | #endif |
64 | #include <sys/proc.h> | | 64 | #include <sys/proc.h> |
65 | #include <sys/queue.h> | | 65 | #include <sys/queue.h> |
66 | #include <sys/bus.h> | | 66 | #include <sys/bus.h> |
67 | | | 67 | |
68 | #include <machine/endian.h> | | 68 | #include <machine/endian.h> |
69 | | | 69 | |
70 | #include <dev/usb/usb.h> | | 70 | #include <dev/usb/usb.h> |
71 | #include <dev/usb/usbdi.h> | | 71 | #include <dev/usb/usbdi.h> |
72 | #include <dev/usb/usbdivar.h> | | 72 | #include <dev/usb/usbdivar.h> |
73 | #include <dev/usb/usb_mem.h> | | 73 | #include <dev/usb/usb_mem.h> |
74 | #include <dev/usb/usb_quirks.h> | | 74 | #include <dev/usb/usb_quirks.h> |
75 | | | 75 | |
76 | #include <dev/usb/uhcireg.h> | | 76 | #include <dev/usb/uhcireg.h> |
77 | #include <dev/usb/uhcivar.h> | | 77 | #include <dev/usb/uhcivar.h> |
78 | #include <dev/usb/usbroothub_subr.h> | | 78 | #include <dev/usb/usbroothub_subr.h> |
79 | | | 79 | |
80 | /* Use bandwidth reclamation for control transfers. Some devices choke on it. */ | | 80 | /* Use bandwidth reclamation for control transfers. Some devices choke on it. */ |
81 | /*#define UHCI_CTL_LOOP */ | | 81 | /*#define UHCI_CTL_LOOP */ |
82 | | | 82 | |
83 | #if defined(__FreeBSD__) | | 83 | #if defined(__FreeBSD__) |
84 | #include <machine/clock.h> | | 84 | #include <machine/clock.h> |
85 | | | 85 | |
86 | #define delay(d) DELAY(d) | | 86 | #define delay(d) DELAY(d) |
87 | #endif | | 87 | #endif |
88 | | | 88 | |
89 | #if defined(__OpenBSD__) | | 89 | #if defined(__OpenBSD__) |
90 | struct cfdriver uhci_cd = { | | 90 | struct cfdriver uhci_cd = { |
91 | NULL, "uhci", DV_DULL | | 91 | NULL, "uhci", DV_DULL |
92 | }; | | 92 | }; |
93 | #endif | | 93 | #endif |
94 | | | 94 | |
95 | #ifdef UHCI_DEBUG | | 95 | #ifdef UHCI_DEBUG |
96 | uhci_softc_t *thesc; | | 96 | uhci_softc_t *thesc; |
97 | #define DPRINTF(x) if (uhcidebug) printf x | | 97 | #define DPRINTF(x) if (uhcidebug) printf x |
98 | #define DPRINTFN(n,x) if (uhcidebug>(n)) printf x | | 98 | #define DPRINTFN(n,x) if (uhcidebug>(n)) printf x |
99 | int uhcidebug = 0; | | 99 | int uhcidebug = 0; |
100 | int uhcinoloop = 0; | | 100 | int uhcinoloop = 0; |
101 | #ifndef __NetBSD__ | | 101 | #ifndef __NetBSD__ |
102 | #define snprintb((q), (f), "%b", q,f,b,l) snprintf((b), (l)) | | 102 | #define snprintb((q), (f), "%b", q,f,b,l) snprintf((b), (l)) |
103 | #endif | | 103 | #endif |
104 | #else | | 104 | #else |
105 | #define DPRINTF(x) | | 105 | #define DPRINTF(x) |
106 | #define DPRINTFN(n,x) | | 106 | #define DPRINTFN(n,x) |
107 | #endif | | 107 | #endif |
108 | | | 108 | |
109 | /* | | 109 | /* |
110 | * The UHCI controller is little endian, so on big endian machines | | 110 | * The UHCI controller is little endian, so on big endian machines |
111 | * the data stored in memory needs to be swapped. | | 111 | * the data stored in memory needs to be swapped. |
112 | */ | | 112 | */ |
113 | #if defined(__FreeBSD__) || defined(__OpenBSD__) | | 113 | #if defined(__FreeBSD__) || defined(__OpenBSD__) |
114 | #if BYTE_ORDER == BIG_ENDIAN | | 114 | #if BYTE_ORDER == BIG_ENDIAN |
115 | #define htole32(x) (bswap32(x)) | | 115 | #define htole32(x) (bswap32(x)) |
116 | #define le32toh(x) (bswap32(x)) | | 116 | #define le32toh(x) (bswap32(x)) |
117 | #else | | 117 | #else |
118 | #define htole32(x) (x) | | 118 | #define htole32(x) (x) |
119 | #define le32toh(x) (x) | | 119 | #define le32toh(x) (x) |
120 | #endif | | 120 | #endif |
121 | #endif | | 121 | #endif |
122 | | | 122 | |
123 | struct uhci_pipe { | | 123 | struct uhci_pipe { |
124 | struct usbd_pipe pipe; | | 124 | struct usbd_pipe pipe; |
125 | int nexttoggle; | | 125 | int nexttoggle; |
126 | | | 126 | |
127 | u_char aborting; | | 127 | u_char aborting; |
128 | usbd_xfer_handle abortstart, abortend; | | 128 | usbd_xfer_handle abortstart, abortend; |
129 | | | 129 | |
130 | /* Info needed for different pipe kinds. */ | | 130 | /* Info needed for different pipe kinds. */ |
131 | union { | | 131 | union { |
132 | /* Control pipe */ | | 132 | /* Control pipe */ |
133 | struct { | | 133 | struct { |
134 | uhci_soft_qh_t *sqh; | | 134 | uhci_soft_qh_t *sqh; |
135 | usb_dma_t reqdma; | | 135 | usb_dma_t reqdma; |
136 | uhci_soft_td_t *setup, *stat; | | 136 | uhci_soft_td_t *setup, *stat; |
137 | u_int length; | | 137 | u_int length; |
138 | } ctl; | | 138 | } ctl; |
139 | /* Interrupt pipe */ | | 139 | /* Interrupt pipe */ |
140 | struct { | | 140 | struct { |
141 | int npoll; | | 141 | int npoll; |
142 | int isread; | | 142 | int isread; |
143 | uhci_soft_qh_t **qhs; | | 143 | uhci_soft_qh_t **qhs; |
144 | } intr; | | 144 | } intr; |
145 | /* Bulk pipe */ | | 145 | /* Bulk pipe */ |
146 | struct { | | 146 | struct { |
147 | uhci_soft_qh_t *sqh; | | 147 | uhci_soft_qh_t *sqh; |
148 | u_int length; | | 148 | u_int length; |
149 | int isread; | | 149 | int isread; |
150 | } bulk; | | 150 | } bulk; |
151 | /* Iso pipe */ | | 151 | /* Iso pipe */ |
152 | struct iso { | | 152 | struct iso { |
153 | uhci_soft_td_t **stds; | | 153 | uhci_soft_td_t **stds; |
154 | int next, inuse; | | 154 | int next, inuse; |
155 | } iso; | | 155 | } iso; |
156 | } u; | | 156 | } u; |
157 | }; | | 157 | }; |
158 | | | 158 | |
159 | Static void uhci_globalreset(uhci_softc_t *); | | 159 | Static void uhci_globalreset(uhci_softc_t *); |
160 | Static usbd_status uhci_portreset(uhci_softc_t*, int); | | 160 | Static usbd_status uhci_portreset(uhci_softc_t*, int); |
161 | Static void uhci_reset(uhci_softc_t *); | | 161 | Static void uhci_reset(uhci_softc_t *); |
162 | Static usbd_status uhci_run(uhci_softc_t *, int run); | | 162 | Static usbd_status uhci_run(uhci_softc_t *, int run); |
163 | Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *); | | 163 | Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *); |
164 | Static void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *); | | 164 | Static void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *); |
165 | Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *); | | 165 | Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *); |
166 | Static void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *); | | 166 | Static void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *); |
167 | #if 0 | | 167 | #if 0 |
168 | Static void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *, | | 168 | Static void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *, |
169 | uhci_intr_info_t *); | | 169 | uhci_intr_info_t *); |
170 | Static void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *); | | 170 | Static void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *); |
171 | #endif | | 171 | #endif |
172 | | | 172 | |
173 | Static void uhci_free_std_chain(uhci_softc_t *, | | 173 | Static void uhci_free_std_chain(uhci_softc_t *, |
174 | uhci_soft_td_t *, uhci_soft_td_t *); | | 174 | uhci_soft_td_t *, uhci_soft_td_t *); |
175 | Static usbd_status uhci_alloc_std_chain(struct uhci_pipe *, | | 175 | Static usbd_status uhci_alloc_std_chain(struct uhci_pipe *, |
176 | uhci_softc_t *, int, int, u_int16_t, usb_dma_t *, | | 176 | uhci_softc_t *, int, int, u_int16_t, usb_dma_t *, |
177 | uhci_soft_td_t **, uhci_soft_td_t **); | | 177 | uhci_soft_td_t **, uhci_soft_td_t **); |
178 | Static void uhci_poll_hub(void *); | | 178 | Static void uhci_poll_hub(void *); |
179 | Static void uhci_waitintr(uhci_softc_t *, usbd_xfer_handle); | | 179 | Static void uhci_waitintr(uhci_softc_t *, usbd_xfer_handle); |
180 | Static void uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *); | | 180 | Static void uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *); |
181 | Static void uhci_idone(uhci_intr_info_t *); | | 181 | Static void uhci_idone(uhci_intr_info_t *); |
182 | | | 182 | |
183 | Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status); | | 183 | Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status); |
184 | | | 184 | |
185 | Static void uhci_timeout(void *); | | 185 | Static void uhci_timeout(void *); |
186 | Static void uhci_timeout_task(void *); | | 186 | Static void uhci_timeout_task(void *); |
187 | Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *); | | 187 | Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *); |
188 | Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *); | | 188 | Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *); |
189 | Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *); | | 189 | Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *); |
190 | Static void uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *); | | 190 | Static void uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *); |
191 | Static void uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *); | | 191 | Static void uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *); |
192 | Static void uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *); | | 192 | Static void uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *); |
193 | Static void uhci_add_loop(uhci_softc_t *sc); | | 193 | Static void uhci_add_loop(uhci_softc_t *sc); |
194 | Static void uhci_rem_loop(uhci_softc_t *sc); | | 194 | Static void uhci_rem_loop(uhci_softc_t *sc); |
195 | | | 195 | |
196 | Static usbd_status uhci_setup_isoc(usbd_pipe_handle pipe); | | 196 | Static usbd_status uhci_setup_isoc(usbd_pipe_handle pipe); |
197 | Static void uhci_device_isoc_enter(usbd_xfer_handle); | | 197 | Static void uhci_device_isoc_enter(usbd_xfer_handle); |
198 | | | 198 | |
199 | Static usbd_status uhci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); | | 199 | Static usbd_status uhci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); |
200 | Static void uhci_freem(struct usbd_bus *, usb_dma_t *); | | 200 | Static void uhci_freem(struct usbd_bus *, usb_dma_t *); |
201 | | | 201 | |
202 | Static usbd_xfer_handle uhci_allocx(struct usbd_bus *); | | 202 | Static usbd_xfer_handle uhci_allocx(struct usbd_bus *); |
203 | Static void uhci_freex(struct usbd_bus *, usbd_xfer_handle); | | 203 | Static void uhci_freex(struct usbd_bus *, usbd_xfer_handle); |
204 | | | 204 | |
205 | Static usbd_status uhci_device_ctrl_transfer(usbd_xfer_handle); | | 205 | Static usbd_status uhci_device_ctrl_transfer(usbd_xfer_handle); |
206 | Static usbd_status uhci_device_ctrl_start(usbd_xfer_handle); | | 206 | Static usbd_status uhci_device_ctrl_start(usbd_xfer_handle); |
207 | Static void uhci_device_ctrl_abort(usbd_xfer_handle); | | 207 | Static void uhci_device_ctrl_abort(usbd_xfer_handle); |
208 | Static void uhci_device_ctrl_close(usbd_pipe_handle); | | 208 | Static void uhci_device_ctrl_close(usbd_pipe_handle); |
209 | Static void uhci_device_ctrl_done(usbd_xfer_handle); | | 209 | Static void uhci_device_ctrl_done(usbd_xfer_handle); |
210 | | | 210 | |
211 | Static usbd_status uhci_device_intr_transfer(usbd_xfer_handle); | | 211 | Static usbd_status uhci_device_intr_transfer(usbd_xfer_handle); |
212 | Static usbd_status uhci_device_intr_start(usbd_xfer_handle); | | 212 | Static usbd_status uhci_device_intr_start(usbd_xfer_handle); |
213 | Static void uhci_device_intr_abort(usbd_xfer_handle); | | 213 | Static void uhci_device_intr_abort(usbd_xfer_handle); |
214 | Static void uhci_device_intr_close(usbd_pipe_handle); | | 214 | Static void uhci_device_intr_close(usbd_pipe_handle); |
215 | Static void uhci_device_intr_done(usbd_xfer_handle); | | 215 | Static void uhci_device_intr_done(usbd_xfer_handle); |
216 | | | 216 | |
217 | Static usbd_status uhci_device_bulk_transfer(usbd_xfer_handle); | | 217 | Static usbd_status uhci_device_bulk_transfer(usbd_xfer_handle); |
218 | Static usbd_status uhci_device_bulk_start(usbd_xfer_handle); | | 218 | Static usbd_status uhci_device_bulk_start(usbd_xfer_handle); |
219 | Static void uhci_device_bulk_abort(usbd_xfer_handle); | | 219 | Static void uhci_device_bulk_abort(usbd_xfer_handle); |
220 | Static void uhci_device_bulk_close(usbd_pipe_handle); | | 220 | Static void uhci_device_bulk_close(usbd_pipe_handle); |
221 | Static void uhci_device_bulk_done(usbd_xfer_handle); | | 221 | Static void uhci_device_bulk_done(usbd_xfer_handle); |
222 | | | 222 | |
223 | Static usbd_status uhci_device_isoc_transfer(usbd_xfer_handle); | | 223 | Static usbd_status uhci_device_isoc_transfer(usbd_xfer_handle); |
224 | Static usbd_status uhci_device_isoc_start(usbd_xfer_handle); | | 224 | Static usbd_status uhci_device_isoc_start(usbd_xfer_handle); |
225 | Static void uhci_device_isoc_abort(usbd_xfer_handle); | | 225 | Static void uhci_device_isoc_abort(usbd_xfer_handle); |
226 | Static void uhci_device_isoc_close(usbd_pipe_handle); | | 226 | Static void uhci_device_isoc_close(usbd_pipe_handle); |
227 | Static void uhci_device_isoc_done(usbd_xfer_handle); | | 227 | Static void uhci_device_isoc_done(usbd_xfer_handle); |
228 | | | 228 | |
229 | Static usbd_status uhci_root_ctrl_transfer(usbd_xfer_handle); | | 229 | Static usbd_status uhci_root_ctrl_transfer(usbd_xfer_handle); |
230 | Static usbd_status uhci_root_ctrl_start(usbd_xfer_handle); | | 230 | Static usbd_status uhci_root_ctrl_start(usbd_xfer_handle); |
231 | Static void uhci_root_ctrl_abort(usbd_xfer_handle); | | 231 | Static void uhci_root_ctrl_abort(usbd_xfer_handle); |
232 | Static void uhci_root_ctrl_close(usbd_pipe_handle); | | 232 | Static void uhci_root_ctrl_close(usbd_pipe_handle); |
233 | Static void uhci_root_ctrl_done(usbd_xfer_handle); | | 233 | Static void uhci_root_ctrl_done(usbd_xfer_handle); |
234 | | | 234 | |
235 | Static usbd_status uhci_root_intr_transfer(usbd_xfer_handle); | | 235 | Static usbd_status uhci_root_intr_transfer(usbd_xfer_handle); |
236 | Static usbd_status uhci_root_intr_start(usbd_xfer_handle); | | 236 | Static usbd_status uhci_root_intr_start(usbd_xfer_handle); |
237 | Static void uhci_root_intr_abort(usbd_xfer_handle); | | 237 | Static void uhci_root_intr_abort(usbd_xfer_handle); |
238 | Static void uhci_root_intr_close(usbd_pipe_handle); | | 238 | Static void uhci_root_intr_close(usbd_pipe_handle); |
239 | Static void uhci_root_intr_done(usbd_xfer_handle); | | 239 | Static void uhci_root_intr_done(usbd_xfer_handle); |
240 | | | 240 | |
241 | Static usbd_status uhci_open(usbd_pipe_handle); | | 241 | Static usbd_status uhci_open(usbd_pipe_handle); |
242 | Static void uhci_poll(struct usbd_bus *); | | 242 | Static void uhci_poll(struct usbd_bus *); |
243 | Static void uhci_softintr(void *); | | 243 | Static void uhci_softintr(void *); |
244 | | | 244 | |
245 | Static usbd_status uhci_device_request(usbd_xfer_handle xfer); | | 245 | Static usbd_status uhci_device_request(usbd_xfer_handle xfer); |
246 | | | 246 | |
247 | Static void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *); | | 247 | Static void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *); |
248 | Static void uhci_remove_intr(uhci_softc_t *, uhci_soft_qh_t *); | | 248 | Static void uhci_remove_intr(uhci_softc_t *, uhci_soft_qh_t *); |
249 | Static usbd_status uhci_device_setintr(uhci_softc_t *sc, | | 249 | Static usbd_status uhci_device_setintr(uhci_softc_t *sc, |
250 | struct uhci_pipe *pipe, int ival); | | 250 | struct uhci_pipe *pipe, int ival); |
251 | | | 251 | |
252 | Static void uhci_device_clear_toggle(usbd_pipe_handle pipe); | | 252 | Static void uhci_device_clear_toggle(usbd_pipe_handle pipe); |
253 | Static void uhci_noop(usbd_pipe_handle pipe); | | 253 | Static void uhci_noop(usbd_pipe_handle pipe); |
254 | | | 254 | |
255 | Static inline uhci_soft_qh_t *uhci_find_prev_qh(uhci_soft_qh_t *, | | 255 | Static inline uhci_soft_qh_t *uhci_find_prev_qh(uhci_soft_qh_t *, |
256 | uhci_soft_qh_t *); | | 256 | uhci_soft_qh_t *); |
257 | | | 257 | |
258 | #ifdef UHCI_DEBUG | | 258 | #ifdef UHCI_DEBUG |
259 | Static void uhci_dump_all(uhci_softc_t *); | | 259 | Static void uhci_dump_all(uhci_softc_t *); |
260 | Static void uhci_dumpregs(uhci_softc_t *); | | 260 | Static void uhci_dumpregs(uhci_softc_t *); |
261 | Static void uhci_dump_qhs(uhci_soft_qh_t *); | | 261 | Static void uhci_dump_qhs(uhci_soft_qh_t *); |
262 | Static void uhci_dump_qh(uhci_soft_qh_t *); | | 262 | Static void uhci_dump_qh(uhci_soft_qh_t *); |
263 | Static void uhci_dump_tds(uhci_soft_td_t *); | | 263 | Static void uhci_dump_tds(uhci_soft_td_t *); |
264 | Static void uhci_dump_td(uhci_soft_td_t *); | | 264 | Static void uhci_dump_td(uhci_soft_td_t *); |
265 | Static void uhci_dump_ii(uhci_intr_info_t *ii); | | 265 | Static void uhci_dump_ii(uhci_intr_info_t *ii); |
266 | void uhci_dump(void); | | 266 | void uhci_dump(void); |
267 | #endif | | 267 | #endif |
268 | | | 268 | |
269 | #define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ | | 269 | #define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ |
270 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) | | 270 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) |
271 | #define UWRITE1(sc, r, x) \ | | 271 | #define UWRITE1(sc, r, x) \ |
272 | do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \ | | 272 | do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \ |
273 | } while (/*CONSTCOND*/0) | | 273 | } while (/*CONSTCOND*/0) |
274 | #define UWRITE2(sc, r, x) \ | | 274 | #define UWRITE2(sc, r, x) \ |
275 | do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \ | | 275 | do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \ |
276 | } while (/*CONSTCOND*/0) | | 276 | } while (/*CONSTCOND*/0) |
277 | #define UWRITE4(sc, r, x) \ | | 277 | #define UWRITE4(sc, r, x) \ |
278 | do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \ | | 278 | do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \ |
279 | } while (/*CONSTCOND*/0) | | 279 | } while (/*CONSTCOND*/0) |
280 | static __inline uint8_t | | 280 | static __inline uint8_t |
281 | UREAD1(uhci_softc_t *sc, bus_size_t r) | | 281 | UREAD1(uhci_softc_t *sc, bus_size_t r) |
282 | { | | 282 | { |
283 | | | 283 | |
284 | UBARR(sc); | | 284 | UBARR(sc); |
285 | return bus_space_read_1(sc->iot, sc->ioh, r); | | 285 | return bus_space_read_1(sc->iot, sc->ioh, r); |
286 | } | | 286 | } |
287 | | | 287 | |
288 | static __inline uint16_t | | 288 | static __inline uint16_t |
289 | UREAD2(uhci_softc_t *sc, bus_size_t r) | | 289 | UREAD2(uhci_softc_t *sc, bus_size_t r) |
290 | { | | 290 | { |
291 | | | 291 | |
292 | UBARR(sc); | | 292 | UBARR(sc); |
293 | return bus_space_read_2(sc->iot, sc->ioh, r); | | 293 | return bus_space_read_2(sc->iot, sc->ioh, r); |
294 | } | | 294 | } |
295 | | | 295 | |
296 | static __inline uint32_t | | 296 | static __inline uint32_t |
297 | UREAD4(uhci_softc_t *sc, bus_size_t r) | | 297 | UREAD4(uhci_softc_t *sc, bus_size_t r) |
298 | { | | 298 | { |
299 | | | 299 | |
300 | UBARR(sc); | | 300 | UBARR(sc); |
301 | return bus_space_read_4(sc->iot, sc->ioh, r); | | 301 | return bus_space_read_4(sc->iot, sc->ioh, r); |
302 | } | | 302 | } |
303 | | | 303 | |
304 | #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd) | | 304 | #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd) |
305 | #define UHCISTS(sc) UREAD2(sc, UHCI_STS) | | 305 | #define UHCISTS(sc) UREAD2(sc, UHCI_STS) |
306 | | | 306 | |
307 | #define UHCI_RESET_TIMEOUT 100 /* ms, reset timeout */ | | 307 | #define UHCI_RESET_TIMEOUT 100 /* ms, reset timeout */ |
308 | | | 308 | |
309 | #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK) | | 309 | #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK) |
310 | | | 310 | |
311 | #define UHCI_INTR_ENDPT 1 | | 311 | #define UHCI_INTR_ENDPT 1 |
312 | | | 312 | |
313 | const struct usbd_bus_methods uhci_bus_methods = { | | 313 | const struct usbd_bus_methods uhci_bus_methods = { |
314 | uhci_open, | | 314 | uhci_open, |
315 | uhci_softintr, | | 315 | uhci_softintr, |
316 | uhci_poll, | | 316 | uhci_poll, |
317 | uhci_allocm, | | 317 | uhci_allocm, |
318 | uhci_freem, | | 318 | uhci_freem, |
319 | uhci_allocx, | | 319 | uhci_allocx, |
320 | uhci_freex, | | 320 | uhci_freex, |
321 | }; | | 321 | }; |
322 | | | 322 | |
323 | const struct usbd_pipe_methods uhci_root_ctrl_methods = { | | 323 | const struct usbd_pipe_methods uhci_root_ctrl_methods = { |
324 | uhci_root_ctrl_transfer, | | 324 | uhci_root_ctrl_transfer, |
325 | uhci_root_ctrl_start, | | 325 | uhci_root_ctrl_start, |
326 | uhci_root_ctrl_abort, | | 326 | uhci_root_ctrl_abort, |
327 | uhci_root_ctrl_close, | | 327 | uhci_root_ctrl_close, |
328 | uhci_noop, | | 328 | uhci_noop, |
329 | uhci_root_ctrl_done, | | 329 | uhci_root_ctrl_done, |
330 | }; | | 330 | }; |
331 | | | 331 | |
332 | const struct usbd_pipe_methods uhci_root_intr_methods = { | | 332 | const struct usbd_pipe_methods uhci_root_intr_methods = { |
333 | uhci_root_intr_transfer, | | 333 | uhci_root_intr_transfer, |
334 | uhci_root_intr_start, | | 334 | uhci_root_intr_start, |
335 | uhci_root_intr_abort, | | 335 | uhci_root_intr_abort, |
336 | uhci_root_intr_close, | | 336 | uhci_root_intr_close, |
337 | uhci_noop, | | 337 | uhci_noop, |
338 | uhci_root_intr_done, | | 338 | uhci_root_intr_done, |
339 | }; | | 339 | }; |
340 | | | 340 | |
341 | const struct usbd_pipe_methods uhci_device_ctrl_methods = { | | 341 | const struct usbd_pipe_methods uhci_device_ctrl_methods = { |
342 | uhci_device_ctrl_transfer, | | 342 | uhci_device_ctrl_transfer, |
343 | uhci_device_ctrl_start, | | 343 | uhci_device_ctrl_start, |
344 | uhci_device_ctrl_abort, | | 344 | uhci_device_ctrl_abort, |
345 | uhci_device_ctrl_close, | | 345 | uhci_device_ctrl_close, |
346 | uhci_noop, | | 346 | uhci_noop, |
347 | uhci_device_ctrl_done, | | 347 | uhci_device_ctrl_done, |
348 | }; | | 348 | }; |
349 | | | 349 | |
350 | const struct usbd_pipe_methods uhci_device_intr_methods = { | | 350 | const struct usbd_pipe_methods uhci_device_intr_methods = { |
351 | uhci_device_intr_transfer, | | 351 | uhci_device_intr_transfer, |
352 | uhci_device_intr_start, | | 352 | uhci_device_intr_start, |
353 | uhci_device_intr_abort, | | 353 | uhci_device_intr_abort, |
354 | uhci_device_intr_close, | | 354 | uhci_device_intr_close, |
355 | uhci_device_clear_toggle, | | 355 | uhci_device_clear_toggle, |
356 | uhci_device_intr_done, | | 356 | uhci_device_intr_done, |
357 | }; | | 357 | }; |
358 | | | 358 | |
359 | const struct usbd_pipe_methods uhci_device_bulk_methods = { | | 359 | const struct usbd_pipe_methods uhci_device_bulk_methods = { |
360 | uhci_device_bulk_transfer, | | 360 | uhci_device_bulk_transfer, |
361 | uhci_device_bulk_start, | | 361 | uhci_device_bulk_start, |
362 | uhci_device_bulk_abort, | | 362 | uhci_device_bulk_abort, |
363 | uhci_device_bulk_close, | | 363 | uhci_device_bulk_close, |
364 | uhci_device_clear_toggle, | | 364 | uhci_device_clear_toggle, |
365 | uhci_device_bulk_done, | | 365 | uhci_device_bulk_done, |
366 | }; | | 366 | }; |
367 | | | 367 | |
368 | const struct usbd_pipe_methods uhci_device_isoc_methods = { | | 368 | const struct usbd_pipe_methods uhci_device_isoc_methods = { |
369 | uhci_device_isoc_transfer, | | 369 | uhci_device_isoc_transfer, |
370 | uhci_device_isoc_start, | | 370 | uhci_device_isoc_start, |
371 | uhci_device_isoc_abort, | | 371 | uhci_device_isoc_abort, |
372 | uhci_device_isoc_close, | | 372 | uhci_device_isoc_close, |
373 | uhci_noop, | | 373 | uhci_noop, |
374 | uhci_device_isoc_done, | | 374 | uhci_device_isoc_done, |
375 | }; | | 375 | }; |
376 | | | 376 | |
377 | #define uhci_add_intr_info(sc, ii) \ | | 377 | #define uhci_add_intr_info(sc, ii) \ |
378 | LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list) | | 378 | LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list) |
379 | #define uhci_del_intr_info(ii) \ | | 379 | #define uhci_del_intr_info(ii) \ |
380 | do { \ | | 380 | do { \ |
381 | LIST_REMOVE((ii), list); \ | | 381 | LIST_REMOVE((ii), list); \ |
382 | (ii)->list.le_prev = NULL; \ | | 382 | (ii)->list.le_prev = NULL; \ |
383 | } while (0) | | 383 | } while (0) |
384 | #define uhci_active_intr_info(ii) ((ii)->list.le_prev != NULL) | | 384 | #define uhci_active_intr_info(ii) ((ii)->list.le_prev != NULL) |
385 | | | 385 | |
386 | Static inline uhci_soft_qh_t * | | 386 | Static inline uhci_soft_qh_t * |
387 | uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh) | | 387 | uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh) |
388 | { | | 388 | { |
389 | DPRINTFN(15,("uhci_find_prev_qh: pqh=%p sqh=%p\n", pqh, sqh)); | | 389 | DPRINTFN(15,("uhci_find_prev_qh: pqh=%p sqh=%p\n", pqh, sqh)); |
390 | | | 390 | |
391 | for (; pqh->hlink != sqh; pqh = pqh->hlink) { | | 391 | for (; pqh->hlink != sqh; pqh = pqh->hlink) { |
392 | #if defined(DIAGNOSTIC) || defined(UHCI_DEBUG) | | 392 | #if defined(DIAGNOSTIC) || defined(UHCI_DEBUG) |
393 | usb_syncmem(&pqh->dma, | | 393 | usb_syncmem(&pqh->dma, |
394 | pqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 394 | pqh->offs + offsetof(uhci_qh_t, qh_hlink), |
395 | sizeof(pqh->qh.qh_hlink), | | 395 | sizeof(pqh->qh.qh_hlink), |
396 | BUS_DMASYNC_POSTWRITE); | | 396 | BUS_DMASYNC_POSTWRITE); |
397 | if (le32toh(pqh->qh.qh_hlink) & UHCI_PTR_T) { | | 397 | if (le32toh(pqh->qh.qh_hlink) & UHCI_PTR_T) { |
398 | printf("uhci_find_prev_qh: QH not found\n"); | | 398 | printf("uhci_find_prev_qh: QH not found\n"); |
399 | return (NULL); | | 399 | return (NULL); |
400 | } | | 400 | } |
401 | #endif | | 401 | #endif |
402 | } | | 402 | } |
403 | return (pqh); | | 403 | return (pqh); |
404 | } | | 404 | } |
405 | | | 405 | |
406 | void | | 406 | void |
407 | uhci_globalreset(uhci_softc_t *sc) | | 407 | uhci_globalreset(uhci_softc_t *sc) |
408 | { | | 408 | { |
409 | UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */ | | 409 | UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */ |
410 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */ | | 410 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */ |
411 | UHCICMD(sc, 0); /* do nothing */ | | 411 | UHCICMD(sc, 0); /* do nothing */ |
412 | } | | 412 | } |
413 | | | 413 | |
414 | usbd_status | | 414 | usbd_status |
415 | uhci_init(uhci_softc_t *sc) | | 415 | uhci_init(uhci_softc_t *sc) |
416 | { | | 416 | { |
417 | usbd_status err; | | 417 | usbd_status err; |
418 | int i, j; | | 418 | int i, j; |
419 | uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh; | | 419 | uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh; |
420 | uhci_soft_td_t *std; | | 420 | uhci_soft_td_t *std; |
421 | | | 421 | |
422 | DPRINTFN(1,("uhci_init: start\n")); | | 422 | DPRINTFN(1,("uhci_init: start\n")); |
423 | | | 423 | |
424 | #ifdef UHCI_DEBUG | | 424 | #ifdef UHCI_DEBUG |
425 | thesc = sc; | | 425 | thesc = sc; |
426 | | | 426 | |
427 | if (uhcidebug > 2) | | 427 | if (uhcidebug > 2) |
428 | uhci_dumpregs(sc); | | 428 | uhci_dumpregs(sc); |
429 | #endif | | 429 | #endif |
430 | | | 430 | |
431 | sc->sc_suspend = PWR_RESUME; | | 431 | sc->sc_suspend = PWR_RESUME; |
432 | | | 432 | |
433 | UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */ | | 433 | UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */ |
434 | uhci_globalreset(sc); /* reset the controller */ | | 434 | uhci_globalreset(sc); /* reset the controller */ |
435 | uhci_reset(sc); | | 435 | uhci_reset(sc); |
436 | | | 436 | |
437 | #ifdef __NetBSD__ | | 437 | #ifdef __NetBSD__ |
438 | usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag, | | 438 | usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag, |
439 | USB_MEM_RESERVE); | | 439 | USB_MEM_RESERVE); |
440 | #endif | | 440 | #endif |
441 | | | 441 | |
442 | /* Allocate and initialize real frame array. */ | | 442 | /* Allocate and initialize real frame array. */ |
443 | err = usb_allocmem(&sc->sc_bus, | | 443 | err = usb_allocmem(&sc->sc_bus, |
444 | UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), | | 444 | UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), |
445 | UHCI_FRAMELIST_ALIGN, &sc->sc_dma); | | 445 | UHCI_FRAMELIST_ALIGN, &sc->sc_dma); |
446 | if (err) | | 446 | if (err) |
447 | return (err); | | 447 | return (err); |
448 | sc->sc_pframes = KERNADDR(&sc->sc_dma, 0); | | 448 | sc->sc_pframes = KERNADDR(&sc->sc_dma, 0); |
449 | UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */ | | 449 | UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */ |
450 | UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/ | | 450 | UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/ |
451 | | | 451 | |
452 | /* | | 452 | /* |
453 | * Allocate a TD, inactive, that hangs from the last QH. | | 453 | * Allocate a TD, inactive, that hangs from the last QH. |
454 | * This is to avoid a bug in the PIIX that makes it run berserk | | 454 | * This is to avoid a bug in the PIIX that makes it run berserk |
455 | * otherwise. | | 455 | * otherwise. |
456 | */ | | 456 | */ |
457 | std = uhci_alloc_std(sc); | | 457 | std = uhci_alloc_std(sc); |
458 | if (std == NULL) | | 458 | if (std == NULL) |
459 | return (USBD_NOMEM); | | 459 | return (USBD_NOMEM); |
460 | std->link.std = NULL; | | 460 | std->link.std = NULL; |
461 | std->td.td_link = htole32(UHCI_PTR_T); | | 461 | std->td.td_link = htole32(UHCI_PTR_T); |
462 | std->td.td_status = htole32(0); /* inactive */ | | 462 | std->td.td_status = htole32(0); /* inactive */ |
463 | std->td.td_token = htole32(0); | | 463 | std->td.td_token = htole32(0); |
464 | std->td.td_buffer = htole32(0); | | 464 | std->td.td_buffer = htole32(0); |
465 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | | 465 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), |
466 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 466 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
467 | | | 467 | |
468 | /* Allocate the dummy QH marking the end and used for looping the QHs.*/ | | 468 | /* Allocate the dummy QH marking the end and used for looping the QHs.*/ |
469 | lsqh = uhci_alloc_sqh(sc); | | 469 | lsqh = uhci_alloc_sqh(sc); |
470 | if (lsqh == NULL) | | 470 | if (lsqh == NULL) |
471 | return (USBD_NOMEM); | | 471 | return (USBD_NOMEM); |
472 | lsqh->hlink = NULL; | | 472 | lsqh->hlink = NULL; |
473 | lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */ | | 473 | lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */ |
474 | lsqh->elink = std; | | 474 | lsqh->elink = std; |
475 | lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD); | | 475 | lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD); |
476 | sc->sc_last_qh = lsqh; | | 476 | sc->sc_last_qh = lsqh; |
477 | usb_syncmem(&lsqh->dma, lsqh->offs, sizeof(lsqh->qh), | | 477 | usb_syncmem(&lsqh->dma, lsqh->offs, sizeof(lsqh->qh), |
478 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 478 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
479 | | | 479 | |
480 | /* Allocate the dummy QH where bulk traffic will be queued. */ | | 480 | /* Allocate the dummy QH where bulk traffic will be queued. */ |
481 | bsqh = uhci_alloc_sqh(sc); | | 481 | bsqh = uhci_alloc_sqh(sc); |
482 | if (bsqh == NULL) | | 482 | if (bsqh == NULL) |
483 | return (USBD_NOMEM); | | 483 | return (USBD_NOMEM); |
484 | bsqh->hlink = lsqh; | | 484 | bsqh->hlink = lsqh; |
485 | bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH); | | 485 | bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH); |
486 | bsqh->elink = NULL; | | 486 | bsqh->elink = NULL; |
487 | bsqh->qh.qh_elink = htole32(UHCI_PTR_T); | | 487 | bsqh->qh.qh_elink = htole32(UHCI_PTR_T); |
488 | sc->sc_bulk_start = sc->sc_bulk_end = bsqh; | | 488 | sc->sc_bulk_start = sc->sc_bulk_end = bsqh; |
489 | usb_syncmem(&bsqh->dma, bsqh->offs, sizeof(bsqh->qh), | | 489 | usb_syncmem(&bsqh->dma, bsqh->offs, sizeof(bsqh->qh), |
490 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 490 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
491 | | | 491 | |
492 | /* Allocate dummy QH where high speed control traffic will be queued. */ | | 492 | /* Allocate dummy QH where high speed control traffic will be queued. */ |
493 | chsqh = uhci_alloc_sqh(sc); | | 493 | chsqh = uhci_alloc_sqh(sc); |
494 | if (chsqh == NULL) | | 494 | if (chsqh == NULL) |
495 | return (USBD_NOMEM); | | 495 | return (USBD_NOMEM); |
496 | chsqh->hlink = bsqh; | | 496 | chsqh->hlink = bsqh; |
497 | chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH); | | 497 | chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH); |
498 | chsqh->elink = NULL; | | 498 | chsqh->elink = NULL; |
499 | chsqh->qh.qh_elink = htole32(UHCI_PTR_T); | | 499 | chsqh->qh.qh_elink = htole32(UHCI_PTR_T); |
500 | sc->sc_hctl_start = sc->sc_hctl_end = chsqh; | | 500 | sc->sc_hctl_start = sc->sc_hctl_end = chsqh; |
501 | usb_syncmem(&chsqh->dma, chsqh->offs, sizeof(chsqh->qh), | | 501 | usb_syncmem(&chsqh->dma, chsqh->offs, sizeof(chsqh->qh), |
502 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 502 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
503 | | | 503 | |
504 | /* Allocate dummy QH where control traffic will be queued. */ | | 504 | /* Allocate dummy QH where control traffic will be queued. */ |
505 | clsqh = uhci_alloc_sqh(sc); | | 505 | clsqh = uhci_alloc_sqh(sc); |
506 | if (clsqh == NULL) | | 506 | if (clsqh == NULL) |
507 | return (USBD_NOMEM); | | 507 | return (USBD_NOMEM); |
508 | clsqh->hlink = chsqh; | | 508 | clsqh->hlink = chsqh; |
509 | clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH); | | 509 | clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH); |
510 | clsqh->elink = NULL; | | 510 | clsqh->elink = NULL; |
511 | clsqh->qh.qh_elink = htole32(UHCI_PTR_T); | | 511 | clsqh->qh.qh_elink = htole32(UHCI_PTR_T); |
512 | sc->sc_lctl_start = sc->sc_lctl_end = clsqh; | | 512 | sc->sc_lctl_start = sc->sc_lctl_end = clsqh; |
513 | usb_syncmem(&clsqh->dma, clsqh->offs, sizeof(clsqh->qh), | | 513 | usb_syncmem(&clsqh->dma, clsqh->offs, sizeof(clsqh->qh), |
514 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 514 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
515 | | | 515 | |
516 | /* | | 516 | /* |
517 | * Make all (virtual) frame list pointers point to the interrupt | | 517 | * Make all (virtual) frame list pointers point to the interrupt |
518 | * queue heads and the interrupt queue heads at the control | | 518 | * queue heads and the interrupt queue heads at the control |
519 | * queue head and point the physical frame list to the virtual. | | 519 | * queue head and point the physical frame list to the virtual. |
520 | */ | | 520 | */ |
521 | for(i = 0; i < UHCI_VFRAMELIST_COUNT; i++) { | | 521 | for(i = 0; i < UHCI_VFRAMELIST_COUNT; i++) { |
522 | std = uhci_alloc_std(sc); | | 522 | std = uhci_alloc_std(sc); |
523 | sqh = uhci_alloc_sqh(sc); | | 523 | sqh = uhci_alloc_sqh(sc); |
524 | if (std == NULL || sqh == NULL) | | 524 | if (std == NULL || sqh == NULL) |
525 | return (USBD_NOMEM); | | 525 | return (USBD_NOMEM); |
526 | std->link.sqh = sqh; | | 526 | std->link.sqh = sqh; |
527 | std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH); | | 527 | std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH); |
528 | std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */ | | 528 | std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */ |
529 | std->td.td_token = htole32(0); | | 529 | std->td.td_token = htole32(0); |
530 | std->td.td_buffer = htole32(0); | | 530 | std->td.td_buffer = htole32(0); |
531 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | | 531 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), |
532 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 532 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
533 | sqh->hlink = clsqh; | | 533 | sqh->hlink = clsqh; |
534 | sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH); | | 534 | sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH); |
535 | sqh->elink = NULL; | | 535 | sqh->elink = NULL; |
536 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | | 536 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); |
537 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | | 537 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), |
538 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 538 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
539 | sc->sc_vframes[i].htd = std; | | 539 | sc->sc_vframes[i].htd = std; |
540 | sc->sc_vframes[i].etd = std; | | 540 | sc->sc_vframes[i].etd = std; |
541 | sc->sc_vframes[i].hqh = sqh; | | 541 | sc->sc_vframes[i].hqh = sqh; |
542 | sc->sc_vframes[i].eqh = sqh; | | 542 | sc->sc_vframes[i].eqh = sqh; |
543 | for (j = i; | | 543 | for (j = i; |
544 | j < UHCI_FRAMELIST_COUNT; | | 544 | j < UHCI_FRAMELIST_COUNT; |
545 | j += UHCI_VFRAMELIST_COUNT) | | 545 | j += UHCI_VFRAMELIST_COUNT) |
546 | sc->sc_pframes[j] = htole32(std->physaddr); | | 546 | sc->sc_pframes[j] = htole32(std->physaddr); |
547 | } | | 547 | } |
548 | usb_syncmem(&sc->sc_dma, 0, | | 548 | usb_syncmem(&sc->sc_dma, 0, |
549 | UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), | | 549 | UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), |
550 | BUS_DMASYNC_PREWRITE); | | 550 | BUS_DMASYNC_PREWRITE); |
551 | | | 551 | |
552 | | | 552 | |
553 | LIST_INIT(&sc->sc_intrhead); | | 553 | LIST_INIT(&sc->sc_intrhead); |
554 | | | 554 | |
555 | SIMPLEQ_INIT(&sc->sc_free_xfers); | | 555 | SIMPLEQ_INIT(&sc->sc_free_xfers); |
556 | | | 556 | |
557 | usb_callout_init(sc->sc_poll_handle); | | 557 | usb_callout_init(sc->sc_poll_handle); |
558 | | | 558 | |
559 | /* Set up the bus struct. */ | | 559 | /* Set up the bus struct. */ |
560 | sc->sc_bus.methods = &uhci_bus_methods; | | 560 | sc->sc_bus.methods = &uhci_bus_methods; |
561 | sc->sc_bus.pipe_size = sizeof(struct uhci_pipe); | | 561 | sc->sc_bus.pipe_size = sizeof(struct uhci_pipe); |
562 | | | 562 | |
563 | UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */ | | 563 | UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */ |
564 | | | 564 | |
565 | DPRINTFN(1,("uhci_init: enabling\n")); | | 565 | DPRINTFN(1,("uhci_init: enabling\n")); |
566 | | | 566 | |
567 | err = uhci_run(sc, 1); /* and here we go... */ | | 567 | err = uhci_run(sc, 1); /* and here we go... */ |
568 | UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | | | 568 | UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | |
569 | UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */ | | 569 | UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */ |
570 | return err; | | 570 | return err; |
571 | } | | 571 | } |
572 | | | 572 | |
573 | #if defined(__NetBSD__) || defined(__OpenBSD__) | | 573 | #if defined(__NetBSD__) || defined(__OpenBSD__) |
574 | int | | 574 | int |
575 | uhci_activate(device_t self, enum devact act) | | 575 | uhci_activate(device_t self, enum devact act) |
576 | { | | 576 | { |
577 | struct uhci_softc *sc = device_private(self); | | 577 | struct uhci_softc *sc = device_private(self); |
578 | int rv = 0; | | 578 | int rv = 0; |
579 | | | 579 | |
580 | switch (act) { | | 580 | switch (act) { |
581 | case DVACT_ACTIVATE: | | 581 | case DVACT_ACTIVATE: |
582 | return (EOPNOTSUPP); | | 582 | return (EOPNOTSUPP); |
583 | | | 583 | |
584 | case DVACT_DEACTIVATE: | | 584 | case DVACT_DEACTIVATE: |
585 | sc->sc_dying = 1; | | 585 | sc->sc_dying = 1; |
586 | if (sc->sc_child != NULL) | | 586 | if (sc->sc_child != NULL) |
587 | rv = config_deactivate(sc->sc_child); | | 587 | rv = config_deactivate(sc->sc_child); |
588 | break; | | 588 | break; |
589 | } | | 589 | } |
590 | return (rv); | | 590 | return (rv); |
591 | } | | 591 | } |
592 | | | 592 | |
593 | void | | 593 | void |
594 | uhci_childdet(device_t self, device_t child) | | 594 | uhci_childdet(device_t self, device_t child) |
595 | { | | 595 | { |
596 | struct uhci_softc *sc = device_private(self); | | 596 | struct uhci_softc *sc = device_private(self); |
597 | | | 597 | |
598 | KASSERT(sc->sc_child == child); | | 598 | KASSERT(sc->sc_child == child); |
599 | sc->sc_child = NULL; | | 599 | sc->sc_child = NULL; |
600 | } | | 600 | } |
601 | | | 601 | |
602 | int | | 602 | int |
603 | uhci_detach(struct uhci_softc *sc, int flags) | | 603 | uhci_detach(struct uhci_softc *sc, int flags) |
604 | { | | 604 | { |
605 | usbd_xfer_handle xfer; | | 605 | usbd_xfer_handle xfer; |
606 | int rv = 0; | | 606 | int rv = 0; |
607 | | | 607 | |
608 | if (sc->sc_child != NULL) | | 608 | if (sc->sc_child != NULL) |
609 | rv = config_detach(sc->sc_child, flags); | | 609 | rv = config_detach(sc->sc_child, flags); |
610 | | | 610 | |
611 | if (rv != 0) | | 611 | if (rv != 0) |
612 | return (rv); | | 612 | return (rv); |
613 | | | 613 | |
614 | /* Free all xfers associated with this HC. */ | | 614 | /* Free all xfers associated with this HC. */ |
615 | for (;;) { | | 615 | for (;;) { |
616 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | | 616 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); |
617 | if (xfer == NULL) | | 617 | if (xfer == NULL) |
618 | break; | | 618 | break; |
619 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | | 619 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); |
620 | free(xfer, M_USB); | | 620 | free(xfer, M_USB); |
621 | } | | 621 | } |
622 | | | 622 | |
623 | callout_halt(&sc->sc_poll_handle, NULL); | | 623 | callout_halt(&sc->sc_poll_handle, NULL); |
624 | callout_destroy(&sc->sc_poll_handle); | | 624 | callout_destroy(&sc->sc_poll_handle); |
625 | | | 625 | |
626 | /* XXX free other data structures XXX */ | | 626 | /* XXX free other data structures XXX */ |
627 | | | 627 | |
628 | return (rv); | | 628 | return (rv); |
629 | } | | 629 | } |
630 | #endif | | 630 | #endif |
631 | | | 631 | |
632 | usbd_status | | 632 | usbd_status |
633 | uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) | | 633 | uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) |
634 | { | | 634 | { |
635 | struct uhci_softc *sc = bus->hci_private; | | 635 | struct uhci_softc *sc = bus->hci_private; |
636 | usbd_status status; | | 636 | usbd_status status; |
637 | u_int32_t n; | | 637 | u_int32_t n; |
638 | | | 638 | |
639 | /* | | 639 | /* |
640 | * XXX | | 640 | * XXX |
641 | * Since we are allocating a buffer we can assume that we will | | 641 | * Since we are allocating a buffer we can assume that we will |
642 | * need TDs for it. Since we don't want to allocate those from | | 642 | * need TDs for it. Since we don't want to allocate those from |
643 | * an interrupt context, we allocate them here and free them again. | | 643 | * an interrupt context, we allocate them here and free them again. |
644 | * This is no guarantee that we'll get the TDs next time... | | 644 | * This is no guarantee that we'll get the TDs next time... |
645 | */ | | 645 | */ |
646 | n = size / 8; | | 646 | n = size / 8; |
647 | if (n > 16) { | | 647 | if (n > 16) { |
648 | u_int32_t i; | | 648 | u_int32_t i; |
649 | uhci_soft_td_t **stds; | | 649 | uhci_soft_td_t **stds; |
650 | DPRINTF(("uhci_allocm: get %d TDs\n", n)); | | 650 | DPRINTF(("uhci_allocm: get %d TDs\n", n)); |
651 | stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP, | | 651 | stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP, |
652 | M_WAITOK|M_ZERO); | | 652 | M_WAITOK|M_ZERO); |
653 | for(i=0; i < n; i++) | | 653 | for(i=0; i < n; i++) |
654 | stds[i] = uhci_alloc_std(sc); | | 654 | stds[i] = uhci_alloc_std(sc); |
655 | for(i=0; i < n; i++) | | 655 | for(i=0; i < n; i++) |
656 | if (stds[i] != NULL) | | 656 | if (stds[i] != NULL) |
657 | uhci_free_std(sc, stds[i]); | | 657 | uhci_free_std(sc, stds[i]); |
658 | free(stds, M_TEMP); | | 658 | free(stds, M_TEMP); |
659 | } | | 659 | } |
660 | | | 660 | |
661 | | | 661 | |
662 | status = usb_allocmem(&sc->sc_bus, size, 0, dma); | | 662 | status = usb_allocmem(&sc->sc_bus, size, 0, dma); |
663 | #ifdef __NetBSD__ | | 663 | #ifdef __NetBSD__ |
664 | if (status == USBD_NOMEM) | | 664 | if (status == USBD_NOMEM) |
665 | status = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size); | | 665 | status = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size); |
666 | #endif | | 666 | #endif |
667 | return status; | | 667 | return status; |
668 | } | | 668 | } |
669 | | | 669 | |
670 | void | | 670 | void |
671 | uhci_freem(struct usbd_bus *bus, usb_dma_t *dma) | | 671 | uhci_freem(struct usbd_bus *bus, usb_dma_t *dma) |
672 | { | | 672 | { |
673 | #ifdef __NetBSD__ | | 673 | #ifdef __NetBSD__ |
674 | if (dma->block->flags & USB_DMA_RESERVE) { | | 674 | if (dma->block->flags & USB_DMA_RESERVE) { |
675 | usb_reserve_freem(&((struct uhci_softc *)bus)->sc_dma_reserve, | | 675 | usb_reserve_freem(&((struct uhci_softc *)bus)->sc_dma_reserve, |
676 | dma); | | 676 | dma); |
677 | return; | | 677 | return; |
678 | } | | 678 | } |
679 | #endif | | 679 | #endif |
680 | usb_freemem(&((struct uhci_softc *)bus)->sc_bus, dma); | | 680 | usb_freemem(&((struct uhci_softc *)bus)->sc_bus, dma); |
681 | } | | 681 | } |
682 | | | 682 | |
683 | usbd_xfer_handle | | 683 | usbd_xfer_handle |
684 | uhci_allocx(struct usbd_bus *bus) | | 684 | uhci_allocx(struct usbd_bus *bus) |
685 | { | | 685 | { |
686 | struct uhci_softc *sc = bus->hci_private; | | 686 | struct uhci_softc *sc = bus->hci_private; |
687 | usbd_xfer_handle xfer; | | 687 | usbd_xfer_handle xfer; |
688 | | | 688 | |
689 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | | 689 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); |
690 | if (xfer != NULL) { | | 690 | if (xfer != NULL) { |
691 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | | 691 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); |
692 | #ifdef DIAGNOSTIC | | 692 | #ifdef DIAGNOSTIC |
693 | if (xfer->busy_free != XFER_FREE) { | | 693 | if (xfer->busy_free != XFER_FREE) { |
694 | printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer, | | 694 | printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer, |
695 | xfer->busy_free); | | 695 | xfer->busy_free); |
696 | } | | 696 | } |
697 | #endif | | 697 | #endif |
698 | } else { | | 698 | } else { |
699 | xfer = malloc(sizeof(struct uhci_xfer), M_USB, M_NOWAIT); | | 699 | xfer = malloc(sizeof(struct uhci_xfer), M_USB, M_NOWAIT); |
700 | } | | 700 | } |
701 | if (xfer != NULL) { | | 701 | if (xfer != NULL) { |
702 | memset(xfer, 0, sizeof (struct uhci_xfer)); | | 702 | memset(xfer, 0, sizeof (struct uhci_xfer)); |
703 | UXFER(xfer)->iinfo.sc = sc; | | 703 | UXFER(xfer)->iinfo.sc = sc; |
704 | #ifdef DIAGNOSTIC | | 704 | #ifdef DIAGNOSTIC |
705 | UXFER(xfer)->iinfo.isdone = 1; | | 705 | UXFER(xfer)->iinfo.isdone = 1; |
706 | xfer->busy_free = XFER_BUSY; | | 706 | xfer->busy_free = XFER_BUSY; |
707 | #endif | | 707 | #endif |
708 | } | | 708 | } |
709 | return (xfer); | | 709 | return (xfer); |
710 | } | | 710 | } |
711 | | | 711 | |
712 | void | | 712 | void |
713 | uhci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) | | 713 | uhci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) |
714 | { | | 714 | { |
715 | struct uhci_softc *sc = bus->hci_private; | | 715 | struct uhci_softc *sc = bus->hci_private; |
716 | | | 716 | |
717 | #ifdef DIAGNOSTIC | | 717 | #ifdef DIAGNOSTIC |
718 | if (xfer->busy_free != XFER_BUSY) { | | 718 | if (xfer->busy_free != XFER_BUSY) { |
719 | printf("uhci_freex: xfer=%p not busy, 0x%08x\n", xfer, | | 719 | printf("uhci_freex: xfer=%p not busy, 0x%08x\n", xfer, |
720 | xfer->busy_free); | | 720 | xfer->busy_free); |
721 | } | | 721 | } |
722 | xfer->busy_free = XFER_FREE; | | 722 | xfer->busy_free = XFER_FREE; |
723 | if (!UXFER(xfer)->iinfo.isdone) { | | 723 | if (!UXFER(xfer)->iinfo.isdone) { |
724 | printf("uhci_freex: !isdone\n"); | | 724 | printf("uhci_freex: !isdone\n"); |
725 | } | | 725 | } |
726 | #endif | | 726 | #endif |
727 | SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next); | | 727 | SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next); |
728 | } | | 728 | } |
729 | | | 729 | |
730 | /* | | 730 | /* |
731 | * Handle suspend/resume. | | 731 | * Handle suspend/resume. |
732 | * | | 732 | * |
733 | * We need to switch to polling mode here, because this routine is | | 733 | * We need to switch to polling mode here, because this routine is |
734 | * called from an interrupt context. This is all right since we | | 734 | * called from an interrupt context. This is all right since we |
735 | * are almost suspended anyway. | | 735 | * are almost suspended anyway. |
736 | */ | | 736 | */ |
737 | bool | | 737 | bool |
738 | uhci_resume(device_t dv PMF_FN_ARGS) | | 738 | uhci_resume(device_t dv PMF_FN_ARGS) |
739 | { | | 739 | { |
740 | uhci_softc_t *sc = device_private(dv); | | 740 | uhci_softc_t *sc = device_private(dv); |
741 | int cmd; | | 741 | int cmd; |
742 | int s; | | 742 | int s; |
743 | | | 743 | |
744 | s = splhardusb(); | | 744 | s = splhardusb(); |
745 | | | 745 | |
746 | cmd = UREAD2(sc, UHCI_CMD); | | 746 | cmd = UREAD2(sc, UHCI_CMD); |
747 | sc->sc_bus.use_polling++; | | 747 | sc->sc_bus.use_polling++; |
748 | UWRITE2(sc, UHCI_INTR, 0); | | 748 | UWRITE2(sc, UHCI_INTR, 0); |
749 | uhci_globalreset(sc); | | 749 | uhci_globalreset(sc); |
750 | uhci_reset(sc); | | 750 | uhci_reset(sc); |
751 | if (cmd & UHCI_CMD_RS) | | 751 | if (cmd & UHCI_CMD_RS) |
752 | uhci_run(sc, 0); | | 752 | uhci_run(sc, 0); |
753 | | | 753 | |
754 | /* restore saved state */ | | 754 | /* restore saved state */ |
755 | UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); | | 755 | UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); |
756 | UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum); | | 756 | UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum); |
757 | UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof); | | 757 | UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof); |
758 | | | 758 | |
759 | UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force resume */ | | 759 | UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force resume */ |
760 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | | 760 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); |
761 | UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */ | | 761 | UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */ |
762 | UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | | | 762 | UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | |
763 | UHCI_INTR_RIE | UHCI_INTR_IOCE | UHCI_INTR_SPIE); | | 763 | UHCI_INTR_RIE | UHCI_INTR_IOCE | UHCI_INTR_SPIE); |
764 | UHCICMD(sc, UHCI_CMD_MAXP); | | 764 | UHCICMD(sc, UHCI_CMD_MAXP); |
765 | uhci_run(sc, 1); /* and start traffic again */ | | 765 | uhci_run(sc, 1); /* and start traffic again */ |
766 | usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); | | 766 | usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); |
767 | sc->sc_bus.use_polling--; | | 767 | sc->sc_bus.use_polling--; |
768 | if (sc->sc_intr_xfer != NULL) | | 768 | if (sc->sc_intr_xfer != NULL) |
769 | usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, | | 769 | usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, |
770 | sc->sc_intr_xfer); | | 770 | sc->sc_intr_xfer); |
771 | #ifdef UHCI_DEBUG | | 771 | #ifdef UHCI_DEBUG |
772 | if (uhcidebug > 2) | | 772 | if (uhcidebug > 2) |
773 | uhci_dumpregs(sc); | | 773 | uhci_dumpregs(sc); |
774 | #endif | | 774 | #endif |
775 | | | 775 | |
776 | sc->sc_suspend = PWR_RESUME; | | 776 | sc->sc_suspend = PWR_RESUME; |
777 | splx(s); | | 777 | splx(s); |
778 | | | 778 | |
779 | return true; | | 779 | return true; |
780 | } | | 780 | } |
781 | | | 781 | |
782 | bool | | 782 | bool |
783 | uhci_suspend(device_t dv PMF_FN_ARGS) | | 783 | uhci_suspend(device_t dv PMF_FN_ARGS) |
784 | { | | 784 | { |
785 | uhci_softc_t *sc = device_private(dv); | | 785 | uhci_softc_t *sc = device_private(dv); |
786 | int cmd; | | 786 | int cmd; |
787 | int s; | | 787 | int s; |
788 | | | 788 | |
789 | s = splhardusb(); | | 789 | s = splhardusb(); |
790 | | | 790 | |
791 | cmd = UREAD2(sc, UHCI_CMD); | | 791 | cmd = UREAD2(sc, UHCI_CMD); |
792 | | | 792 | |
793 | #ifdef UHCI_DEBUG | | 793 | #ifdef UHCI_DEBUG |
794 | if (uhcidebug > 2) | | 794 | if (uhcidebug > 2) |
795 | uhci_dumpregs(sc); | | 795 | uhci_dumpregs(sc); |
796 | #endif | | 796 | #endif |
797 | if (sc->sc_intr_xfer != NULL) | | 797 | if (sc->sc_intr_xfer != NULL) |
798 | usb_uncallout(sc->sc_poll_handle, uhci_poll_hub, | | 798 | usb_uncallout(sc->sc_poll_handle, uhci_poll_hub, |
799 | sc->sc_intr_xfer); | | 799 | sc->sc_intr_xfer); |
800 | sc->sc_suspend = PWR_SUSPEND; | | 800 | sc->sc_suspend = PWR_SUSPEND; |
801 | sc->sc_bus.use_polling++; | | 801 | sc->sc_bus.use_polling++; |
802 | | | 802 | |
803 | uhci_run(sc, 0); /* stop the controller */ | | 803 | uhci_run(sc, 0); /* stop the controller */ |
804 | cmd &= ~UHCI_CMD_RS; | | 804 | cmd &= ~UHCI_CMD_RS; |
805 | | | 805 | |
806 | /* save some state if BIOS doesn't */ | | 806 | /* save some state if BIOS doesn't */ |
807 | sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM); | | 807 | sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM); |
808 | sc->sc_saved_sof = UREAD1(sc, UHCI_SOF); | | 808 | sc->sc_saved_sof = UREAD1(sc, UHCI_SOF); |
809 | | | 809 | |
810 | UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */ | | 810 | UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */ |
811 | | | 811 | |
812 | UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter suspend */ | | 812 | UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter suspend */ |
813 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); | | 813 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); |
814 | sc->sc_bus.use_polling--; | | 814 | sc->sc_bus.use_polling--; |
815 | | | 815 | |
816 | splx(s); | | 816 | splx(s); |
817 | | | 817 | |
818 | return true; | | 818 | return true; |
819 | } | | 819 | } |
820 | | | 820 | |
821 | #ifdef UHCI_DEBUG | | 821 | #ifdef UHCI_DEBUG |
822 | Static void | | 822 | Static void |
823 | uhci_dumpregs(uhci_softc_t *sc) | | 823 | uhci_dumpregs(uhci_softc_t *sc) |
824 | { | | 824 | { |
825 | DPRINTFN(-1,("%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, " | | 825 | DPRINTFN(-1,("%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, " |
826 | "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n", | | 826 | "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n", |
827 | device_xname(sc->sc_dev), | | 827 | device_xname(sc->sc_dev), |
828 | UREAD2(sc, UHCI_CMD), | | 828 | UREAD2(sc, UHCI_CMD), |
829 | UREAD2(sc, UHCI_STS), | | 829 | UREAD2(sc, UHCI_STS), |
830 | UREAD2(sc, UHCI_INTR), | | 830 | UREAD2(sc, UHCI_INTR), |
831 | UREAD2(sc, UHCI_FRNUM), | | 831 | UREAD2(sc, UHCI_FRNUM), |
832 | UREAD4(sc, UHCI_FLBASEADDR), | | 832 | UREAD4(sc, UHCI_FLBASEADDR), |
833 | UREAD1(sc, UHCI_SOF), | | 833 | UREAD1(sc, UHCI_SOF), |
834 | UREAD2(sc, UHCI_PORTSC1), | | 834 | UREAD2(sc, UHCI_PORTSC1), |
835 | UREAD2(sc, UHCI_PORTSC2))); | | 835 | UREAD2(sc, UHCI_PORTSC2))); |
836 | } | | 836 | } |
837 | | | 837 | |
838 | void | | 838 | void |
839 | uhci_dump_td(uhci_soft_td_t *p) | | 839 | uhci_dump_td(uhci_soft_td_t *p) |
840 | { | | 840 | { |
841 | char sbuf[128], sbuf2[128]; | | 841 | char sbuf[128], sbuf2[128]; |
842 | | | 842 | |
843 | | | 843 | |
844 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), | | 844 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), |
845 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 845 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
846 | DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx " | | 846 | DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx " |
847 | "token=0x%08lx buffer=0x%08lx\n", | | 847 | "token=0x%08lx buffer=0x%08lx\n", |
848 | p, (long)p->physaddr, | | 848 | p, (long)p->physaddr, |
849 | (long)le32toh(p->td.td_link), | | 849 | (long)le32toh(p->td.td_link), |
850 | (long)le32toh(p->td.td_status), | | 850 | (long)le32toh(p->td.td_status), |
851 | (long)le32toh(p->td.td_token), | | 851 | (long)le32toh(p->td.td_token), |
852 | (long)le32toh(p->td.td_buffer))); | | 852 | (long)le32toh(p->td.td_buffer))); |
853 | | | 853 | |
854 | snprintb(sbuf, sizeof(sbuf), "\20\1T\2Q\3VF", | | 854 | snprintb(sbuf, sizeof(sbuf), "\20\1T\2Q\3VF", |
855 | (u_int32_t)le32toh(p->td.td_link)); | | 855 | (u_int32_t)le32toh(p->td.td_link)); |
856 | snprintb(sbuf2, sizeof(sbuf2), | | 856 | snprintb(sbuf2, sizeof(sbuf2), |
857 | "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27" | | 857 | "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27" |
858 | "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD", | | 858 | "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD", |
859 | (u_int32_t)le32toh(p->td.td_status)); | | 859 | (u_int32_t)le32toh(p->td.td_status)); |
860 | | | 860 | |
861 | DPRINTFN(-1,(" %s %s,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d," | | 861 | DPRINTFN(-1,(" %s %s,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d," |
862 | "D=%d,maxlen=%d\n", sbuf, sbuf2, | | 862 | "D=%d,maxlen=%d\n", sbuf, sbuf2, |
863 | UHCI_TD_GET_ERRCNT(le32toh(p->td.td_status)), | | 863 | UHCI_TD_GET_ERRCNT(le32toh(p->td.td_status)), |
864 | UHCI_TD_GET_ACTLEN(le32toh(p->td.td_status)), | | 864 | UHCI_TD_GET_ACTLEN(le32toh(p->td.td_status)), |
865 | UHCI_TD_GET_PID(le32toh(p->td.td_token)), | | 865 | UHCI_TD_GET_PID(le32toh(p->td.td_token)), |
866 | UHCI_TD_GET_DEVADDR(le32toh(p->td.td_token)), | | 866 | UHCI_TD_GET_DEVADDR(le32toh(p->td.td_token)), |
867 | UHCI_TD_GET_ENDPT(le32toh(p->td.td_token)), | | 867 | UHCI_TD_GET_ENDPT(le32toh(p->td.td_token)), |
868 | UHCI_TD_GET_DT(le32toh(p->td.td_token)), | | 868 | UHCI_TD_GET_DT(le32toh(p->td.td_token)), |
869 | UHCI_TD_GET_MAXLEN(le32toh(p->td.td_token)))); | | 869 | UHCI_TD_GET_MAXLEN(le32toh(p->td.td_token)))); |
870 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), | | 870 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), |
871 | BUS_DMASYNC_PREREAD); | | 871 | BUS_DMASYNC_PREREAD); |
872 | } | | 872 | } |
873 | | | 873 | |
874 | void | | 874 | void |
875 | uhci_dump_qh(uhci_soft_qh_t *sqh) | | 875 | uhci_dump_qh(uhci_soft_qh_t *sqh) |
876 | { | | 876 | { |
877 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | | 877 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), |
878 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 878 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
879 | DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh, | | 879 | DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh, |
880 | (int)sqh->physaddr, le32toh(sqh->qh.qh_hlink), | | 880 | (int)sqh->physaddr, le32toh(sqh->qh.qh_hlink), |
881 | le32toh(sqh->qh.qh_elink))); | | 881 | le32toh(sqh->qh.qh_elink))); |
882 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), BUS_DMASYNC_PREREAD); | | 882 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), BUS_DMASYNC_PREREAD); |
883 | } | | 883 | } |
884 | | | 884 | |
885 | | | 885 | |
886 | #if 1 | | 886 | #if 1 |
887 | void | | 887 | void |
888 | uhci_dump(void) | | 888 | uhci_dump(void) |
889 | { | | 889 | { |
890 | uhci_dump_all(thesc); | | 890 | uhci_dump_all(thesc); |
891 | } | | 891 | } |
892 | #endif | | 892 | #endif |
893 | | | 893 | |
894 | void | | 894 | void |
895 | uhci_dump_all(uhci_softc_t *sc) | | 895 | uhci_dump_all(uhci_softc_t *sc) |
896 | { | | 896 | { |
897 | uhci_dumpregs(sc); | | 897 | uhci_dumpregs(sc); |
898 | printf("intrs=%d\n", sc->sc_bus.no_intrs); | | 898 | printf("intrs=%d\n", sc->sc_bus.no_intrs); |
899 | /*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/ | | 899 | /*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/ |
900 | uhci_dump_qh(sc->sc_lctl_start); | | 900 | uhci_dump_qh(sc->sc_lctl_start); |
901 | } | | 901 | } |
902 | | | 902 | |
903 | | | 903 | |
904 | void | | 904 | void |
905 | uhci_dump_qhs(uhci_soft_qh_t *sqh) | | 905 | uhci_dump_qhs(uhci_soft_qh_t *sqh) |
906 | { | | 906 | { |
907 | uhci_dump_qh(sqh); | | 907 | uhci_dump_qh(sqh); |
908 | | | 908 | |
909 | /* uhci_dump_qhs displays all the QHs and TDs from the given QH onwards | | 909 | /* uhci_dump_qhs displays all the QHs and TDs from the given QH onwards |
910 | * Traverses sideways first, then down. | | 910 | * Traverses sideways first, then down. |
911 | * | | 911 | * |
912 | * QH1 | | 912 | * QH1 |
913 | * QH2 | | 913 | * QH2 |
914 | * No QH | | 914 | * No QH |
915 | * TD2.1 | | 915 | * TD2.1 |
916 | * TD2.2 | | 916 | * TD2.2 |
917 | * TD1.1 | | 917 | * TD1.1 |
918 | * etc. | | 918 | * etc. |
919 | * | | 919 | * |
920 | * TD2.x being the TDs queued at QH2 and QH1 being referenced from QH1. | | 920 | * TD2.x being the TDs queued at QH2 and QH1 being referenced from QH1. |
921 | */ | | 921 | */ |
922 | | | 922 | |
923 | | | 923 | |
924 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | | 924 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), |
925 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 925 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
926 | if (sqh->hlink != NULL && !(le32toh(sqh->qh.qh_hlink) & UHCI_PTR_T)) | | 926 | if (sqh->hlink != NULL && !(le32toh(sqh->qh.qh_hlink) & UHCI_PTR_T)) |
927 | uhci_dump_qhs(sqh->hlink); | | 927 | uhci_dump_qhs(sqh->hlink); |
928 | else | | 928 | else |
929 | DPRINTF(("No QH\n")); | | 929 | DPRINTF(("No QH\n")); |
930 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), BUS_DMASYNC_PREREAD); | | 930 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), BUS_DMASYNC_PREREAD); |
931 | | | 931 | |
932 | if (sqh->elink != NULL && !(le32toh(sqh->qh.qh_elink) & UHCI_PTR_T)) | | 932 | if (sqh->elink != NULL && !(le32toh(sqh->qh.qh_elink) & UHCI_PTR_T)) |
933 | uhci_dump_tds(sqh->elink); | | 933 | uhci_dump_tds(sqh->elink); |
934 | else | | 934 | else |
935 | DPRINTF(("No TD\n")); | | 935 | DPRINTF(("No TD\n")); |
936 | } | | 936 | } |
937 | | | 937 | |
938 | void | | 938 | void |
939 | uhci_dump_tds(uhci_soft_td_t *std) | | 939 | uhci_dump_tds(uhci_soft_td_t *std) |
940 | { | | 940 | { |
941 | uhci_soft_td_t *td; | | 941 | uhci_soft_td_t *td; |
942 | int stop; | | 942 | int stop; |
943 | | | 943 | |
944 | for(td = std; td != NULL; td = td->link.std) { | | 944 | for(td = std; td != NULL; td = td->link.std) { |
945 | uhci_dump_td(td); | | 945 | uhci_dump_td(td); |
946 | | | 946 | |
947 | /* Check whether the link pointer in this TD marks | | 947 | /* Check whether the link pointer in this TD marks |
948 | * the link pointer as end of queue. This avoids | | 948 | * the link pointer as end of queue. This avoids |
949 | * printing the free list in case the queue/TD has | | 949 | * printing the free list in case the queue/TD has |
950 | * already been moved there (seatbelt). | | 950 | * already been moved there (seatbelt). |
951 | */ | | 951 | */ |
952 | usb_syncmem(&td->dma, td->offs + offsetof(uhci_td_t, td_link), | | 952 | usb_syncmem(&td->dma, td->offs + offsetof(uhci_td_t, td_link), |
953 | sizeof(td->td.td_link), | | 953 | sizeof(td->td.td_link), |
954 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 954 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
955 | stop = (le32toh(td->td.td_link) & UHCI_PTR_T || | | 955 | stop = (le32toh(td->td.td_link) & UHCI_PTR_T || |
956 | le32toh(td->td.td_link) == 0); | | 956 | le32toh(td->td.td_link) == 0); |
957 | usb_syncmem(&td->dma, td->offs + offsetof(uhci_td_t, td_link), | | 957 | usb_syncmem(&td->dma, td->offs + offsetof(uhci_td_t, td_link), |
958 | sizeof(td->td.td_link), BUS_DMASYNC_PREREAD); | | 958 | sizeof(td->td.td_link), BUS_DMASYNC_PREREAD); |
959 | if (stop) | | 959 | if (stop) |
960 | break; | | 960 | break; |
961 | } | | 961 | } |
962 | } | | 962 | } |
963 | | | 963 | |
964 | Static void | | 964 | Static void |
965 | uhci_dump_ii(uhci_intr_info_t *ii) | | 965 | uhci_dump_ii(uhci_intr_info_t *ii) |
966 | { | | 966 | { |
967 | usbd_pipe_handle pipe; | | 967 | usbd_pipe_handle pipe; |
968 | usb_endpoint_descriptor_t *ed; | | 968 | usb_endpoint_descriptor_t *ed; |
969 | usbd_device_handle dev; | | 969 | usbd_device_handle dev; |
970 | | | 970 | |
971 | #ifdef DIAGNOSTIC | | 971 | #ifdef DIAGNOSTIC |
972 | #define DONE ii->isdone | | 972 | #define DONE ii->isdone |
973 | #else | | 973 | #else |
974 | #define DONE 0 | | 974 | #define DONE 0 |
975 | #endif | | 975 | #endif |
976 | if (ii == NULL) { | | 976 | if (ii == NULL) { |
977 | printf("ii NULL\n"); | | 977 | printf("ii NULL\n"); |
978 | return; | | 978 | return; |
979 | } | | 979 | } |
980 | if (ii->xfer == NULL) { | | 980 | if (ii->xfer == NULL) { |
981 | printf("ii %p: done=%d xfer=NULL\n", | | 981 | printf("ii %p: done=%d xfer=NULL\n", |
982 | ii, DONE); | | 982 | ii, DONE); |
983 | return; | | 983 | return; |
984 | } | | 984 | } |
985 | pipe = ii->xfer->pipe; | | 985 | pipe = ii->xfer->pipe; |
986 | if (pipe == NULL) { | | 986 | if (pipe == NULL) { |
987 | printf("ii %p: done=%d xfer=%p pipe=NULL\n", | | 987 | printf("ii %p: done=%d xfer=%p pipe=NULL\n", |
988 | ii, DONE, ii->xfer); | | 988 | ii, DONE, ii->xfer); |
989 | return; | | 989 | return; |
990 | } | | 990 | } |
991 | if (pipe->endpoint == NULL) { | | 991 | if (pipe->endpoint == NULL) { |
992 | printf("ii %p: done=%d xfer=%p pipe=%p pipe->endpoint=NULL\n", | | 992 | printf("ii %p: done=%d xfer=%p pipe=%p pipe->endpoint=NULL\n", |
993 | ii, DONE, ii->xfer, pipe); | | 993 | ii, DONE, ii->xfer, pipe); |
994 | return; | | 994 | return; |
995 | } | | 995 | } |
996 | if (pipe->device == NULL) { | | 996 | if (pipe->device == NULL) { |
997 | printf("ii %p: done=%d xfer=%p pipe=%p pipe->device=NULL\n", | | 997 | printf("ii %p: done=%d xfer=%p pipe=%p pipe->device=NULL\n", |
998 | ii, DONE, ii->xfer, pipe); | | 998 | ii, DONE, ii->xfer, pipe); |
999 | return; | | 999 | return; |
1000 | } | | 1000 | } |
1001 | ed = pipe->endpoint->edesc; | | 1001 | ed = pipe->endpoint->edesc; |
1002 | dev = pipe->device; | | 1002 | dev = pipe->device; |
1003 | printf("ii %p: done=%d xfer=%p dev=%p vid=0x%04x pid=0x%04x addr=%d pipe=%p ep=0x%02x attr=0x%02x\n", | | 1003 | printf("ii %p: done=%d xfer=%p dev=%p vid=0x%04x pid=0x%04x addr=%d pipe=%p ep=0x%02x attr=0x%02x\n", |
1004 | ii, DONE, ii->xfer, dev, | | 1004 | ii, DONE, ii->xfer, dev, |
1005 | UGETW(dev->ddesc.idVendor), | | 1005 | UGETW(dev->ddesc.idVendor), |
1006 | UGETW(dev->ddesc.idProduct), | | 1006 | UGETW(dev->ddesc.idProduct), |
1007 | dev->address, pipe, | | 1007 | dev->address, pipe, |
1008 | ed->bEndpointAddress, ed->bmAttributes); | | 1008 | ed->bEndpointAddress, ed->bmAttributes); |
1009 | #undef DONE | | 1009 | #undef DONE |
1010 | } | | 1010 | } |
1011 | | | 1011 | |
1012 | void uhci_dump_iis(struct uhci_softc *sc); | | 1012 | void uhci_dump_iis(struct uhci_softc *sc); |
1013 | void | | 1013 | void |
1014 | uhci_dump_iis(struct uhci_softc *sc) | | 1014 | uhci_dump_iis(struct uhci_softc *sc) |
1015 | { | | 1015 | { |
1016 | uhci_intr_info_t *ii; | | 1016 | uhci_intr_info_t *ii; |
1017 | | | 1017 | |
1018 | printf("intr_info list:\n"); | | 1018 | printf("intr_info list:\n"); |
1019 | for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list)) | | 1019 | for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list)) |
1020 | uhci_dump_ii(ii); | | 1020 | uhci_dump_ii(ii); |
1021 | } | | 1021 | } |
1022 | | | 1022 | |
1023 | void iidump(void); | | 1023 | void iidump(void); |
1024 | void iidump(void) { uhci_dump_iis(thesc); } | | 1024 | void iidump(void) { uhci_dump_iis(thesc); } |
1025 | | | 1025 | |
1026 | #endif | | 1026 | #endif |
1027 | | | 1027 | |
1028 | /* | | 1028 | /* |
1029 | * This routine is executed periodically and simulates interrupts | | 1029 | * This routine is executed periodically and simulates interrupts |
1030 | * from the root controller interrupt pipe for port status change. | | 1030 | * from the root controller interrupt pipe for port status change. |
1031 | */ | | 1031 | */ |
1032 | void | | 1032 | void |
1033 | uhci_poll_hub(void *addr) | | 1033 | uhci_poll_hub(void *addr) |
1034 | { | | 1034 | { |
1035 | usbd_xfer_handle xfer = addr; | | 1035 | usbd_xfer_handle xfer = addr; |
1036 | usbd_pipe_handle pipe = xfer->pipe; | | 1036 | usbd_pipe_handle pipe = xfer->pipe; |
1037 | uhci_softc_t *sc; | | 1037 | uhci_softc_t *sc; |
1038 | int s; | | 1038 | int s; |
1039 | u_char *p; | | 1039 | u_char *p; |
1040 | | | 1040 | |
1041 | DPRINTFN(20, ("uhci_poll_hub\n")); | | 1041 | DPRINTFN(20, ("uhci_poll_hub\n")); |
1042 | | | 1042 | |
1043 | if (pipe->device == NULL) return; /* device has detached */ | | 1043 | if (__predict_false(pipe->device == NULL || pipe->device->bus == NULL)) |
| | | 1044 | return; /* device has detached */ |
1044 | sc = pipe->device->bus->hci_private; | | 1045 | sc = pipe->device->bus->hci_private; |
1045 | usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer); | | 1046 | usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer); |
1046 | | | 1047 | |
1047 | p = KERNADDR(&xfer->dmabuf, 0); | | 1048 | p = KERNADDR(&xfer->dmabuf, 0); |
1048 | p[0] = 0; | | 1049 | p[0] = 0; |
1049 | if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC)) | | 1050 | if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC)) |
1050 | p[0] |= 1<<1; | | 1051 | p[0] |= 1<<1; |
1051 | if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC)) | | 1052 | if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC)) |
1052 | p[0] |= 1<<2; | | 1053 | p[0] |= 1<<2; |
1053 | if (p[0] == 0) | | 1054 | if (p[0] == 0) |
1054 | /* No change, try again in a while */ | | 1055 | /* No change, try again in a while */ |
1055 | return; | | 1056 | return; |
1056 | | | 1057 | |
1057 | xfer->actlen = 1; | | 1058 | xfer->actlen = 1; |
1058 | xfer->status = USBD_NORMAL_COMPLETION; | | 1059 | xfer->status = USBD_NORMAL_COMPLETION; |
1059 | s = splusb(); | | 1060 | s = splusb(); |
1060 | xfer->device->bus->intr_context++; | | 1061 | xfer->device->bus->intr_context++; |
1061 | usb_transfer_complete(xfer); | | 1062 | usb_transfer_complete(xfer); |
1062 | xfer->device->bus->intr_context--; | | 1063 | xfer->device->bus->intr_context--; |
1063 | splx(s); | | 1064 | splx(s); |
1064 | } | | 1065 | } |
1065 | | | 1066 | |
1066 | void | | 1067 | void |
1067 | uhci_root_intr_done(usbd_xfer_handle xfer) | | 1068 | uhci_root_intr_done(usbd_xfer_handle xfer) |
1068 | { | | 1069 | { |
1069 | } | | 1070 | } |
1070 | | | 1071 | |
1071 | void | | 1072 | void |
1072 | uhci_root_ctrl_done(usbd_xfer_handle xfer) | | 1073 | uhci_root_ctrl_done(usbd_xfer_handle xfer) |
1073 | { | | 1074 | { |
1074 | } | | 1075 | } |
1075 | | | 1076 | |
1076 | /* | | 1077 | /* |
1077 | * Let the last QH loop back to the high speed control transfer QH. | | 1078 | * Let the last QH loop back to the high speed control transfer QH. |
1078 | * This is what intel calls "bandwidth reclamation" and improves | | 1079 | * This is what intel calls "bandwidth reclamation" and improves |
1079 | * USB performance a lot for some devices. | | 1080 | * USB performance a lot for some devices. |
1080 | * If we are already looping, just count it. | | 1081 | * If we are already looping, just count it. |
1081 | */ | | 1082 | */ |
1082 | void | | 1083 | void |
1083 | uhci_add_loop(uhci_softc_t *sc) { | | 1084 | uhci_add_loop(uhci_softc_t *sc) { |
1084 | #ifdef UHCI_DEBUG | | 1085 | #ifdef UHCI_DEBUG |
1085 | if (uhcinoloop) | | 1086 | if (uhcinoloop) |
1086 | return; | | 1087 | return; |
1087 | #endif | | 1088 | #endif |
1088 | if (++sc->sc_loops == 1) { | | 1089 | if (++sc->sc_loops == 1) { |
1089 | DPRINTFN(5,("uhci_start_loop: add\n")); | | 1090 | DPRINTFN(5,("uhci_start_loop: add\n")); |
1090 | /* Note, we don't loop back the soft pointer. */ | | 1091 | /* Note, we don't loop back the soft pointer. */ |
1091 | sc->sc_last_qh->qh.qh_hlink = | | 1092 | sc->sc_last_qh->qh.qh_hlink = |
1092 | htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH); | | 1093 | htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH); |
1093 | usb_syncmem(&sc->sc_last_qh->dma, | | 1094 | usb_syncmem(&sc->sc_last_qh->dma, |
1094 | sc->sc_last_qh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1095 | sc->sc_last_qh->offs + offsetof(uhci_qh_t, qh_hlink), |
1095 | sizeof(sc->sc_last_qh->qh.qh_hlink), | | 1096 | sizeof(sc->sc_last_qh->qh.qh_hlink), |
1096 | BUS_DMASYNC_PREWRITE); | | 1097 | BUS_DMASYNC_PREWRITE); |
1097 | } | | 1098 | } |
1098 | } | | 1099 | } |
1099 | | | 1100 | |
1100 | void | | 1101 | void |
1101 | uhci_rem_loop(uhci_softc_t *sc) { | | 1102 | uhci_rem_loop(uhci_softc_t *sc) { |
1102 | #ifdef UHCI_DEBUG | | 1103 | #ifdef UHCI_DEBUG |
1103 | if (uhcinoloop) | | 1104 | if (uhcinoloop) |
1104 | return; | | 1105 | return; |
1105 | #endif | | 1106 | #endif |
1106 | if (--sc->sc_loops == 0) { | | 1107 | if (--sc->sc_loops == 0) { |
1107 | DPRINTFN(5,("uhci_end_loop: remove\n")); | | 1108 | DPRINTFN(5,("uhci_end_loop: remove\n")); |
1108 | sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T); | | 1109 | sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T); |
1109 | usb_syncmem(&sc->sc_last_qh->dma, | | 1110 | usb_syncmem(&sc->sc_last_qh->dma, |
1110 | sc->sc_last_qh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1111 | sc->sc_last_qh->offs + offsetof(uhci_qh_t, qh_hlink), |
1111 | sizeof(sc->sc_last_qh->qh.qh_hlink), | | 1112 | sizeof(sc->sc_last_qh->qh.qh_hlink), |
1112 | BUS_DMASYNC_PREWRITE); | | 1113 | BUS_DMASYNC_PREWRITE); |
1113 | } | | 1114 | } |
1114 | } | | 1115 | } |
1115 | | | 1116 | |
1116 | /* Add high speed control QH, called at splusb(). */ | | 1117 | /* Add high speed control QH, called at splusb(). */ |
1117 | void | | 1118 | void |
1118 | uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | | 1119 | uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) |
1119 | { | | 1120 | { |
1120 | uhci_soft_qh_t *eqh; | | 1121 | uhci_soft_qh_t *eqh; |
1121 | | | 1122 | |
1122 | SPLUSBCHECK; | | 1123 | SPLUSBCHECK; |
1123 | | | 1124 | |
1124 | DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh)); | | 1125 | DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh)); |
1125 | eqh = sc->sc_hctl_end; | | 1126 | eqh = sc->sc_hctl_end; |
1126 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1127 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1127 | sizeof(eqh->qh.qh_hlink), | | 1128 | sizeof(eqh->qh.qh_hlink), |
1128 | BUS_DMASYNC_POSTWRITE); | | 1129 | BUS_DMASYNC_POSTWRITE); |
1129 | sqh->hlink = eqh->hlink; | | 1130 | sqh->hlink = eqh->hlink; |
1130 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; | | 1131 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; |
1131 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | | 1132 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), |
1132 | BUS_DMASYNC_PREWRITE); | | 1133 | BUS_DMASYNC_PREWRITE); |
1133 | eqh->hlink = sqh; | | 1134 | eqh->hlink = sqh; |
1134 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); | | 1135 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); |
1135 | sc->sc_hctl_end = sqh; | | 1136 | sc->sc_hctl_end = sqh; |
1136 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1137 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1137 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | | 1138 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); |
1138 | #ifdef UHCI_CTL_LOOP | | 1139 | #ifdef UHCI_CTL_LOOP |
1139 | uhci_add_loop(sc); | | 1140 | uhci_add_loop(sc); |
1140 | #endif | | 1141 | #endif |
1141 | } | | 1142 | } |
1142 | | | 1143 | |
1143 | /* Remove high speed control QH, called at splusb(). */ | | 1144 | /* Remove high speed control QH, called at splusb(). */ |
1144 | void | | 1145 | void |
1145 | uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | | 1146 | uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) |
1146 | { | | 1147 | { |
1147 | uhci_soft_qh_t *pqh; | | 1148 | uhci_soft_qh_t *pqh; |
1148 | | | 1149 | |
1149 | SPLUSBCHECK; | | 1150 | SPLUSBCHECK; |
1150 | | | 1151 | |
1151 | DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh)); | | 1152 | DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh)); |
1152 | #ifdef UHCI_CTL_LOOP | | 1153 | #ifdef UHCI_CTL_LOOP |
1153 | uhci_rem_loop(sc); | | 1154 | uhci_rem_loop(sc); |
1154 | #endif | | 1155 | #endif |
1155 | /* | | 1156 | /* |
1156 | * The T bit should be set in the elink of the QH so that the HC | | 1157 | * The T bit should be set in the elink of the QH so that the HC |
1157 | * doesn't follow the pointer. This condition may fail if the | | 1158 | * doesn't follow the pointer. This condition may fail if the |
1158 | * the transferred packet was short so that the QH still points | | 1159 | * the transferred packet was short so that the QH still points |
1159 | * at the last used TD. | | 1160 | * at the last used TD. |
1160 | * In this case we set the T bit and wait a little for the HC | | 1161 | * In this case we set the T bit and wait a little for the HC |
1161 | * to stop looking at the TD. | | 1162 | * to stop looking at the TD. |
1162 | * Note that if the TD chain is large enough, the controller | | 1163 | * Note that if the TD chain is large enough, the controller |
1163 | * may still be looking at the chain at the end of this function. | | 1164 | * may still be looking at the chain at the end of this function. |
1164 | * uhci_free_std_chain() will make sure the controller stops | | 1165 | * uhci_free_std_chain() will make sure the controller stops |
1165 | * looking at it quickly, but until then we should not change | | 1166 | * looking at it quickly, but until then we should not change |
1166 | * sqh->hlink. | | 1167 | * sqh->hlink. |
1167 | */ | | 1168 | */ |
1168 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), | | 1169 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), |
1169 | sizeof(sqh->qh.qh_elink), | | 1170 | sizeof(sqh->qh.qh_elink), |
1170 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1171 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1171 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { | | 1172 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { |
1172 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | | 1173 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); |
1173 | usb_syncmem(&sqh->dma, | | 1174 | usb_syncmem(&sqh->dma, |
1174 | sqh->offs + offsetof(uhci_qh_t, qh_elink), | | 1175 | sqh->offs + offsetof(uhci_qh_t, qh_elink), |
1175 | sizeof(sqh->qh.qh_elink), | | 1176 | sizeof(sqh->qh.qh_elink), |
1176 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 1177 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1177 | delay(UHCI_QH_REMOVE_DELAY); | | 1178 | delay(UHCI_QH_REMOVE_DELAY); |
1178 | } | | 1179 | } |
1179 | | | 1180 | |
1180 | pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh); | | 1181 | pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh); |
1181 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1182 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1182 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | | 1183 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); |
1183 | pqh->hlink = sqh->hlink; | | 1184 | pqh->hlink = sqh->hlink; |
1184 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; | | 1185 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; |
1185 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1186 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1186 | sizeof(pqh->qh.qh_hlink), | | 1187 | sizeof(pqh->qh.qh_hlink), |
1187 | BUS_DMASYNC_PREWRITE); | | 1188 | BUS_DMASYNC_PREWRITE); |
1188 | delay(UHCI_QH_REMOVE_DELAY); | | 1189 | delay(UHCI_QH_REMOVE_DELAY); |
1189 | if (sc->sc_hctl_end == sqh) | | 1190 | if (sc->sc_hctl_end == sqh) |
1190 | sc->sc_hctl_end = pqh; | | 1191 | sc->sc_hctl_end = pqh; |
1191 | } | | 1192 | } |
1192 | | | 1193 | |
1193 | /* Add low speed control QH, called at splusb(). */ | | 1194 | /* Add low speed control QH, called at splusb(). */ |
1194 | void | | 1195 | void |
1195 | uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | | 1196 | uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) |
1196 | { | | 1197 | { |
1197 | uhci_soft_qh_t *eqh; | | 1198 | uhci_soft_qh_t *eqh; |
1198 | | | 1199 | |
1199 | SPLUSBCHECK; | | 1200 | SPLUSBCHECK; |
1200 | | | 1201 | |
1201 | DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh)); | | 1202 | DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh)); |
1202 | eqh = sc->sc_lctl_end; | | 1203 | eqh = sc->sc_lctl_end; |
1203 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1204 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1204 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | | 1205 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); |
1205 | sqh->hlink = eqh->hlink; | | 1206 | sqh->hlink = eqh->hlink; |
1206 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; | | 1207 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; |
1207 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | | 1208 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), |
1208 | BUS_DMASYNC_PREWRITE); | | 1209 | BUS_DMASYNC_PREWRITE); |
1209 | eqh->hlink = sqh; | | 1210 | eqh->hlink = sqh; |
1210 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); | | 1211 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); |
1211 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1212 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1212 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | | 1213 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); |
1213 | sc->sc_lctl_end = sqh; | | 1214 | sc->sc_lctl_end = sqh; |
1214 | } | | 1215 | } |
1215 | | | 1216 | |
1216 | /* Remove low speed control QH, called at splusb(). */ | | 1217 | /* Remove low speed control QH, called at splusb(). */ |
1217 | void | | 1218 | void |
1218 | uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | | 1219 | uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) |
1219 | { | | 1220 | { |
1220 | uhci_soft_qh_t *pqh; | | 1221 | uhci_soft_qh_t *pqh; |
1221 | | | 1222 | |
1222 | SPLUSBCHECK; | | 1223 | SPLUSBCHECK; |
1223 | | | 1224 | |
1224 | DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh)); | | 1225 | DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh)); |
1225 | /* See comment in uhci_remove_hs_ctrl() */ | | 1226 | /* See comment in uhci_remove_hs_ctrl() */ |
1226 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), | | 1227 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), |
1227 | sizeof(sqh->qh.qh_elink), | | 1228 | sizeof(sqh->qh.qh_elink), |
1228 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1229 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1229 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { | | 1230 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { |
1230 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | | 1231 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); |
1231 | usb_syncmem(&sqh->dma, | | 1232 | usb_syncmem(&sqh->dma, |
1232 | sqh->offs + offsetof(uhci_qh_t, qh_elink), | | 1233 | sqh->offs + offsetof(uhci_qh_t, qh_elink), |
1233 | sizeof(sqh->qh.qh_elink), | | 1234 | sizeof(sqh->qh.qh_elink), |
1234 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 1235 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1235 | delay(UHCI_QH_REMOVE_DELAY); | | 1236 | delay(UHCI_QH_REMOVE_DELAY); |
1236 | } | | 1237 | } |
1237 | pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh); | | 1238 | pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh); |
1238 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1239 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1239 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | | 1240 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); |
1240 | pqh->hlink = sqh->hlink; | | 1241 | pqh->hlink = sqh->hlink; |
1241 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; | | 1242 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; |
1242 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1243 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1243 | sizeof(pqh->qh.qh_hlink), | | 1244 | sizeof(pqh->qh.qh_hlink), |
1244 | BUS_DMASYNC_PREWRITE); | | 1245 | BUS_DMASYNC_PREWRITE); |
1245 | delay(UHCI_QH_REMOVE_DELAY); | | 1246 | delay(UHCI_QH_REMOVE_DELAY); |
1246 | if (sc->sc_lctl_end == sqh) | | 1247 | if (sc->sc_lctl_end == sqh) |
1247 | sc->sc_lctl_end = pqh; | | 1248 | sc->sc_lctl_end = pqh; |
1248 | } | | 1249 | } |
1249 | | | 1250 | |
1250 | /* Add bulk QH, called at splusb(). */ | | 1251 | /* Add bulk QH, called at splusb(). */ |
1251 | void | | 1252 | void |
1252 | uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | | 1253 | uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh) |
1253 | { | | 1254 | { |
1254 | uhci_soft_qh_t *eqh; | | 1255 | uhci_soft_qh_t *eqh; |
1255 | | | 1256 | |
1256 | SPLUSBCHECK; | | 1257 | SPLUSBCHECK; |
1257 | | | 1258 | |
1258 | DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh)); | | 1259 | DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh)); |
1259 | eqh = sc->sc_bulk_end; | | 1260 | eqh = sc->sc_bulk_end; |
1260 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1261 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1261 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | | 1262 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); |
1262 | sqh->hlink = eqh->hlink; | | 1263 | sqh->hlink = eqh->hlink; |
1263 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; | | 1264 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; |
1264 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | | 1265 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), |
1265 | BUS_DMASYNC_PREWRITE); | | 1266 | BUS_DMASYNC_PREWRITE); |
1266 | eqh->hlink = sqh; | | 1267 | eqh->hlink = sqh; |
1267 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); | | 1268 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); |
1268 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1269 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1269 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | | 1270 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); |
1270 | sc->sc_bulk_end = sqh; | | 1271 | sc->sc_bulk_end = sqh; |
1271 | uhci_add_loop(sc); | | 1272 | uhci_add_loop(sc); |
1272 | } | | 1273 | } |
1273 | | | 1274 | |
1274 | /* Remove bulk QH, called at splusb(). */ | | 1275 | /* Remove bulk QH, called at splusb(). */ |
1275 | void | | 1276 | void |
1276 | uhci_remove_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | | 1277 | uhci_remove_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh) |
1277 | { | | 1278 | { |
1278 | uhci_soft_qh_t *pqh; | | 1279 | uhci_soft_qh_t *pqh; |
1279 | | | 1280 | |
1280 | SPLUSBCHECK; | | 1281 | SPLUSBCHECK; |
1281 | | | 1282 | |
1282 | DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh)); | | 1283 | DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh)); |
1283 | uhci_rem_loop(sc); | | 1284 | uhci_rem_loop(sc); |
1284 | /* See comment in uhci_remove_hs_ctrl() */ | | 1285 | /* See comment in uhci_remove_hs_ctrl() */ |
1285 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), | | 1286 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), |
1286 | sizeof(sqh->qh.qh_elink), | | 1287 | sizeof(sqh->qh.qh_elink), |
1287 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1288 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1288 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { | | 1289 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { |
1289 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | | 1290 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); |
1290 | usb_syncmem(&sqh->dma, | | 1291 | usb_syncmem(&sqh->dma, |
1291 | sqh->offs + offsetof(uhci_qh_t, qh_elink), | | 1292 | sqh->offs + offsetof(uhci_qh_t, qh_elink), |
1292 | sizeof(sqh->qh.qh_elink), | | 1293 | sizeof(sqh->qh.qh_elink), |
1293 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 1294 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1294 | delay(UHCI_QH_REMOVE_DELAY); | | 1295 | delay(UHCI_QH_REMOVE_DELAY); |
1295 | } | | 1296 | } |
1296 | pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh); | | 1297 | pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh); |
1297 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1298 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1298 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | | 1299 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); |
1299 | pqh->hlink = sqh->hlink; | | 1300 | pqh->hlink = sqh->hlink; |
1300 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; | | 1301 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; |
1301 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), | | 1302 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), |
1302 | sizeof(pqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | | 1303 | sizeof(pqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); |
1303 | delay(UHCI_QH_REMOVE_DELAY); | | 1304 | delay(UHCI_QH_REMOVE_DELAY); |
1304 | if (sc->sc_bulk_end == sqh) | | 1305 | if (sc->sc_bulk_end == sqh) |
1305 | sc->sc_bulk_end = pqh; | | 1306 | sc->sc_bulk_end = pqh; |
1306 | } | | 1307 | } |
1307 | | | 1308 | |
1308 | Static int uhci_intr1(uhci_softc_t *); | | 1309 | Static int uhci_intr1(uhci_softc_t *); |
1309 | | | 1310 | |
1310 | int | | 1311 | int |
1311 | uhci_intr(void *arg) | | 1312 | uhci_intr(void *arg) |
1312 | { | | 1313 | { |
1313 | uhci_softc_t *sc = arg; | | 1314 | uhci_softc_t *sc = arg; |
1314 | | | 1315 | |
1315 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) | | 1316 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) |
1316 | return (0); | | 1317 | return (0); |
1317 | | | 1318 | |
1318 | if (sc->sc_bus.use_polling || UREAD2(sc, UHCI_INTR) == 0) { | | 1319 | if (sc->sc_bus.use_polling || UREAD2(sc, UHCI_INTR) == 0) { |
1319 | #ifdef DIAGNOSTIC | | 1320 | #ifdef DIAGNOSTIC |
1320 | DPRINTFN(16, ("uhci_intr: ignored interrupt while polling\n")); | | 1321 | DPRINTFN(16, ("uhci_intr: ignored interrupt while polling\n")); |
1321 | #endif | | 1322 | #endif |
1322 | return (0); | | 1323 | return (0); |
1323 | } | | 1324 | } |
1324 | | | 1325 | |
1325 | return (uhci_intr1(sc)); | | 1326 | return (uhci_intr1(sc)); |
1326 | } | | 1327 | } |
1327 | | | 1328 | |
1328 | int | | 1329 | int |
1329 | uhci_intr1(uhci_softc_t *sc) | | 1330 | uhci_intr1(uhci_softc_t *sc) |
1330 | { | | 1331 | { |
1331 | int status; | | 1332 | int status; |
1332 | int ack; | | 1333 | int ack; |
1333 | | | 1334 | |
1334 | #ifdef UHCI_DEBUG | | 1335 | #ifdef UHCI_DEBUG |
1335 | if (uhcidebug > 15) { | | 1336 | if (uhcidebug > 15) { |
1336 | DPRINTF(("%s: uhci_intr1\n", device_xname(sc->sc_dev))); | | 1337 | DPRINTF(("%s: uhci_intr1\n", device_xname(sc->sc_dev))); |
1337 | uhci_dumpregs(sc); | | 1338 | uhci_dumpregs(sc); |
1338 | } | | 1339 | } |
1339 | #endif | | 1340 | #endif |
1340 | | | 1341 | |
1341 | status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS; | | 1342 | status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS; |
1342 | if (status == 0) /* The interrupt was not for us. */ | | 1343 | if (status == 0) /* The interrupt was not for us. */ |
1343 | return (0); | | 1344 | return (0); |
1344 | | | 1345 | |
1345 | if (sc->sc_suspend != PWR_RESUME) { | | 1346 | if (sc->sc_suspend != PWR_RESUME) { |
1346 | #ifdef DIAGNOSTIC | | 1347 | #ifdef DIAGNOSTIC |
1347 | printf("%s: interrupt while not operating ignored\n", | | 1348 | printf("%s: interrupt while not operating ignored\n", |
1348 | device_xname(sc->sc_dev)); | | 1349 | device_xname(sc->sc_dev)); |
1349 | #endif | | 1350 | #endif |
1350 | UWRITE2(sc, UHCI_STS, status); /* acknowledge the ints */ | | 1351 | UWRITE2(sc, UHCI_STS, status); /* acknowledge the ints */ |
1351 | return (0); | | 1352 | return (0); |
1352 | } | | 1353 | } |
1353 | | | 1354 | |
1354 | ack = 0; | | 1355 | ack = 0; |
1355 | if (status & UHCI_STS_USBINT) | | 1356 | if (status & UHCI_STS_USBINT) |
1356 | ack |= UHCI_STS_USBINT; | | 1357 | ack |= UHCI_STS_USBINT; |
1357 | if (status & UHCI_STS_USBEI) | | 1358 | if (status & UHCI_STS_USBEI) |
1358 | ack |= UHCI_STS_USBEI; | | 1359 | ack |= UHCI_STS_USBEI; |
1359 | if (status & UHCI_STS_RD) { | | 1360 | if (status & UHCI_STS_RD) { |
1360 | ack |= UHCI_STS_RD; | | 1361 | ack |= UHCI_STS_RD; |
1361 | #ifdef UHCI_DEBUG | | 1362 | #ifdef UHCI_DEBUG |
1362 | printf("%s: resume detect\n", device_xname(sc->sc_dev)); | | 1363 | printf("%s: resume detect\n", device_xname(sc->sc_dev)); |
1363 | #endif | | 1364 | #endif |
1364 | } | | 1365 | } |
1365 | if (status & UHCI_STS_HSE) { | | 1366 | if (status & UHCI_STS_HSE) { |
1366 | ack |= UHCI_STS_HSE; | | 1367 | ack |= UHCI_STS_HSE; |
1367 | printf("%s: host system error\n", device_xname(sc->sc_dev)); | | 1368 | printf("%s: host system error\n", device_xname(sc->sc_dev)); |
1368 | } | | 1369 | } |
1369 | if (status & UHCI_STS_HCPE) { | | 1370 | if (status & UHCI_STS_HCPE) { |
1370 | ack |= UHCI_STS_HCPE; | | 1371 | ack |= UHCI_STS_HCPE; |
1371 | printf("%s: host controller process error\n", | | 1372 | printf("%s: host controller process error\n", |
1372 | device_xname(sc->sc_dev)); | | 1373 | device_xname(sc->sc_dev)); |
1373 | } | | 1374 | } |
1374 | if (status & UHCI_STS_HCH) { | | 1375 | if (status & UHCI_STS_HCH) { |
1375 | /* no acknowledge needed */ | | 1376 | /* no acknowledge needed */ |
1376 | if (!sc->sc_dying) { | | 1377 | if (!sc->sc_dying) { |
1377 | printf("%s: host controller halted\n", | | 1378 | printf("%s: host controller halted\n", |
1378 | device_xname(sc->sc_dev)); | | 1379 | device_xname(sc->sc_dev)); |
1379 | #ifdef UHCI_DEBUG | | 1380 | #ifdef UHCI_DEBUG |
1380 | uhci_dump_all(sc); | | 1381 | uhci_dump_all(sc); |
1381 | #endif | | 1382 | #endif |
1382 | } | | 1383 | } |
1383 | sc->sc_dying = 1; | | 1384 | sc->sc_dying = 1; |
1384 | } | | 1385 | } |
1385 | | | 1386 | |
1386 | if (!ack) | | 1387 | if (!ack) |
1387 | return (0); /* nothing to acknowledge */ | | 1388 | return (0); /* nothing to acknowledge */ |
1388 | UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */ | | 1389 | UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */ |
1389 | | | 1390 | |
1390 | sc->sc_bus.no_intrs++; | | 1391 | sc->sc_bus.no_intrs++; |
1391 | usb_schedsoftintr(&sc->sc_bus); | | 1392 | usb_schedsoftintr(&sc->sc_bus); |
1392 | | | 1393 | |
1393 | DPRINTFN(15, ("%s: uhci_intr: exit\n", device_xname(sc->sc_dev))); | | 1394 | DPRINTFN(15, ("%s: uhci_intr: exit\n", device_xname(sc->sc_dev))); |
1394 | | | 1395 | |
1395 | return (1); | | 1396 | return (1); |
1396 | } | | 1397 | } |
1397 | | | 1398 | |
1398 | void | | 1399 | void |
1399 | uhci_softintr(void *v) | | 1400 | uhci_softintr(void *v) |
1400 | { | | 1401 | { |
1401 | struct usbd_bus *bus = v; | | 1402 | struct usbd_bus *bus = v; |
1402 | uhci_softc_t *sc = bus->hci_private; | | 1403 | uhci_softc_t *sc = bus->hci_private; |
1403 | uhci_intr_info_t *ii, *nextii; | | 1404 | uhci_intr_info_t *ii, *nextii; |
1404 | | | 1405 | |
1405 | DPRINTFN(10,("%s: uhci_softintr (%d)\n", device_xname(sc->sc_dev), | | 1406 | DPRINTFN(10,("%s: uhci_softintr (%d)\n", device_xname(sc->sc_dev), |
1406 | sc->sc_bus.intr_context)); | | 1407 | sc->sc_bus.intr_context)); |
1407 | | | 1408 | |
1408 | sc->sc_bus.intr_context++; | | 1409 | sc->sc_bus.intr_context++; |
1409 | | | 1410 | |
1410 | /* | | 1411 | /* |
1411 | * Interrupts on UHCI really suck. When the host controller | | 1412 | * Interrupts on UHCI really suck. When the host controller |
1412 | * interrupts because a transfer is completed there is no | | 1413 | * interrupts because a transfer is completed there is no |
1413 | * way of knowing which transfer it was. You can scan down | | 1414 | * way of knowing which transfer it was. You can scan down |
1414 | * the TDs and QHs of the previous frame to limit the search, | | 1415 | * the TDs and QHs of the previous frame to limit the search, |
1415 | * but that assumes that the interrupt was not delayed by more | | 1416 | * but that assumes that the interrupt was not delayed by more |
1416 | * than 1 ms, which may not always be true (e.g. after debug | | 1417 | * than 1 ms, which may not always be true (e.g. after debug |
1417 | * output on a slow console). | | 1418 | * output on a slow console). |
1418 | * We scan all interrupt descriptors to see if any have | | 1419 | * We scan all interrupt descriptors to see if any have |
1419 | * completed. | | 1420 | * completed. |
1420 | */ | | 1421 | */ |
1421 | for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = nextii) { | | 1422 | for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = nextii) { |
1422 | nextii = LIST_NEXT(ii, list); | | 1423 | nextii = LIST_NEXT(ii, list); |
1423 | uhci_check_intr(sc, ii); | | 1424 | uhci_check_intr(sc, ii); |
1424 | } | | 1425 | } |
1425 | | | 1426 | |
1426 | #ifdef USB_USE_SOFTINTR | | 1427 | #ifdef USB_USE_SOFTINTR |
1427 | if (sc->sc_softwake) { | | 1428 | if (sc->sc_softwake) { |
1428 | sc->sc_softwake = 0; | | 1429 | sc->sc_softwake = 0; |
1429 | wakeup(&sc->sc_softwake); | | 1430 | wakeup(&sc->sc_softwake); |
1430 | } | | 1431 | } |
1431 | #endif /* USB_USE_SOFTINTR */ | | 1432 | #endif /* USB_USE_SOFTINTR */ |
1432 | | | 1433 | |
1433 | sc->sc_bus.intr_context--; | | 1434 | sc->sc_bus.intr_context--; |
1434 | } | | 1435 | } |
1435 | | | 1436 | |
1436 | /* Check for an interrupt. */ | | 1437 | /* Check for an interrupt. */ |
1437 | void | | 1438 | void |
1438 | uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii) | | 1439 | uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii) |
1439 | { | | 1440 | { |
1440 | uhci_soft_td_t *std, *lstd; | | 1441 | uhci_soft_td_t *std, *lstd; |
1441 | u_int32_t status; | | 1442 | u_int32_t status; |
1442 | | | 1443 | |
1443 | DPRINTFN(15, ("uhci_check_intr: ii=%p\n", ii)); | | 1444 | DPRINTFN(15, ("uhci_check_intr: ii=%p\n", ii)); |
1444 | #ifdef DIAGNOSTIC | | 1445 | #ifdef DIAGNOSTIC |
1445 | if (ii == NULL) { | | 1446 | if (ii == NULL) { |
1446 | printf("uhci_check_intr: no ii? %p\n", ii); | | 1447 | printf("uhci_check_intr: no ii? %p\n", ii); |
1447 | return; | | 1448 | return; |
1448 | } | | 1449 | } |
1449 | #endif | | 1450 | #endif |
1450 | if (ii->xfer->status == USBD_CANCELLED || | | 1451 | if (ii->xfer->status == USBD_CANCELLED || |
1451 | ii->xfer->status == USBD_TIMEOUT) { | | 1452 | ii->xfer->status == USBD_TIMEOUT) { |
1452 | DPRINTF(("uhci_check_intr: aborted xfer=%p\n", ii->xfer)); | | 1453 | DPRINTF(("uhci_check_intr: aborted xfer=%p\n", ii->xfer)); |
1453 | return; | | 1454 | return; |
1454 | } | | 1455 | } |
1455 | | | 1456 | |
1456 | if (ii->stdstart == NULL) | | 1457 | if (ii->stdstart == NULL) |
1457 | return; | | 1458 | return; |
1458 | lstd = ii->stdend; | | 1459 | lstd = ii->stdend; |
1459 | #ifdef DIAGNOSTIC | | 1460 | #ifdef DIAGNOSTIC |
1460 | if (lstd == NULL) { | | 1461 | if (lstd == NULL) { |
1461 | printf("uhci_check_intr: std==0\n"); | | 1462 | printf("uhci_check_intr: std==0\n"); |
1462 | return; | | 1463 | return; |
1463 | } | | 1464 | } |
1464 | #endif | | 1465 | #endif |
1465 | /* | | 1466 | /* |
1466 | * If the last TD is still active we need to check whether there | | 1467 | * If the last TD is still active we need to check whether there |
1467 | * is an error somewhere in the middle, or whether there was a | | 1468 | * is an error somewhere in the middle, or whether there was a |
1468 | * short packet (SPD and not ACTIVE). | | 1469 | * short packet (SPD and not ACTIVE). |
1469 | */ | | 1470 | */ |
1470 | usb_syncmem(&lstd->dma, | | 1471 | usb_syncmem(&lstd->dma, |
1471 | lstd->offs + offsetof(uhci_td_t, td_status), | | 1472 | lstd->offs + offsetof(uhci_td_t, td_status), |
1472 | sizeof(lstd->td.td_status), | | 1473 | sizeof(lstd->td.td_status), |
1473 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1474 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1474 | if (le32toh(lstd->td.td_status) & UHCI_TD_ACTIVE) { | | 1475 | if (le32toh(lstd->td.td_status) & UHCI_TD_ACTIVE) { |
1475 | DPRINTFN(12, ("uhci_check_intr: active ii=%p\n", ii)); | | 1476 | DPRINTFN(12, ("uhci_check_intr: active ii=%p\n", ii)); |
1476 | for (std = ii->stdstart; std != lstd; std = std->link.std) { | | 1477 | for (std = ii->stdstart; std != lstd; std = std->link.std) { |
1477 | usb_syncmem(&std->dma, | | 1478 | usb_syncmem(&std->dma, |
1478 | std->offs + offsetof(uhci_td_t, td_status), | | 1479 | std->offs + offsetof(uhci_td_t, td_status), |
1479 | sizeof(std->td.td_status), | | 1480 | sizeof(std->td.td_status), |
1480 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1481 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1481 | status = le32toh(std->td.td_status); | | 1482 | status = le32toh(std->td.td_status); |
1482 | usb_syncmem(&std->dma, | | 1483 | usb_syncmem(&std->dma, |
1483 | std->offs + offsetof(uhci_td_t, td_status), | | 1484 | std->offs + offsetof(uhci_td_t, td_status), |
1484 | sizeof(std->td.td_status), BUS_DMASYNC_PREREAD); | | 1485 | sizeof(std->td.td_status), BUS_DMASYNC_PREREAD); |
1485 | /* If there's an active TD the xfer isn't done. */ | | 1486 | /* If there's an active TD the xfer isn't done. */ |
1486 | if (status & UHCI_TD_ACTIVE) | | 1487 | if (status & UHCI_TD_ACTIVE) |
1487 | break; | | 1488 | break; |
1488 | /* Any kind of error makes the xfer done. */ | | 1489 | /* Any kind of error makes the xfer done. */ |
1489 | if (status & UHCI_TD_STALLED) | | 1490 | if (status & UHCI_TD_STALLED) |
1490 | goto done; | | 1491 | goto done; |
1491 | /* We want short packets, and it is short: it's done */ | | 1492 | /* We want short packets, and it is short: it's done */ |
1492 | usb_syncmem(&std->dma, | | 1493 | usb_syncmem(&std->dma, |
1493 | std->offs + offsetof(uhci_td_t, td_token), | | 1494 | std->offs + offsetof(uhci_td_t, td_token), |
1494 | sizeof(std->td.td_token), | | 1495 | sizeof(std->td.td_token), |
1495 | BUS_DMASYNC_POSTWRITE); | | 1496 | BUS_DMASYNC_POSTWRITE); |
1496 | if ((status & UHCI_TD_SPD) && | | 1497 | if ((status & UHCI_TD_SPD) && |
1497 | UHCI_TD_GET_ACTLEN(status) < | | 1498 | UHCI_TD_GET_ACTLEN(status) < |
1498 | UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token))) | | 1499 | UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token))) |
1499 | goto done; | | 1500 | goto done; |
1500 | } | | 1501 | } |
1501 | DPRINTFN(12, ("uhci_check_intr: ii=%p std=%p still active\n", | | 1502 | DPRINTFN(12, ("uhci_check_intr: ii=%p std=%p still active\n", |
1502 | ii, ii->stdstart)); | | 1503 | ii, ii->stdstart)); |
1503 | usb_syncmem(&lstd->dma, | | 1504 | usb_syncmem(&lstd->dma, |
1504 | lstd->offs + offsetof(uhci_td_t, td_status), | | 1505 | lstd->offs + offsetof(uhci_td_t, td_status), |
1505 | sizeof(lstd->td.td_status), | | 1506 | sizeof(lstd->td.td_status), |
1506 | BUS_DMASYNC_PREREAD); | | 1507 | BUS_DMASYNC_PREREAD); |
1507 | return; | | 1508 | return; |
1508 | } | | 1509 | } |
1509 | done: | | 1510 | done: |
1510 | DPRINTFN(12, ("uhci_check_intr: ii=%p done\n", ii)); | | 1511 | DPRINTFN(12, ("uhci_check_intr: ii=%p done\n", ii)); |
1511 | usb_uncallout(ii->xfer->timeout_handle, uhci_timeout, ii); | | 1512 | usb_uncallout(ii->xfer->timeout_handle, uhci_timeout, ii); |
1512 | uhci_idone(ii); | | 1513 | uhci_idone(ii); |
1513 | } | | 1514 | } |
1514 | | | 1515 | |
1515 | /* Called at splusb() */ | | 1516 | /* Called at splusb() */ |
1516 | void | | 1517 | void |
1517 | uhci_idone(uhci_intr_info_t *ii) | | 1518 | uhci_idone(uhci_intr_info_t *ii) |
1518 | { | | 1519 | { |
1519 | usbd_xfer_handle xfer = ii->xfer; | | 1520 | usbd_xfer_handle xfer = ii->xfer; |
1520 | struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; | | 1521 | struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; |
1521 | uhci_soft_td_t *std; | | 1522 | uhci_soft_td_t *std; |
1522 | u_int32_t status = 0, nstatus; | | 1523 | u_int32_t status = 0, nstatus; |
1523 | int actlen; | | 1524 | int actlen; |
1524 | | | 1525 | |
1525 | DPRINTFN(12, ("uhci_idone: ii=%p\n", ii)); | | 1526 | DPRINTFN(12, ("uhci_idone: ii=%p\n", ii)); |
1526 | #ifdef DIAGNOSTIC | | 1527 | #ifdef DIAGNOSTIC |
1527 | { | | 1528 | { |
1528 | int s = splhigh(); | | 1529 | int s = splhigh(); |
1529 | if (ii->isdone) { | | 1530 | if (ii->isdone) { |
1530 | splx(s); | | 1531 | splx(s); |
1531 | #ifdef UHCI_DEBUG | | 1532 | #ifdef UHCI_DEBUG |
1532 | printf("uhci_idone: ii is done!\n "); | | 1533 | printf("uhci_idone: ii is done!\n "); |
1533 | uhci_dump_ii(ii); | | 1534 | uhci_dump_ii(ii); |
1534 | #else | | 1535 | #else |
1535 | printf("uhci_idone: ii=%p is done!\n", ii); | | 1536 | printf("uhci_idone: ii=%p is done!\n", ii); |
1536 | #endif | | 1537 | #endif |
1537 | return; | | 1538 | return; |
1538 | } | | 1539 | } |
1539 | ii->isdone = 1; | | 1540 | ii->isdone = 1; |
1540 | splx(s); | | 1541 | splx(s); |
1541 | } | | 1542 | } |
1542 | #endif | | 1543 | #endif |
1543 | | | 1544 | |
1544 | if (xfer->nframes != 0) { | | 1545 | if (xfer->nframes != 0) { |
1545 | /* Isoc transfer, do things differently. */ | | 1546 | /* Isoc transfer, do things differently. */ |
1546 | uhci_soft_td_t **stds = upipe->u.iso.stds; | | 1547 | uhci_soft_td_t **stds = upipe->u.iso.stds; |
1547 | int i, n, nframes, len; | | 1548 | int i, n, nframes, len; |
1548 | | | 1549 | |
1549 | DPRINTFN(5,("uhci_idone: ii=%p isoc ready\n", ii)); | | 1550 | DPRINTFN(5,("uhci_idone: ii=%p isoc ready\n", ii)); |
1550 | | | 1551 | |
1551 | nframes = xfer->nframes; | | 1552 | nframes = xfer->nframes; |
1552 | actlen = 0; | | 1553 | actlen = 0; |
1553 | n = UXFER(xfer)->curframe; | | 1554 | n = UXFER(xfer)->curframe; |
1554 | for (i = 0; i < nframes; i++) { | | 1555 | for (i = 0; i < nframes; i++) { |
1555 | std = stds[n]; | | 1556 | std = stds[n]; |
1556 | #ifdef UHCI_DEBUG | | 1557 | #ifdef UHCI_DEBUG |
1557 | if (uhcidebug > 5) { | | 1558 | if (uhcidebug > 5) { |
1558 | DPRINTFN(-1,("uhci_idone: isoc TD %d\n", i)); | | 1559 | DPRINTFN(-1,("uhci_idone: isoc TD %d\n", i)); |
1559 | uhci_dump_td(std); | | 1560 | uhci_dump_td(std); |
1560 | } | | 1561 | } |
1561 | #endif | | 1562 | #endif |
1562 | if (++n >= UHCI_VFRAMELIST_COUNT) | | 1563 | if (++n >= UHCI_VFRAMELIST_COUNT) |
1563 | n = 0; | | 1564 | n = 0; |
1564 | usb_syncmem(&std->dma, | | 1565 | usb_syncmem(&std->dma, |
1565 | std->offs + offsetof(uhci_td_t, td_status), | | 1566 | std->offs + offsetof(uhci_td_t, td_status), |
1566 | sizeof(std->td.td_status), | | 1567 | sizeof(std->td.td_status), |
1567 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1568 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1568 | status = le32toh(std->td.td_status); | | 1569 | status = le32toh(std->td.td_status); |
1569 | len = UHCI_TD_GET_ACTLEN(status); | | 1570 | len = UHCI_TD_GET_ACTLEN(status); |
1570 | xfer->frlengths[i] = len; | | 1571 | xfer->frlengths[i] = len; |
1571 | actlen += len; | | 1572 | actlen += len; |
1572 | } | | 1573 | } |
1573 | upipe->u.iso.inuse -= nframes; | | 1574 | upipe->u.iso.inuse -= nframes; |
1574 | xfer->actlen = actlen; | | 1575 | xfer->actlen = actlen; |
1575 | xfer->status = USBD_NORMAL_COMPLETION; | | 1576 | xfer->status = USBD_NORMAL_COMPLETION; |
1576 | goto end; | | 1577 | goto end; |
1577 | } | | 1578 | } |
1578 | | | 1579 | |
1579 | #ifdef UHCI_DEBUG | | 1580 | #ifdef UHCI_DEBUG |
1580 | DPRINTFN(10, ("uhci_idone: ii=%p, xfer=%p, pipe=%p ready\n", | | 1581 | DPRINTFN(10, ("uhci_idone: ii=%p, xfer=%p, pipe=%p ready\n", |
1581 | ii, xfer, upipe)); | | 1582 | ii, xfer, upipe)); |
1582 | if (uhcidebug > 10) | | 1583 | if (uhcidebug > 10) |
1583 | uhci_dump_tds(ii->stdstart); | | 1584 | uhci_dump_tds(ii->stdstart); |
1584 | #endif | | 1585 | #endif |
1585 | | | 1586 | |
1586 | /* The transfer is done, compute actual length and status. */ | | 1587 | /* The transfer is done, compute actual length and status. */ |
1587 | actlen = 0; | | 1588 | actlen = 0; |
1588 | for (std = ii->stdstart; std != NULL; std = std->link.std) { | | 1589 | for (std = ii->stdstart; std != NULL; std = std->link.std) { |
1589 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | | 1590 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), |
1590 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1591 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1591 | nstatus = le32toh(std->td.td_status); | | 1592 | nstatus = le32toh(std->td.td_status); |
1592 | if (nstatus & UHCI_TD_ACTIVE) | | 1593 | if (nstatus & UHCI_TD_ACTIVE) |
1593 | break; | | 1594 | break; |
1594 | | | 1595 | |
1595 | status = nstatus; | | 1596 | status = nstatus; |
1596 | if (UHCI_TD_GET_PID(le32toh(std->td.td_token)) != | | 1597 | if (UHCI_TD_GET_PID(le32toh(std->td.td_token)) != |
1597 | UHCI_TD_PID_SETUP) | | 1598 | UHCI_TD_PID_SETUP) |
1598 | actlen += UHCI_TD_GET_ACTLEN(status); | | 1599 | actlen += UHCI_TD_GET_ACTLEN(status); |
1599 | else { | | 1600 | else { |
1600 | /* | | 1601 | /* |
1601 | * UHCI will report CRCTO in addition to a STALL or NAK | | 1602 | * UHCI will report CRCTO in addition to a STALL or NAK |
1602 | * for a SETUP transaction. See section 3.2.2, "TD | | 1603 | * for a SETUP transaction. See section 3.2.2, "TD |
1603 | * CONTROL AND STATUS". | | 1604 | * CONTROL AND STATUS". |
1604 | */ | | 1605 | */ |
1605 | if (status & (UHCI_TD_STALLED | UHCI_TD_NAK)) | | 1606 | if (status & (UHCI_TD_STALLED | UHCI_TD_NAK)) |
1606 | status &= ~UHCI_TD_CRCTO; | | 1607 | status &= ~UHCI_TD_CRCTO; |
1607 | } | | 1608 | } |
1608 | } | | 1609 | } |
1609 | /* If there are left over TDs we need to update the toggle. */ | | 1610 | /* If there are left over TDs we need to update the toggle. */ |
1610 | if (std != NULL) | | 1611 | if (std != NULL) |
1611 | upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token)); | | 1612 | upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token)); |
1612 | | | 1613 | |
1613 | status &= UHCI_TD_ERROR; | | 1614 | status &= UHCI_TD_ERROR; |
1614 | DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n", | | 1615 | DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n", |
1615 | actlen, status)); | | 1616 | actlen, status)); |
1616 | xfer->actlen = actlen; | | 1617 | xfer->actlen = actlen; |
1617 | if (status != 0) { | | 1618 | if (status != 0) { |
1618 | #ifdef UHCI_DEBUG | | 1619 | #ifdef UHCI_DEBUG |
1619 | char sbuf[128]; | | 1620 | char sbuf[128]; |
1620 | | | 1621 | |
1621 | snprintb(sbuf, sizeof(sbuf), | | 1622 | snprintb(sbuf, sizeof(sbuf), |
1622 | "\20\22BITSTUFF\23CRCTO\24NAK\25" | | 1623 | "\20\22BITSTUFF\23CRCTO\24NAK\25" |
1623 | "BABBLE\26DBUFFER\27STALLED\30ACTIVE",(u_int32_t)status); | | 1624 | "BABBLE\26DBUFFER\27STALLED\30ACTIVE",(u_int32_t)status); |
1624 | | | 1625 | |
1625 | DPRINTFN((status == UHCI_TD_STALLED)*10, | | 1626 | DPRINTFN((status == UHCI_TD_STALLED)*10, |
1626 | ("uhci_idone: error, addr=%d, endpt=0x%02x, " | | 1627 | ("uhci_idone: error, addr=%d, endpt=0x%02x, " |
1627 | "status 0x%s\n", | | 1628 | "status 0x%s\n", |
1628 | xfer->pipe->device->address, | | 1629 | xfer->pipe->device->address, |
1629 | xfer->pipe->endpoint->edesc->bEndpointAddress, | | 1630 | xfer->pipe->endpoint->edesc->bEndpointAddress, |
1630 | sbuf)); | | 1631 | sbuf)); |
1631 | #endif | | 1632 | #endif |
1632 | | | 1633 | |
1633 | if (status == UHCI_TD_STALLED) | | 1634 | if (status == UHCI_TD_STALLED) |
1634 | xfer->status = USBD_STALLED; | | 1635 | xfer->status = USBD_STALLED; |
1635 | else | | 1636 | else |
1636 | xfer->status = USBD_IOERROR; /* more info XXX */ | | 1637 | xfer->status = USBD_IOERROR; /* more info XXX */ |
1637 | } else { | | 1638 | } else { |
1638 | xfer->status = USBD_NORMAL_COMPLETION; | | 1639 | xfer->status = USBD_NORMAL_COMPLETION; |
1639 | } | | 1640 | } |
1640 | | | 1641 | |
1641 | end: | | 1642 | end: |
1642 | usb_transfer_complete(xfer); | | 1643 | usb_transfer_complete(xfer); |
1643 | DPRINTFN(12, ("uhci_idone: ii=%p done\n", ii)); | | 1644 | DPRINTFN(12, ("uhci_idone: ii=%p done\n", ii)); |
1644 | } | | 1645 | } |
1645 | | | 1646 | |
1646 | /* | | 1647 | /* |
1647 | * Called when a request does not complete. | | 1648 | * Called when a request does not complete. |
1648 | */ | | 1649 | */ |
1649 | void | | 1650 | void |
1650 | uhci_timeout(void *addr) | | 1651 | uhci_timeout(void *addr) |
1651 | { | | 1652 | { |
1652 | uhci_intr_info_t *ii = addr; | | 1653 | uhci_intr_info_t *ii = addr; |
1653 | struct uhci_xfer *uxfer = UXFER(ii->xfer); | | 1654 | struct uhci_xfer *uxfer = UXFER(ii->xfer); |
1654 | struct uhci_pipe *upipe = (struct uhci_pipe *)uxfer->xfer.pipe; | | 1655 | struct uhci_pipe *upipe = (struct uhci_pipe *)uxfer->xfer.pipe; |
1655 | uhci_softc_t *sc = upipe->pipe.device->bus->hci_private; | | 1656 | uhci_softc_t *sc = upipe->pipe.device->bus->hci_private; |
1656 | | | 1657 | |
1657 | DPRINTF(("uhci_timeout: uxfer=%p\n", uxfer)); | | 1658 | DPRINTF(("uhci_timeout: uxfer=%p\n", uxfer)); |
1658 | | | 1659 | |
1659 | if (sc->sc_dying) { | | 1660 | if (sc->sc_dying) { |
1660 | uhci_abort_xfer(&uxfer->xfer, USBD_TIMEOUT); | | 1661 | uhci_abort_xfer(&uxfer->xfer, USBD_TIMEOUT); |
1661 | return; | | 1662 | return; |
1662 | } | | 1663 | } |
1663 | | | 1664 | |
1664 | /* Execute the abort in a process context. */ | | 1665 | /* Execute the abort in a process context. */ |
1665 | usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer); | | 1666 | usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer); |
1666 | usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task, | | 1667 | usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task, |
1667 | USB_TASKQ_HC); | | 1668 | USB_TASKQ_HC); |
1668 | } | | 1669 | } |
1669 | | | 1670 | |
1670 | void | | 1671 | void |
1671 | uhci_timeout_task(void *addr) | | 1672 | uhci_timeout_task(void *addr) |
1672 | { | | 1673 | { |
1673 | usbd_xfer_handle xfer = addr; | | 1674 | usbd_xfer_handle xfer = addr; |
1674 | int s; | | 1675 | int s; |
1675 | | | 1676 | |
1676 | DPRINTF(("uhci_timeout_task: xfer=%p\n", xfer)); | | 1677 | DPRINTF(("uhci_timeout_task: xfer=%p\n", xfer)); |
1677 | | | 1678 | |
1678 | s = splusb(); | | 1679 | s = splusb(); |
1679 | uhci_abort_xfer(xfer, USBD_TIMEOUT); | | 1680 | uhci_abort_xfer(xfer, USBD_TIMEOUT); |
1680 | splx(s); | | 1681 | splx(s); |
1681 | } | | 1682 | } |
1682 | | | 1683 | |
1683 | /* | | 1684 | /* |
1684 | * Wait here until controller claims to have an interrupt. | | 1685 | * Wait here until controller claims to have an interrupt. |
1685 | * Then call uhci_intr and return. Use timeout to avoid waiting | | 1686 | * Then call uhci_intr and return. Use timeout to avoid waiting |
1686 | * too long. | | 1687 | * too long. |
1687 | * Only used during boot when interrupts are not enabled yet. | | 1688 | * Only used during boot when interrupts are not enabled yet. |
1688 | */ | | 1689 | */ |
1689 | void | | 1690 | void |
1690 | uhci_waitintr(uhci_softc_t *sc, usbd_xfer_handle xfer) | | 1691 | uhci_waitintr(uhci_softc_t *sc, usbd_xfer_handle xfer) |
1691 | { | | 1692 | { |
1692 | int timo = xfer->timeout; | | 1693 | int timo = xfer->timeout; |
1693 | uhci_intr_info_t *ii; | | 1694 | uhci_intr_info_t *ii; |
1694 | | | 1695 | |
1695 | DPRINTFN(10,("uhci_waitintr: timeout = %dms\n", timo)); | | 1696 | DPRINTFN(10,("uhci_waitintr: timeout = %dms\n", timo)); |
1696 | | | 1697 | |
1697 | xfer->status = USBD_IN_PROGRESS; | | 1698 | xfer->status = USBD_IN_PROGRESS; |
1698 | for (; timo >= 0; timo--) { | | 1699 | for (; timo >= 0; timo--) { |
1699 | usb_delay_ms(&sc->sc_bus, 1); | | 1700 | usb_delay_ms(&sc->sc_bus, 1); |
1700 | DPRINTFN(20,("uhci_waitintr: 0x%04x\n", UREAD2(sc, UHCI_STS))); | | 1701 | DPRINTFN(20,("uhci_waitintr: 0x%04x\n", UREAD2(sc, UHCI_STS))); |
1701 | if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) { | | 1702 | if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) { |
1702 | uhci_intr1(sc); | | 1703 | uhci_intr1(sc); |
1703 | if (xfer->status != USBD_IN_PROGRESS) | | 1704 | if (xfer->status != USBD_IN_PROGRESS) |
1704 | return; | | 1705 | return; |
1705 | } | | 1706 | } |
1706 | } | | 1707 | } |
1707 | | | 1708 | |
1708 | /* Timeout */ | | 1709 | /* Timeout */ |
1709 | DPRINTF(("uhci_waitintr: timeout\n")); | | 1710 | DPRINTF(("uhci_waitintr: timeout\n")); |
1710 | for (ii = LIST_FIRST(&sc->sc_intrhead); | | 1711 | for (ii = LIST_FIRST(&sc->sc_intrhead); |
1711 | ii != NULL && ii->xfer != xfer; | | 1712 | ii != NULL && ii->xfer != xfer; |
1712 | ii = LIST_NEXT(ii, list)) | | 1713 | ii = LIST_NEXT(ii, list)) |
1713 | ; | | 1714 | ; |
1714 | #ifdef DIAGNOSTIC | | 1715 | #ifdef DIAGNOSTIC |
1715 | if (ii == NULL) | | 1716 | if (ii == NULL) |
1716 | panic("uhci_waitintr: lost intr_info"); | | 1717 | panic("uhci_waitintr: lost intr_info"); |
1717 | #endif | | 1718 | #endif |
1718 | uhci_idone(ii); | | 1719 | uhci_idone(ii); |
1719 | } | | 1720 | } |
1720 | | | 1721 | |
1721 | void | | 1722 | void |
1722 | uhci_poll(struct usbd_bus *bus) | | 1723 | uhci_poll(struct usbd_bus *bus) |
1723 | { | | 1724 | { |
1724 | uhci_softc_t *sc = bus->hci_private; | | 1725 | uhci_softc_t *sc = bus->hci_private; |
1725 | | | 1726 | |
1726 | if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) | | 1727 | if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) |
1727 | uhci_intr1(sc); | | 1728 | uhci_intr1(sc); |
1728 | } | | 1729 | } |
1729 | | | 1730 | |
1730 | void | | 1731 | void |
1731 | uhci_reset(uhci_softc_t *sc) | | 1732 | uhci_reset(uhci_softc_t *sc) |
1732 | { | | 1733 | { |
1733 | int n; | | 1734 | int n; |
1734 | | | 1735 | |
1735 | UHCICMD(sc, UHCI_CMD_HCRESET); | | 1736 | UHCICMD(sc, UHCI_CMD_HCRESET); |
1736 | /* The reset bit goes low when the controller is done. */ | | 1737 | /* The reset bit goes low when the controller is done. */ |
1737 | for (n = 0; n < UHCI_RESET_TIMEOUT && | | 1738 | for (n = 0; n < UHCI_RESET_TIMEOUT && |
1738 | (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++) | | 1739 | (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++) |
1739 | usb_delay_ms(&sc->sc_bus, 1); | | 1740 | usb_delay_ms(&sc->sc_bus, 1); |
1740 | if (n >= UHCI_RESET_TIMEOUT) | | 1741 | if (n >= UHCI_RESET_TIMEOUT) |
1741 | printf("%s: controller did not reset\n", | | 1742 | printf("%s: controller did not reset\n", |
1742 | device_xname(sc->sc_dev)); | | 1743 | device_xname(sc->sc_dev)); |
1743 | } | | 1744 | } |
1744 | | | 1745 | |
1745 | usbd_status | | 1746 | usbd_status |
1746 | uhci_run(uhci_softc_t *sc, int run) | | 1747 | uhci_run(uhci_softc_t *sc, int run) |
1747 | { | | 1748 | { |
1748 | int s, n, running; | | 1749 | int s, n, running; |
1749 | u_int16_t cmd; | | 1750 | u_int16_t cmd; |
1750 | | | 1751 | |
1751 | run = run != 0; | | 1752 | run = run != 0; |
1752 | s = splhardusb(); | | 1753 | s = splhardusb(); |
1753 | DPRINTF(("uhci_run: setting run=%d\n", run)); | | 1754 | DPRINTF(("uhci_run: setting run=%d\n", run)); |
1754 | cmd = UREAD2(sc, UHCI_CMD); | | 1755 | cmd = UREAD2(sc, UHCI_CMD); |
1755 | if (run) | | 1756 | if (run) |
1756 | cmd |= UHCI_CMD_RS; | | 1757 | cmd |= UHCI_CMD_RS; |
1757 | else | | 1758 | else |
1758 | cmd &= ~UHCI_CMD_RS; | | 1759 | cmd &= ~UHCI_CMD_RS; |
1759 | UHCICMD(sc, cmd); | | 1760 | UHCICMD(sc, cmd); |
1760 | for(n = 0; n < 10; n++) { | | 1761 | for(n = 0; n < 10; n++) { |
1761 | running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH); | | 1762 | running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH); |
1762 | /* return when we've entered the state we want */ | | 1763 | /* return when we've entered the state we want */ |
1763 | if (run == running) { | | 1764 | if (run == running) { |
1764 | splx(s); | | 1765 | splx(s); |
1765 | DPRINTF(("uhci_run: done cmd=0x%x sts=0x%x\n", | | 1766 | DPRINTF(("uhci_run: done cmd=0x%x sts=0x%x\n", |
1766 | UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS))); | | 1767 | UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS))); |
1767 | return (USBD_NORMAL_COMPLETION); | | 1768 | return (USBD_NORMAL_COMPLETION); |
1768 | } | | 1769 | } |
1769 | usb_delay_ms(&sc->sc_bus, 1); | | 1770 | usb_delay_ms(&sc->sc_bus, 1); |
1770 | } | | 1771 | } |
1771 | splx(s); | | 1772 | splx(s); |
1772 | printf("%s: cannot %s\n", device_xname(sc->sc_dev), | | 1773 | printf("%s: cannot %s\n", device_xname(sc->sc_dev), |
1773 | run ? "start" : "stop"); | | 1774 | run ? "start" : "stop"); |
1774 | return (USBD_IOERROR); | | 1775 | return (USBD_IOERROR); |
1775 | } | | 1776 | } |
1776 | | | 1777 | |
1777 | /* | | 1778 | /* |
1778 | * Memory management routines. | | 1779 | * Memory management routines. |
1779 | * uhci_alloc_std allocates TDs | | 1780 | * uhci_alloc_std allocates TDs |
1780 | * uhci_alloc_sqh allocates QHs | | 1781 | * uhci_alloc_sqh allocates QHs |
1781 | * These two routines do their own free list management, | | 1782 | * These two routines do their own free list management, |
1782 | * partly for speed, partly because allocating DMAable memory | | 1783 | * partly for speed, partly because allocating DMAable memory |
1783 | * has page size granularaity so much memory would be wasted if | | 1784 | * has page size granularaity so much memory would be wasted if |
1784 | * only one TD/QH (32 bytes) was placed in each allocated chunk. | | 1785 | * only one TD/QH (32 bytes) was placed in each allocated chunk. |
1785 | */ | | 1786 | */ |
1786 | | | 1787 | |
1787 | uhci_soft_td_t * | | 1788 | uhci_soft_td_t * |
1788 | uhci_alloc_std(uhci_softc_t *sc) | | 1789 | uhci_alloc_std(uhci_softc_t *sc) |
1789 | { | | 1790 | { |
1790 | uhci_soft_td_t *std; | | 1791 | uhci_soft_td_t *std; |
1791 | usbd_status err; | | 1792 | usbd_status err; |
1792 | int i, offs; | | 1793 | int i, offs; |
1793 | usb_dma_t dma; | | 1794 | usb_dma_t dma; |
1794 | | | 1795 | |
1795 | if (sc->sc_freetds == NULL) { | | 1796 | if (sc->sc_freetds == NULL) { |
1796 | DPRINTFN(2,("uhci_alloc_std: allocating chunk\n")); | | 1797 | DPRINTFN(2,("uhci_alloc_std: allocating chunk\n")); |
1797 | err = usb_allocmem(&sc->sc_bus, UHCI_STD_SIZE * UHCI_STD_CHUNK, | | 1798 | err = usb_allocmem(&sc->sc_bus, UHCI_STD_SIZE * UHCI_STD_CHUNK, |
1798 | UHCI_TD_ALIGN, &dma); | | 1799 | UHCI_TD_ALIGN, &dma); |
1799 | if (err) | | 1800 | if (err) |
1800 | return (0); | | 1801 | return (0); |
1801 | for(i = 0; i < UHCI_STD_CHUNK; i++) { | | 1802 | for(i = 0; i < UHCI_STD_CHUNK; i++) { |
1802 | offs = i * UHCI_STD_SIZE; | | 1803 | offs = i * UHCI_STD_SIZE; |
1803 | std = KERNADDR(&dma, offs); | | 1804 | std = KERNADDR(&dma, offs); |
1804 | std->physaddr = DMAADDR(&dma, offs); | | 1805 | std->physaddr = DMAADDR(&dma, offs); |
1805 | std->dma = dma; | | 1806 | std->dma = dma; |
1806 | std->offs = offs; | | 1807 | std->offs = offs; |
1807 | std->link.std = sc->sc_freetds; | | 1808 | std->link.std = sc->sc_freetds; |
1808 | sc->sc_freetds = std; | | 1809 | sc->sc_freetds = std; |
1809 | } | | 1810 | } |
1810 | } | | 1811 | } |
1811 | std = sc->sc_freetds; | | 1812 | std = sc->sc_freetds; |
1812 | sc->sc_freetds = std->link.std; | | 1813 | sc->sc_freetds = std->link.std; |
1813 | memset(&std->td, 0, sizeof(uhci_td_t)); | | 1814 | memset(&std->td, 0, sizeof(uhci_td_t)); |
1814 | return std; | | 1815 | return std; |
1815 | } | | 1816 | } |
1816 | | | 1817 | |
1817 | void | | 1818 | void |
1818 | uhci_free_std(uhci_softc_t *sc, uhci_soft_td_t *std) | | 1819 | uhci_free_std(uhci_softc_t *sc, uhci_soft_td_t *std) |
1819 | { | | 1820 | { |
1820 | #ifdef DIAGNOSTIC | | 1821 | #ifdef DIAGNOSTIC |
1821 | #define TD_IS_FREE 0x12345678 | | 1822 | #define TD_IS_FREE 0x12345678 |
1822 | if (le32toh(std->td.td_token) == TD_IS_FREE) { | | 1823 | if (le32toh(std->td.td_token) == TD_IS_FREE) { |
1823 | printf("uhci_free_std: freeing free TD %p\n", std); | | 1824 | printf("uhci_free_std: freeing free TD %p\n", std); |
1824 | return; | | 1825 | return; |
1825 | } | | 1826 | } |
1826 | std->td.td_token = htole32(TD_IS_FREE); | | 1827 | std->td.td_token = htole32(TD_IS_FREE); |
1827 | #endif | | 1828 | #endif |
1828 | std->link.std = sc->sc_freetds; | | 1829 | std->link.std = sc->sc_freetds; |
1829 | sc->sc_freetds = std; | | 1830 | sc->sc_freetds = std; |
1830 | } | | 1831 | } |
1831 | | | 1832 | |
1832 | uhci_soft_qh_t * | | 1833 | uhci_soft_qh_t * |
1833 | uhci_alloc_sqh(uhci_softc_t *sc) | | 1834 | uhci_alloc_sqh(uhci_softc_t *sc) |
1834 | { | | 1835 | { |
1835 | uhci_soft_qh_t *sqh; | | 1836 | uhci_soft_qh_t *sqh; |
1836 | usbd_status err; | | 1837 | usbd_status err; |
1837 | int i, offs; | | 1838 | int i, offs; |
1838 | usb_dma_t dma; | | 1839 | usb_dma_t dma; |
1839 | | | 1840 | |
1840 | if (sc->sc_freeqhs == NULL) { | | 1841 | if (sc->sc_freeqhs == NULL) { |
1841 | DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n")); | | 1842 | DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n")); |
1842 | err = usb_allocmem(&sc->sc_bus, UHCI_SQH_SIZE * UHCI_SQH_CHUNK, | | 1843 | err = usb_allocmem(&sc->sc_bus, UHCI_SQH_SIZE * UHCI_SQH_CHUNK, |
1843 | UHCI_QH_ALIGN, &dma); | | 1844 | UHCI_QH_ALIGN, &dma); |
1844 | if (err) | | 1845 | if (err) |
1845 | return (0); | | 1846 | return (0); |
1846 | for(i = 0; i < UHCI_SQH_CHUNK; i++) { | | 1847 | for(i = 0; i < UHCI_SQH_CHUNK; i++) { |
1847 | offs = i * UHCI_SQH_SIZE; | | 1848 | offs = i * UHCI_SQH_SIZE; |
1848 | sqh = KERNADDR(&dma, offs); | | 1849 | sqh = KERNADDR(&dma, offs); |
1849 | sqh->physaddr = DMAADDR(&dma, offs); | | 1850 | sqh->physaddr = DMAADDR(&dma, offs); |
1850 | sqh->dma = dma; | | 1851 | sqh->dma = dma; |
1851 | sqh->offs = offs; | | 1852 | sqh->offs = offs; |
1852 | sqh->hlink = sc->sc_freeqhs; | | 1853 | sqh->hlink = sc->sc_freeqhs; |
1853 | sc->sc_freeqhs = sqh; | | 1854 | sc->sc_freeqhs = sqh; |
1854 | } | | 1855 | } |
1855 | } | | 1856 | } |
1856 | sqh = sc->sc_freeqhs; | | 1857 | sqh = sc->sc_freeqhs; |
1857 | sc->sc_freeqhs = sqh->hlink; | | 1858 | sc->sc_freeqhs = sqh->hlink; |
1858 | memset(&sqh->qh, 0, sizeof(uhci_qh_t)); | | 1859 | memset(&sqh->qh, 0, sizeof(uhci_qh_t)); |
1859 | return (sqh); | | 1860 | return (sqh); |
1860 | } | | 1861 | } |
1861 | | | 1862 | |
1862 | void | | 1863 | void |
1863 | uhci_free_sqh(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | | 1864 | uhci_free_sqh(uhci_softc_t *sc, uhci_soft_qh_t *sqh) |
1864 | { | | 1865 | { |
1865 | sqh->hlink = sc->sc_freeqhs; | | 1866 | sqh->hlink = sc->sc_freeqhs; |
1866 | sc->sc_freeqhs = sqh; | | 1867 | sc->sc_freeqhs = sqh; |
1867 | } | | 1868 | } |
1868 | | | 1869 | |
1869 | void | | 1870 | void |
1870 | uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std, | | 1871 | uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std, |
1871 | uhci_soft_td_t *stdend) | | 1872 | uhci_soft_td_t *stdend) |
1872 | { | | 1873 | { |
1873 | uhci_soft_td_t *p; | | 1874 | uhci_soft_td_t *p; |
1874 | | | 1875 | |
1875 | /* | | 1876 | /* |
1876 | * to avoid race condition with the controller which may be looking | | 1877 | * to avoid race condition with the controller which may be looking |
1877 | * at this chain, we need to first invalidate all links, and | | 1878 | * at this chain, we need to first invalidate all links, and |
1878 | * then wait for the controller to move to another queue | | 1879 | * then wait for the controller to move to another queue |
1879 | */ | | 1880 | */ |
1880 | for (p = std; p != stdend; p = p->link.std) { | | 1881 | for (p = std; p != stdend; p = p->link.std) { |
1881 | usb_syncmem(&p->dma, | | 1882 | usb_syncmem(&p->dma, |
1882 | p->offs + offsetof(uhci_td_t, td_link), | | 1883 | p->offs + offsetof(uhci_td_t, td_link), |
1883 | sizeof(p->td.td_link), | | 1884 | sizeof(p->td.td_link), |
1884 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1885 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1885 | if ((p->td.td_link & UHCI_PTR_T) == 0) { | | 1886 | if ((p->td.td_link & UHCI_PTR_T) == 0) { |
1886 | p->td.td_link = UHCI_PTR_T; | | 1887 | p->td.td_link = UHCI_PTR_T; |
1887 | usb_syncmem(&p->dma, | | 1888 | usb_syncmem(&p->dma, |
1888 | p->offs + offsetof(uhci_td_t, td_link), | | 1889 | p->offs + offsetof(uhci_td_t, td_link), |
1889 | sizeof(p->td.td_link), | | 1890 | sizeof(p->td.td_link), |
1890 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 1891 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1891 | } | | 1892 | } |
1892 | } | | 1893 | } |
1893 | delay(UHCI_QH_REMOVE_DELAY); | | 1894 | delay(UHCI_QH_REMOVE_DELAY); |
1894 | | | 1895 | |
1895 | for (; std != stdend; std = p) { | | 1896 | for (; std != stdend; std = p) { |
1896 | p = std->link.std; | | 1897 | p = std->link.std; |
1897 | uhci_free_std(sc, std); | | 1898 | uhci_free_std(sc, std); |
1898 | } | | 1899 | } |
1899 | } | | 1900 | } |
1900 | | | 1901 | |
1901 | usbd_status | | 1902 | usbd_status |
1902 | uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len, | | 1903 | uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len, |
1903 | int rd, u_int16_t flags, usb_dma_t *dma, | | 1904 | int rd, u_int16_t flags, usb_dma_t *dma, |
1904 | uhci_soft_td_t **sp, uhci_soft_td_t **ep) | | 1905 | uhci_soft_td_t **sp, uhci_soft_td_t **ep) |
1905 | { | | 1906 | { |
1906 | uhci_soft_td_t *p, *lastp; | | 1907 | uhci_soft_td_t *p, *lastp; |
1907 | uhci_physaddr_t lastlink; | | 1908 | uhci_physaddr_t lastlink; |
1908 | int i, ntd, l, tog, maxp; | | 1909 | int i, ntd, l, tog, maxp; |
1909 | u_int32_t status; | | 1910 | u_int32_t status; |
1910 | int addr = upipe->pipe.device->address; | | 1911 | int addr = upipe->pipe.device->address; |
1911 | int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; | | 1912 | int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; |
1912 | | | 1913 | |
1913 | DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d speed=%d " | | 1914 | DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d speed=%d " |
1914 | "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len, | | 1915 | "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len, |
1915 | upipe->pipe.device->speed, flags)); | | 1916 | upipe->pipe.device->speed, flags)); |
1916 | maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize); | | 1917 | maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize); |
1917 | if (maxp == 0) { | | 1918 | if (maxp == 0) { |
1918 | printf("uhci_alloc_std_chain: maxp=0\n"); | | 1919 | printf("uhci_alloc_std_chain: maxp=0\n"); |
1919 | return (USBD_INVAL); | | 1920 | return (USBD_INVAL); |
1920 | } | | 1921 | } |
1921 | ntd = (len + maxp - 1) / maxp; | | 1922 | ntd = (len + maxp - 1) / maxp; |
1922 | if ((flags & USBD_FORCE_SHORT_XFER) && len % maxp == 0) | | 1923 | if ((flags & USBD_FORCE_SHORT_XFER) && len % maxp == 0) |
1923 | ntd++; | | 1924 | ntd++; |
1924 | DPRINTFN(10, ("uhci_alloc_std_chain: maxp=%d ntd=%d\n", maxp, ntd)); | | 1925 | DPRINTFN(10, ("uhci_alloc_std_chain: maxp=%d ntd=%d\n", maxp, ntd)); |
1925 | if (ntd == 0) { | | 1926 | if (ntd == 0) { |
1926 | *sp = *ep = 0; | | 1927 | *sp = *ep = 0; |
1927 | DPRINTFN(-1,("uhci_alloc_std_chain: ntd=0\n")); | | 1928 | DPRINTFN(-1,("uhci_alloc_std_chain: ntd=0\n")); |
1928 | return (USBD_NORMAL_COMPLETION); | | 1929 | return (USBD_NORMAL_COMPLETION); |
1929 | } | | 1930 | } |
1930 | tog = upipe->nexttoggle; | | 1931 | tog = upipe->nexttoggle; |
1931 | if (ntd % 2 == 0) | | 1932 | if (ntd % 2 == 0) |
1932 | tog ^= 1; | | 1933 | tog ^= 1; |
1933 | upipe->nexttoggle = tog ^ 1; | | 1934 | upipe->nexttoggle = tog ^ 1; |
1934 | lastp = NULL; | | 1935 | lastp = NULL; |
1935 | lastlink = UHCI_PTR_T; | | 1936 | lastlink = UHCI_PTR_T; |
1936 | ntd--; | | 1937 | ntd--; |
1937 | status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE); | | 1938 | status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE); |
1938 | if (upipe->pipe.device->speed == USB_SPEED_LOW) | | 1939 | if (upipe->pipe.device->speed == USB_SPEED_LOW) |
1939 | status |= UHCI_TD_LS; | | 1940 | status |= UHCI_TD_LS; |
1940 | if (flags & USBD_SHORT_XFER_OK) | | 1941 | if (flags & USBD_SHORT_XFER_OK) |
1941 | status |= UHCI_TD_SPD; | | 1942 | status |= UHCI_TD_SPD; |
1942 | usb_syncmem(dma, 0, len, | | 1943 | usb_syncmem(dma, 0, len, |
1943 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | | 1944 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); |
1944 | for (i = ntd; i >= 0; i--) { | | 1945 | for (i = ntd; i >= 0; i--) { |
1945 | p = uhci_alloc_std(sc); | | 1946 | p = uhci_alloc_std(sc); |
1946 | if (p == NULL) { | | 1947 | if (p == NULL) { |
1947 | KASSERT(lastp != NULL); | | 1948 | KASSERT(lastp != NULL); |
1948 | uhci_free_std_chain(sc, lastp, NULL); | | 1949 | uhci_free_std_chain(sc, lastp, NULL); |
1949 | return (USBD_NOMEM); | | 1950 | return (USBD_NOMEM); |
1950 | } | | 1951 | } |
1951 | p->link.std = lastp; | | 1952 | p->link.std = lastp; |
1952 | p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD); | | 1953 | p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD); |
1953 | lastp = p; | | 1954 | lastp = p; |
1954 | lastlink = p->physaddr; | | 1955 | lastlink = p->physaddr; |
1955 | p->td.td_status = htole32(status); | | 1956 | p->td.td_status = htole32(status); |
1956 | if (i == ntd) { | | 1957 | if (i == ntd) { |
1957 | /* last TD */ | | 1958 | /* last TD */ |
1958 | l = len % maxp; | | 1959 | l = len % maxp; |
1959 | if (l == 0 && !(flags & USBD_FORCE_SHORT_XFER)) | | 1960 | if (l == 0 && !(flags & USBD_FORCE_SHORT_XFER)) |
1960 | l = maxp; | | 1961 | l = maxp; |
1961 | *ep = p; | | 1962 | *ep = p; |
1962 | } else | | 1963 | } else |
1963 | l = maxp; | | 1964 | l = maxp; |
1964 | p->td.td_token = | | 1965 | p->td.td_token = |
1965 | htole32(rd ? UHCI_TD_IN (l, endpt, addr, tog) : | | 1966 | htole32(rd ? UHCI_TD_IN (l, endpt, addr, tog) : |
1966 | UHCI_TD_OUT(l, endpt, addr, tog)); | | 1967 | UHCI_TD_OUT(l, endpt, addr, tog)); |
1967 | p->td.td_buffer = htole32(DMAADDR(dma, i * maxp)); | | 1968 | p->td.td_buffer = htole32(DMAADDR(dma, i * maxp)); |
1968 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), | | 1969 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), |
1969 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 1970 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1970 | tog ^= 1; | | 1971 | tog ^= 1; |
1971 | } | | 1972 | } |
1972 | *sp = lastp; | | 1973 | *sp = lastp; |
1973 | DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n", | | 1974 | DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n", |
1974 | upipe->nexttoggle)); | | 1975 | upipe->nexttoggle)); |
1975 | return (USBD_NORMAL_COMPLETION); | | 1976 | return (USBD_NORMAL_COMPLETION); |
1976 | } | | 1977 | } |
1977 | | | 1978 | |
1978 | void | | 1979 | void |
1979 | uhci_device_clear_toggle(usbd_pipe_handle pipe) | | 1980 | uhci_device_clear_toggle(usbd_pipe_handle pipe) |
1980 | { | | 1981 | { |
1981 | struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; | | 1982 | struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; |
1982 | upipe->nexttoggle = 0; | | 1983 | upipe->nexttoggle = 0; |
1983 | } | | 1984 | } |
1984 | | | 1985 | |
1985 | void | | 1986 | void |
1986 | uhci_noop(usbd_pipe_handle pipe) | | 1987 | uhci_noop(usbd_pipe_handle pipe) |
1987 | { | | 1988 | { |
1988 | } | | 1989 | } |
1989 | | | 1990 | |
1990 | usbd_status | | 1991 | usbd_status |
1991 | uhci_device_bulk_transfer(usbd_xfer_handle xfer) | | 1992 | uhci_device_bulk_transfer(usbd_xfer_handle xfer) |
1992 | { | | 1993 | { |
1993 | usbd_status err; | | 1994 | usbd_status err; |
1994 | | | 1995 | |
1995 | /* Insert last in queue. */ | | 1996 | /* Insert last in queue. */ |
1996 | err = usb_insert_transfer(xfer); | | 1997 | err = usb_insert_transfer(xfer); |
1997 | if (err) | | 1998 | if (err) |
1998 | return (err); | | 1999 | return (err); |
1999 | | | 2000 | |
2000 | /* | | 2001 | /* |
2001 | * Pipe isn't running (otherwise err would be USBD_INPROG), | | 2002 | * Pipe isn't running (otherwise err would be USBD_INPROG), |
2002 | * so start it first. | | 2003 | * so start it first. |
2003 | */ | | 2004 | */ |
2004 | return (uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | | 2005 | return (uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); |
2005 | } | | 2006 | } |
2006 | | | 2007 | |
2007 | usbd_status | | 2008 | usbd_status |
2008 | uhci_device_bulk_start(usbd_xfer_handle xfer) | | 2009 | uhci_device_bulk_start(usbd_xfer_handle xfer) |
2009 | { | | 2010 | { |
2010 | struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; | | 2011 | struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; |
2011 | usbd_device_handle dev = upipe->pipe.device; | | 2012 | usbd_device_handle dev = upipe->pipe.device; |
2012 | uhci_softc_t *sc = dev->bus->hci_private; | | 2013 | uhci_softc_t *sc = dev->bus->hci_private; |
2013 | uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; | | 2014 | uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; |
2014 | uhci_soft_td_t *data, *dataend; | | 2015 | uhci_soft_td_t *data, *dataend; |
2015 | uhci_soft_qh_t *sqh; | | 2016 | uhci_soft_qh_t *sqh; |
2016 | usbd_status err; | | 2017 | usbd_status err; |
2017 | int len, isread, endpt; | | 2018 | int len, isread, endpt; |
2018 | int s; | | 2019 | int s; |
2019 | | | 2020 | |
2020 | DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%d flags=%d ii=%p\n", | | 2021 | DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%d flags=%d ii=%p\n", |
2021 | xfer, xfer->length, xfer->flags, ii)); | | 2022 | xfer, xfer->length, xfer->flags, ii)); |
2022 | | | 2023 | |
2023 | if (sc->sc_dying) | | 2024 | if (sc->sc_dying) |
2024 | return (USBD_IOERROR); | | 2025 | return (USBD_IOERROR); |
2025 | | | 2026 | |
2026 | #ifdef DIAGNOSTIC | | 2027 | #ifdef DIAGNOSTIC |
2027 | if (xfer->rqflags & URQ_REQUEST) | | 2028 | if (xfer->rqflags & URQ_REQUEST) |
2028 | panic("uhci_device_bulk_transfer: a request"); | | 2029 | panic("uhci_device_bulk_transfer: a request"); |
2029 | #endif | | 2030 | #endif |
2030 | | | 2031 | |
2031 | len = xfer->length; | | 2032 | len = xfer->length; |
2032 | endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; | | 2033 | endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; |
2033 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 2034 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
2034 | sqh = upipe->u.bulk.sqh; | | 2035 | sqh = upipe->u.bulk.sqh; |
2035 | | | 2036 | |
2036 | upipe->u.bulk.isread = isread; | | 2037 | upipe->u.bulk.isread = isread; |
2037 | upipe->u.bulk.length = len; | | 2038 | upipe->u.bulk.length = len; |
2038 | | | 2039 | |
2039 | err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags, | | 2040 | err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags, |
2040 | &xfer->dmabuf, &data, &dataend); | | 2041 | &xfer->dmabuf, &data, &dataend); |
2041 | if (err) | | 2042 | if (err) |
2042 | return (err); | | 2043 | return (err); |