- convert usbd_bus_methods{} and usbd_pipe_methods{} to use c99 struct initialisers - move the locks from the pipe to the bus, since we'll need access to them from bus-level ops - remove dead-for-years SPLUSBCHECK and replaced it with asserts that the thread lock is held - begin to document the locking scheme - convert usbd_*lock_pipe() into real function-like macrosdiff -r1.181.6.3 -r1.181.6.4 src/sys/dev/usb/ehci.c
(mrg)
--- src/sys/dev/usb/ehci.c 2011/12/06 02:10:01 1.181.6.3
+++ src/sys/dev/usb/ehci.c 2011/12/08 02:51:07 1.181.6.4
@@ -1,4242 +1,4245 @@ | @@ -1,4242 +1,4245 @@ | |||
1 | /* $NetBSD: ehci.c,v 1.181.6.3 2011/12/06 02:10:01 mrg Exp $ */ | 1 | /* $NetBSD: ehci.c,v 1.181.6.4 2011/12/08 02:51:07 mrg Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2004-2011 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2004-2011 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net), Charles M. Hannum, | 8 | * by Lennart Augustsson (lennart@augustsson.net), Charles M. Hannum, | |
9 | * Jeremy Morse (jeremy.morse@gmail.com), and Jared D. McNeill | 9 | * Jeremy Morse (jeremy.morse@gmail.com), and Jared D. McNeill | |
10 | * (jmcneill@invisible.ca). | 10 | * (jmcneill@invisible.ca). | |
11 | * | 11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | 12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | 13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | 14 | * are met: | |
15 | * 1. Redistributions of source code must retain the above copyright | 15 | * 1. Redistributions of source code must retain the above copyright | |
16 | * notice, this list of conditions and the following disclaimer. | 16 | * notice, this list of conditions and the following disclaimer. | |
17 | * 2. Redistributions in binary form must reproduce the above copyright | 17 | * 2. Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | 18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | 19 | * documentation and/or other materials provided with the distribution. | |
20 | * | 20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | * POSSIBILITY OF SUCH DAMAGE. | 31 | * POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | 32 | */ | |
33 | 33 | |||
34 | /* | 34 | /* | |
35 | * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. | 35 | * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. | |
36 | * | 36 | * | |
37 | * The EHCI 1.0 spec can be found at | 37 | * The EHCI 1.0 spec can be found at | |
38 | * http://www.intel.com/technology/usb/spec.htm | 38 | * http://www.intel.com/technology/usb/spec.htm | |
39 | * and the USB 2.0 spec at | 39 | * and the USB 2.0 spec at | |
40 | * http://www.usb.org/developers/docs/ | 40 | * http://www.usb.org/developers/docs/ | |
41 | * | 41 | * | |
42 | */ | 42 | */ | |
43 | 43 | |||
44 | /* | 44 | /* | |
45 | * TODO: | 45 | * TODO: | |
46 | * 1) hold off explorations by companion controllers until ehci has started. | 46 | * 1) hold off explorations by companion controllers until ehci has started. | |
47 | * | 47 | * | |
48 | * 2) The hub driver needs to handle and schedule the transaction translator, | 48 | * 2) The hub driver needs to handle and schedule the transaction translator, | |
49 | * to assign place in frame where different devices get to go. See chapter | 49 | * to assign place in frame where different devices get to go. See chapter | |
50 | * on hubs in USB 2.0 for details. | 50 | * on hubs in USB 2.0 for details. | |
51 | * | 51 | * | |
52 | * 3) Command failures are not recovered correctly. | 52 | * 3) Command failures are not recovered correctly. | |
53 | */ | 53 | */ | |
54 | 54 | |||
55 | #include <sys/cdefs.h> | 55 | #include <sys/cdefs.h> | |
56 | __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.181.6.3 2011/12/06 02:10:01 mrg Exp $"); | 56 | __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.181.6.4 2011/12/08 02:51:07 mrg Exp $"); | |
57 | 57 | |||
58 | #include "ohci.h" | 58 | #include "ohci.h" | |
59 | #include "uhci.h" | 59 | #include "uhci.h" | |
60 | #include "opt_usb.h" | 60 | #include "opt_usb.h" | |
61 | 61 | |||
62 | #include <sys/param.h> | 62 | #include <sys/param.h> | |
63 | #include <sys/systm.h> | 63 | #include <sys/systm.h> | |
64 | #include <sys/kernel.h> | 64 | #include <sys/kernel.h> | |
65 | #include <sys/kmem.h> | 65 | #include <sys/kmem.h> | |
66 | #include <sys/device.h> | 66 | #include <sys/device.h> | |
67 | #include <sys/select.h> | 67 | #include <sys/select.h> | |
68 | #include <sys/proc.h> | 68 | #include <sys/proc.h> | |
69 | #include <sys/queue.h> | 69 | #include <sys/queue.h> | |
70 | #include <sys/mutex.h> | 70 | #include <sys/mutex.h> | |
71 | #include <sys/bus.h> | 71 | #include <sys/bus.h> | |
72 | 72 | |||
73 | #include <machine/endian.h> | 73 | #include <machine/endian.h> | |
74 | 74 | |||
75 | #include <dev/usb/usb.h> | 75 | #include <dev/usb/usb.h> | |
76 | #include <dev/usb/usbdi.h> | 76 | #include <dev/usb/usbdi.h> | |
77 | #include <dev/usb/usbdivar.h> | 77 | #include <dev/usb/usbdivar.h> | |
78 | #include <dev/usb/usb_mem.h> | 78 | #include <dev/usb/usb_mem.h> | |
79 | #include <dev/usb/usb_quirks.h> | 79 | #include <dev/usb/usb_quirks.h> | |
80 | 80 | |||
81 | #include <dev/usb/ehcireg.h> | 81 | #include <dev/usb/ehcireg.h> | |
82 | #include <dev/usb/ehcivar.h> | 82 | #include <dev/usb/ehcivar.h> | |
83 | #include <dev/usb/usbroothub_subr.h> | 83 | #include <dev/usb/usbroothub_subr.h> | |
84 | 84 | |||
85 | #ifdef EHCI_DEBUG | 85 | #ifdef EHCI_DEBUG | |
86 | #include <sys/kprintf.h> | 86 | #include <sys/kprintf.h> | |
87 | static void | 87 | static void | |
88 | ehciprintf(const char *fmt, ...) | 88 | ehciprintf(const char *fmt, ...) | |
89 | { | 89 | { | |
90 | va_list ap; | 90 | va_list ap; | |
91 | 91 | |||
92 | va_start(ap, fmt); | 92 | va_start(ap, fmt); | |
93 | kprintf(fmt, TOLOG|TOCONS, NULL, NULL, ap); | 93 | kprintf(fmt, TOLOG|TOCONS, NULL, NULL, ap); | |
94 | va_end(ap); | 94 | va_end(ap); | |
95 | } | 95 | } | |
96 | 96 | |||
97 | #define DPRINTF(x) do { if (ehcidebug) ehciprintf x; } while(0) | 97 | #define DPRINTF(x) do { if (ehcidebug) ehciprintf x; } while(0) | |
98 | #define DPRINTFN(n,x) do { if (ehcidebug>(n)) ehciprintf x; } while (0) | 98 | #define DPRINTFN(n,x) do { if (ehcidebug>(n)) ehciprintf x; } while (0) | |
99 | int ehcidebug = 0; | 99 | int ehcidebug = 0; | |
100 | #else | 100 | #else | |
101 | #define DPRINTF(x) | 101 | #define DPRINTF(x) | |
102 | #define DPRINTFN(n,x) | 102 | #define DPRINTFN(n,x) | |
103 | #endif | 103 | #endif | |
104 | 104 | |||
105 | struct ehci_pipe { | 105 | struct ehci_pipe { | |
106 | struct usbd_pipe pipe; | 106 | struct usbd_pipe pipe; | |
107 | int nexttoggle; | 107 | int nexttoggle; | |
108 | 108 | |||
109 | ehci_soft_qh_t *sqh; | 109 | ehci_soft_qh_t *sqh; | |
110 | union { | 110 | union { | |
111 | ehci_soft_qtd_t *qtd; | 111 | ehci_soft_qtd_t *qtd; | |
112 | /* ehci_soft_itd_t *itd; */ | 112 | /* ehci_soft_itd_t *itd; */ | |
113 | } tail; | 113 | } tail; | |
114 | union { | 114 | union { | |
115 | /* Control pipe */ | 115 | /* Control pipe */ | |
116 | struct { | 116 | struct { | |
117 | usb_dma_t reqdma; | 117 | usb_dma_t reqdma; | |
118 | u_int length; | 118 | u_int length; | |
119 | } ctl; | 119 | } ctl; | |
120 | /* Interrupt pipe */ | 120 | /* Interrupt pipe */ | |
121 | struct { | 121 | struct { | |
122 | u_int length; | 122 | u_int length; | |
123 | } intr; | 123 | } intr; | |
124 | /* Bulk pipe */ | 124 | /* Bulk pipe */ | |
125 | struct { | 125 | struct { | |
126 | u_int length; | 126 | u_int length; | |
127 | } bulk; | 127 | } bulk; | |
128 | /* Iso pipe */ | 128 | /* Iso pipe */ | |
129 | struct { | 129 | struct { | |
130 | u_int next_frame; | 130 | u_int next_frame; | |
131 | u_int cur_xfers; | 131 | u_int cur_xfers; | |
132 | } isoc; | 132 | } isoc; | |
133 | } u; | 133 | } u; | |
134 | }; | 134 | }; | |
135 | 135 | |||
136 | Static usbd_status ehci_open(usbd_pipe_handle); | 136 | Static usbd_status ehci_open(usbd_pipe_handle); | |
137 | Static void ehci_poll(struct usbd_bus *); | 137 | Static void ehci_poll(struct usbd_bus *); | |
138 | Static void ehci_softintr(void *); | 138 | Static void ehci_softintr(void *); | |
139 | Static int ehci_intr1(ehci_softc_t *); | 139 | Static int ehci_intr1(ehci_softc_t *); | |
140 | Static void ehci_waitintr(ehci_softc_t *, usbd_xfer_handle); | 140 | Static void ehci_waitintr(ehci_softc_t *, usbd_xfer_handle); | |
141 | Static void ehci_check_intr(ehci_softc_t *, struct ehci_xfer *); | 141 | Static void ehci_check_intr(ehci_softc_t *, struct ehci_xfer *); | |
142 | Static void ehci_check_qh_intr(ehci_softc_t *, struct ehci_xfer *); | 142 | Static void ehci_check_qh_intr(ehci_softc_t *, struct ehci_xfer *); | |
143 | Static void ehci_check_itd_intr(ehci_softc_t *, struct ehci_xfer *); | 143 | Static void ehci_check_itd_intr(ehci_softc_t *, struct ehci_xfer *); | |
144 | Static void ehci_idone(struct ehci_xfer *); | 144 | Static void ehci_idone(struct ehci_xfer *); | |
145 | Static void ehci_timeout(void *); | 145 | Static void ehci_timeout(void *); | |
146 | Static void ehci_timeout_task(void *); | 146 | Static void ehci_timeout_task(void *); | |
147 | Static void ehci_intrlist_timeout(void *); | 147 | Static void ehci_intrlist_timeout(void *); | |
148 | Static void ehci_doorbell(void *); | 148 | Static void ehci_doorbell(void *); | |
149 | Static void ehci_pcd(void *); | 149 | Static void ehci_pcd(void *); | |
150 | 150 | |||
151 | Static usbd_status ehci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); | 151 | Static usbd_status ehci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); | |
152 | Static void ehci_freem(struct usbd_bus *, usb_dma_t *); | 152 | Static void ehci_freem(struct usbd_bus *, usb_dma_t *); | |
153 | 153 | |||
154 | Static usbd_xfer_handle ehci_allocx(struct usbd_bus *); | 154 | Static usbd_xfer_handle ehci_allocx(struct usbd_bus *); | |
155 | Static void ehci_freex(struct usbd_bus *, usbd_xfer_handle); | 155 | Static void ehci_freex(struct usbd_bus *, usbd_xfer_handle); | |
156 | Static void ehci_get_locks(struct usbd_bus *, kmutex_t **, | 156 | Static void ehci_get_locks(struct usbd_bus *, kmutex_t **, | |
157 | kmutex_t **); | 157 | kmutex_t **); | |
158 | 158 | |||
159 | Static usbd_status ehci_root_ctrl_transfer(usbd_xfer_handle); | 159 | Static usbd_status ehci_root_ctrl_transfer(usbd_xfer_handle); | |
160 | Static usbd_status ehci_root_ctrl_start(usbd_xfer_handle); | 160 | Static usbd_status ehci_root_ctrl_start(usbd_xfer_handle); | |
161 | Static void ehci_root_ctrl_abort(usbd_xfer_handle); | 161 | Static void ehci_root_ctrl_abort(usbd_xfer_handle); | |
162 | Static void ehci_root_ctrl_close(usbd_pipe_handle); | 162 | Static void ehci_root_ctrl_close(usbd_pipe_handle); | |
163 | Static void ehci_root_ctrl_done(usbd_xfer_handle); | 163 | Static void ehci_root_ctrl_done(usbd_xfer_handle); | |
164 | 164 | |||
165 | Static usbd_status ehci_root_intr_transfer(usbd_xfer_handle); | 165 | Static usbd_status ehci_root_intr_transfer(usbd_xfer_handle); | |
166 | Static usbd_status ehci_root_intr_start(usbd_xfer_handle); | 166 | Static usbd_status ehci_root_intr_start(usbd_xfer_handle); | |
167 | Static void ehci_root_intr_abort(usbd_xfer_handle); | 167 | Static void ehci_root_intr_abort(usbd_xfer_handle); | |
168 | Static void ehci_root_intr_close(usbd_pipe_handle); | 168 | Static void ehci_root_intr_close(usbd_pipe_handle); | |
169 | Static void ehci_root_intr_done(usbd_xfer_handle); | 169 | Static void ehci_root_intr_done(usbd_xfer_handle); | |
170 | 170 | |||
171 | Static usbd_status ehci_device_ctrl_transfer(usbd_xfer_handle); | 171 | Static usbd_status ehci_device_ctrl_transfer(usbd_xfer_handle); | |
172 | Static usbd_status ehci_device_ctrl_start(usbd_xfer_handle); | 172 | Static usbd_status ehci_device_ctrl_start(usbd_xfer_handle); | |
173 | Static void ehci_device_ctrl_abort(usbd_xfer_handle); | 173 | Static void ehci_device_ctrl_abort(usbd_xfer_handle); | |
174 | Static void ehci_device_ctrl_close(usbd_pipe_handle); | 174 | Static void ehci_device_ctrl_close(usbd_pipe_handle); | |
175 | Static void ehci_device_ctrl_done(usbd_xfer_handle); | 175 | Static void ehci_device_ctrl_done(usbd_xfer_handle); | |
176 | 176 | |||
177 | Static usbd_status ehci_device_bulk_transfer(usbd_xfer_handle); | 177 | Static usbd_status ehci_device_bulk_transfer(usbd_xfer_handle); | |
178 | Static usbd_status ehci_device_bulk_start(usbd_xfer_handle); | 178 | Static usbd_status ehci_device_bulk_start(usbd_xfer_handle); | |
179 | Static void ehci_device_bulk_abort(usbd_xfer_handle); | 179 | Static void ehci_device_bulk_abort(usbd_xfer_handle); | |
180 | Static void ehci_device_bulk_close(usbd_pipe_handle); | 180 | Static void ehci_device_bulk_close(usbd_pipe_handle); | |
181 | Static void ehci_device_bulk_done(usbd_xfer_handle); | 181 | Static void ehci_device_bulk_done(usbd_xfer_handle); | |
182 | 182 | |||
183 | Static usbd_status ehci_device_intr_transfer(usbd_xfer_handle); | 183 | Static usbd_status ehci_device_intr_transfer(usbd_xfer_handle); | |
184 | Static usbd_status ehci_device_intr_start(usbd_xfer_handle); | 184 | Static usbd_status ehci_device_intr_start(usbd_xfer_handle); | |
185 | Static void ehci_device_intr_abort(usbd_xfer_handle); | 185 | Static void ehci_device_intr_abort(usbd_xfer_handle); | |
186 | Static void ehci_device_intr_close(usbd_pipe_handle); | 186 | Static void ehci_device_intr_close(usbd_pipe_handle); | |
187 | Static void ehci_device_intr_done(usbd_xfer_handle); | 187 | Static void ehci_device_intr_done(usbd_xfer_handle); | |
188 | 188 | |||
189 | Static usbd_status ehci_device_isoc_transfer(usbd_xfer_handle); | 189 | Static usbd_status ehci_device_isoc_transfer(usbd_xfer_handle); | |
190 | Static usbd_status ehci_device_isoc_start(usbd_xfer_handle); | 190 | Static usbd_status ehci_device_isoc_start(usbd_xfer_handle); | |
191 | Static void ehci_device_isoc_abort(usbd_xfer_handle); | 191 | Static void ehci_device_isoc_abort(usbd_xfer_handle); | |
192 | Static void ehci_device_isoc_close(usbd_pipe_handle); | 192 | Static void ehci_device_isoc_close(usbd_pipe_handle); | |
193 | Static void ehci_device_isoc_done(usbd_xfer_handle); | 193 | Static void ehci_device_isoc_done(usbd_xfer_handle); | |
194 | 194 | |||
195 | Static void ehci_device_clear_toggle(usbd_pipe_handle pipe); | 195 | Static void ehci_device_clear_toggle(usbd_pipe_handle pipe); | |
196 | Static void ehci_noop(usbd_pipe_handle pipe); | 196 | Static void ehci_noop(usbd_pipe_handle pipe); | |
197 | 197 | |||
198 | Static void ehci_disown(ehci_softc_t *, int, int); | 198 | Static void ehci_disown(ehci_softc_t *, int, int); | |
199 | 199 | |||
200 | Static ehci_soft_qh_t *ehci_alloc_sqh(ehci_softc_t *); | 200 | Static ehci_soft_qh_t *ehci_alloc_sqh(ehci_softc_t *); | |
201 | Static void ehci_free_sqh(ehci_softc_t *, ehci_soft_qh_t *); | 201 | Static void ehci_free_sqh(ehci_softc_t *, ehci_soft_qh_t *); | |
202 | 202 | |||
203 | Static ehci_soft_qtd_t *ehci_alloc_sqtd(ehci_softc_t *); | 203 | Static ehci_soft_qtd_t *ehci_alloc_sqtd(ehci_softc_t *); | |
204 | Static void ehci_free_sqtd(ehci_softc_t *, ehci_soft_qtd_t *); | 204 | Static void ehci_free_sqtd(ehci_softc_t *, ehci_soft_qtd_t *); | |
205 | Static usbd_status ehci_alloc_sqtd_chain(struct ehci_pipe *, | 205 | Static usbd_status ehci_alloc_sqtd_chain(struct ehci_pipe *, | |
206 | ehci_softc_t *, int, int, usbd_xfer_handle, | 206 | ehci_softc_t *, int, int, usbd_xfer_handle, | |
207 | ehci_soft_qtd_t **, ehci_soft_qtd_t **); | 207 | ehci_soft_qtd_t **, ehci_soft_qtd_t **); | |
208 | Static void ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qtd_t *, | 208 | Static void ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qtd_t *, | |
209 | ehci_soft_qtd_t *); | 209 | ehci_soft_qtd_t *); | |
210 | 210 | |||
211 | Static ehci_soft_itd_t *ehci_alloc_itd(ehci_softc_t *sc); | 211 | Static ehci_soft_itd_t *ehci_alloc_itd(ehci_softc_t *sc); | |
212 | Static void ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd); | 212 | Static void ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd); | |
213 | Static void ehci_rem_free_itd_chain(ehci_softc_t *sc, | 213 | Static void ehci_rem_free_itd_chain(ehci_softc_t *sc, | |
214 | struct ehci_xfer *exfer); | 214 | struct ehci_xfer *exfer); | |
215 | Static void ehci_abort_isoc_xfer(usbd_xfer_handle xfer, | 215 | Static void ehci_abort_isoc_xfer(usbd_xfer_handle xfer, | |
216 | usbd_status status); | 216 | usbd_status status); | |
217 | 217 | |||
218 | Static usbd_status ehci_device_request(usbd_xfer_handle xfer); | 218 | Static usbd_status ehci_device_request(usbd_xfer_handle xfer); | |
219 | 219 | |||
220 | Static usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *, | 220 | Static usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *, | |
221 | int ival); | 221 | int ival); | |
222 | 222 | |||
223 | Static void ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *); | 223 | Static void ehci_add_qh(ehci_softc_t *, ehci_soft_qh_t *, | |
224 | ehci_soft_qh_t *); | |||
224 | Static void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *, | 225 | Static void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *, | |
225 | ehci_soft_qh_t *); | 226 | ehci_soft_qh_t *); | |
226 | Static void ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *); | 227 | Static void ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *); | |
227 | Static void ehci_sync_hc(ehci_softc_t *); | 228 | Static void ehci_sync_hc(ehci_softc_t *); | |
228 | 229 | |||
229 | Static void ehci_close_pipe(usbd_pipe_handle, ehci_soft_qh_t *); | 230 | Static void ehci_close_pipe(usbd_pipe_handle, ehci_soft_qh_t *); | |
230 | Static void ehci_abort_xfer(usbd_xfer_handle, usbd_status); | 231 | Static void ehci_abort_xfer(usbd_xfer_handle, usbd_status); | |
231 | 232 | |||
232 | #ifdef EHCI_DEBUG | 233 | #ifdef EHCI_DEBUG | |
233 | Static void ehci_dump_regs(ehci_softc_t *); | 234 | Static void ehci_dump_regs(ehci_softc_t *); | |
234 | void ehci_dump(void); | 235 | void ehci_dump(void); | |
235 | Static ehci_softc_t *theehci; | 236 | Static ehci_softc_t *theehci; | |
236 | Static void ehci_dump_link(ehci_link_t, int); | 237 | Static void ehci_dump_link(ehci_link_t, int); | |
237 | Static void ehci_dump_sqtds(ehci_soft_qtd_t *); | 238 | Static void ehci_dump_sqtds(ehci_soft_qtd_t *); | |
238 | Static void ehci_dump_sqtd(ehci_soft_qtd_t *); | 239 | Static void ehci_dump_sqtd(ehci_soft_qtd_t *); | |
239 | Static void ehci_dump_qtd(ehci_qtd_t *); | 240 | Static void ehci_dump_qtd(ehci_qtd_t *); | |
240 | Static void ehci_dump_sqh(ehci_soft_qh_t *); | 241 | Static void ehci_dump_sqh(ehci_soft_qh_t *); | |
241 | #if notyet | 242 | #if notyet | |
242 | Static void ehci_dump_sitd(struct ehci_soft_itd *itd); | 243 | Static void ehci_dump_sitd(struct ehci_soft_itd *itd); | |
243 | Static void ehci_dump_itd(struct ehci_soft_itd *); | 244 | Static void ehci_dump_itd(struct ehci_soft_itd *); | |
244 | #endif | 245 | #endif | |
245 | #ifdef DIAGNOSTIC | 246 | #ifdef DIAGNOSTIC | |
246 | Static void ehci_dump_exfer(struct ehci_xfer *); | 247 | Static void ehci_dump_exfer(struct ehci_xfer *); | |
247 | #endif | 248 | #endif | |
248 | #endif | 249 | #endif | |
249 | 250 | |||
250 | #define EHCI_NULL htole32(EHCI_LINK_TERMINATE) | 251 | #define EHCI_NULL htole32(EHCI_LINK_TERMINATE) | |
251 | 252 | |||
252 | #define EHCI_INTR_ENDPT 1 | 253 | #define EHCI_INTR_ENDPT 1 | |
253 | 254 | |||
254 | #define ehci_add_intr_list(sc, ex) \ | 255 | #define ehci_add_intr_list(sc, ex) \ | |
255 | TAILQ_INSERT_TAIL(&(sc)->sc_intrhead, (ex), inext); | 256 | TAILQ_INSERT_TAIL(&(sc)->sc_intrhead, (ex), inext); | |
256 | #define ehci_del_intr_list(sc, ex) \ | 257 | #define ehci_del_intr_list(sc, ex) \ | |
257 | do { \ | 258 | do { \ | |
258 | TAILQ_REMOVE(&sc->sc_intrhead, (ex), inext); \ | 259 | TAILQ_REMOVE(&sc->sc_intrhead, (ex), inext); \ | |
259 | (ex)->inext.tqe_prev = NULL; \ | 260 | (ex)->inext.tqe_prev = NULL; \ | |
260 | } while (0) | 261 | } while (0) | |
261 | #define ehci_active_intr_list(ex) ((ex)->inext.tqe_prev != NULL) | 262 | #define ehci_active_intr_list(ex) ((ex)->inext.tqe_prev != NULL) | |
262 | 263 | |||
263 | Static const struct usbd_bus_methods ehci_bus_methods = { | 264 | Static const struct usbd_bus_methods ehci_bus_methods = { | |
264 | ehci_open, | 265 | .open_pipe = ehci_open, | |
265 | ehci_softintr, | 266 | .soft_intr = ehci_softintr, | |
266 | ehci_poll, | 267 | .do_poll = ehci_poll, | |
267 | ehci_allocm, | 268 | .allocm = ehci_allocm, | |
268 | ehci_freem, | 269 | .freem = ehci_freem, | |
269 | ehci_allocx, | 270 | .allocx = ehci_allocx, | |
270 | ehci_freex, | 271 | .freex = ehci_freex, | |
271 | ehci_get_locks, | 272 | .get_locks = ehci_get_locks, | |
272 | }; | 273 | }; | |
273 | 274 | |||
274 | Static const struct usbd_pipe_methods ehci_root_ctrl_methods = { | 275 | Static const struct usbd_pipe_methods ehci_root_ctrl_methods = { | |
275 | ehci_root_ctrl_transfer, | 276 | .transfer = ehci_root_ctrl_transfer, | |
276 | ehci_root_ctrl_start, | 277 | .start = ehci_root_ctrl_start, | |
277 | ehci_root_ctrl_abort, | 278 | .abort = ehci_root_ctrl_abort, | |
278 | ehci_root_ctrl_close, | 279 | .close = ehci_root_ctrl_close, | |
279 | ehci_noop, | 280 | .cleartoggle = ehci_noop, | |
280 | ehci_root_ctrl_done, | 281 | .done = ehci_root_ctrl_done, | |
281 | }; | 282 | }; | |
282 | 283 | |||
283 | Static const struct usbd_pipe_methods ehci_root_intr_methods = { | 284 | Static const struct usbd_pipe_methods ehci_root_intr_methods = { | |
284 | ehci_root_intr_transfer, | 285 | .transfer = ehci_root_intr_transfer, | |
285 | ehci_root_intr_start, | 286 | .start = ehci_root_intr_start, | |
286 | ehci_root_intr_abort, | 287 | .abort = ehci_root_intr_abort, | |
287 | ehci_root_intr_close, | 288 | .close = ehci_root_intr_close, | |
288 | ehci_noop, | 289 | .cleartoggle = ehci_noop, | |
289 | ehci_root_intr_done, | 290 | .done = ehci_root_intr_done, | |
290 | }; | 291 | }; | |
291 | 292 | |||
292 | Static const struct usbd_pipe_methods ehci_device_ctrl_methods = { | 293 | Static const struct usbd_pipe_methods ehci_device_ctrl_methods = { | |
293 | ehci_device_ctrl_transfer, | 294 | .transfer = ehci_device_ctrl_transfer, | |
294 | ehci_device_ctrl_start, | 295 | .start = ehci_device_ctrl_start, | |
295 | ehci_device_ctrl_abort, | 296 | .abort = ehci_device_ctrl_abort, | |
296 | ehci_device_ctrl_close, | 297 | .close = ehci_device_ctrl_close, | |
297 | ehci_noop, | 298 | .cleartoggle = ehci_noop, | |
298 | ehci_device_ctrl_done, | 299 | .done = ehci_device_ctrl_done, | |
299 | }; | 300 | }; | |
300 | 301 | |||
301 | Static const struct usbd_pipe_methods ehci_device_intr_methods = { | 302 | Static const struct usbd_pipe_methods ehci_device_intr_methods = { | |
302 | ehci_device_intr_transfer, | 303 | .transfer = ehci_device_intr_transfer, | |
303 | ehci_device_intr_start, | 304 | .start = ehci_device_intr_start, | |
304 | ehci_device_intr_abort, | 305 | .abort = ehci_device_intr_abort, | |
305 | ehci_device_intr_close, | 306 | .close = ehci_device_intr_close, | |
306 | ehci_device_clear_toggle, | 307 | .cleartoggle = ehci_device_clear_toggle, | |
307 | ehci_device_intr_done, | 308 | .done = ehci_device_intr_done, | |
308 | }; | 309 | }; | |
309 | 310 | |||
310 | Static const struct usbd_pipe_methods ehci_device_bulk_methods = { | 311 | Static const struct usbd_pipe_methods ehci_device_bulk_methods = { | |
311 | ehci_device_bulk_transfer, | 312 | .transfer = ehci_device_bulk_transfer, | |
312 | ehci_device_bulk_start, | 313 | .start = ehci_device_bulk_start, | |
313 | ehci_device_bulk_abort, | 314 | .abort = ehci_device_bulk_abort, | |
314 | ehci_device_bulk_close, | 315 | .close = ehci_device_bulk_close, | |
315 | ehci_device_clear_toggle, | 316 | .cleartoggle = ehci_device_clear_toggle, | |
316 | ehci_device_bulk_done, | 317 | .done = ehci_device_bulk_done, | |
317 | }; | 318 | }; | |
318 | 319 | |||
319 | Static const struct usbd_pipe_methods ehci_device_isoc_methods = { | 320 | Static const struct usbd_pipe_methods ehci_device_isoc_methods = { | |
320 | ehci_device_isoc_transfer, | 321 | .transfer = ehci_device_isoc_transfer, | |
321 | ehci_device_isoc_start, | 322 | .start = ehci_device_isoc_start, | |
322 | ehci_device_isoc_abort, | 323 | .abort = ehci_device_isoc_abort, | |
323 | ehci_device_isoc_close, | 324 | .close = ehci_device_isoc_close, | |
324 | ehci_noop, | 325 | .cleartoggle = ehci_noop, | |
325 | ehci_device_isoc_done, | 326 | .done = ehci_device_isoc_done, | |
326 | }; | 327 | }; | |
327 | 328 | |||
328 | static const uint8_t revbits[EHCI_MAX_POLLRATE] = { | 329 | static const uint8_t revbits[EHCI_MAX_POLLRATE] = { | |
329 | 0x00,0x40,0x20,0x60,0x10,0x50,0x30,0x70,0x08,0x48,0x28,0x68,0x18,0x58,0x38,0x78, | 330 | 0x00,0x40,0x20,0x60,0x10,0x50,0x30,0x70,0x08,0x48,0x28,0x68,0x18,0x58,0x38,0x78, | |
330 | 0x04,0x44,0x24,0x64,0x14,0x54,0x34,0x74,0x0c,0x4c,0x2c,0x6c,0x1c,0x5c,0x3c,0x7c, | 331 | 0x04,0x44,0x24,0x64,0x14,0x54,0x34,0x74,0x0c,0x4c,0x2c,0x6c,0x1c,0x5c,0x3c,0x7c, | |
331 | 0x02,0x42,0x22,0x62,0x12,0x52,0x32,0x72,0x0a,0x4a,0x2a,0x6a,0x1a,0x5a,0x3a,0x7a, | 332 | 0x02,0x42,0x22,0x62,0x12,0x52,0x32,0x72,0x0a,0x4a,0x2a,0x6a,0x1a,0x5a,0x3a,0x7a, | |
332 | 0x06,0x46,0x26,0x66,0x16,0x56,0x36,0x76,0x0e,0x4e,0x2e,0x6e,0x1e,0x5e,0x3e,0x7e, | 333 | 0x06,0x46,0x26,0x66,0x16,0x56,0x36,0x76,0x0e,0x4e,0x2e,0x6e,0x1e,0x5e,0x3e,0x7e, | |
333 | 0x01,0x41,0x21,0x61,0x11,0x51,0x31,0x71,0x09,0x49,0x29,0x69,0x19,0x59,0x39,0x79, | 334 | 0x01,0x41,0x21,0x61,0x11,0x51,0x31,0x71,0x09,0x49,0x29,0x69,0x19,0x59,0x39,0x79, | |
334 | 0x05,0x45,0x25,0x65,0x15,0x55,0x35,0x75,0x0d,0x4d,0x2d,0x6d,0x1d,0x5d,0x3d,0x7d, | 335 | 0x05,0x45,0x25,0x65,0x15,0x55,0x35,0x75,0x0d,0x4d,0x2d,0x6d,0x1d,0x5d,0x3d,0x7d, | |
335 | 0x03,0x43,0x23,0x63,0x13,0x53,0x33,0x73,0x0b,0x4b,0x2b,0x6b,0x1b,0x5b,0x3b,0x7b, | 336 | 0x03,0x43,0x23,0x63,0x13,0x53,0x33,0x73,0x0b,0x4b,0x2b,0x6b,0x1b,0x5b,0x3b,0x7b, | |
336 | 0x07,0x47,0x27,0x67,0x17,0x57,0x37,0x77,0x0f,0x4f,0x2f,0x6f,0x1f,0x5f,0x3f,0x7f, | 337 | 0x07,0x47,0x27,0x67,0x17,0x57,0x37,0x77,0x0f,0x4f,0x2f,0x6f,0x1f,0x5f,0x3f,0x7f, | |
337 | }; | 338 | }; | |
338 | 339 | |||
339 | usbd_status | 340 | usbd_status | |
340 | ehci_init(ehci_softc_t *sc) | 341 | ehci_init(ehci_softc_t *sc) | |
341 | { | 342 | { | |
342 | u_int32_t vers, sparams, cparams, hcr; | 343 | u_int32_t vers, sparams, cparams, hcr; | |
343 | u_int i; | 344 | u_int i; | |
344 | usbd_status err; | 345 | usbd_status err; | |
345 | ehci_soft_qh_t *sqh; | 346 | ehci_soft_qh_t *sqh; | |
346 | u_int ncomp; | 347 | u_int ncomp; | |
347 | 348 | |||
348 | DPRINTF(("ehci_init: start\n")); | 349 | DPRINTF(("ehci_init: start\n")); | |
349 | #ifdef EHCI_DEBUG | 350 | #ifdef EHCI_DEBUG | |
350 | theehci = sc; | 351 | theehci = sc; | |
351 | #endif | 352 | #endif | |
352 | 353 | |||
353 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | 354 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | |
354 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | 355 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | |
355 | cv_init(&sc->sc_softwake_cv, "ehciab"); | 356 | cv_init(&sc->sc_softwake_cv, "ehciab"); | |
356 | cv_init(&sc->sc_doorbell, "ehcidi"); | 357 | cv_init(&sc->sc_doorbell, "ehcidi"); | |
357 | 358 | |||
358 | sc->sc_doorbell_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | 359 | sc->sc_doorbell_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | |
359 | ehci_doorbell, sc); | 360 | ehci_doorbell, sc); | |
360 | sc->sc_pcd_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | 361 | sc->sc_pcd_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | |
361 | ehci_pcd, sc); | 362 | ehci_pcd, sc); | |
362 | 363 | |||
363 | sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); | 364 | sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); | |
364 | 365 | |||
365 | vers = EREAD2(sc, EHCI_HCIVERSION); | 366 | vers = EREAD2(sc, EHCI_HCIVERSION); | |
366 | aprint_verbose("%s: EHCI version %x.%x\n", device_xname(sc->sc_dev), | 367 | aprint_verbose("%s: EHCI version %x.%x\n", device_xname(sc->sc_dev), | |
367 | vers >> 8, vers & 0xff); | 368 | vers >> 8, vers & 0xff); | |
368 | 369 | |||
369 | sparams = EREAD4(sc, EHCI_HCSPARAMS); | 370 | sparams = EREAD4(sc, EHCI_HCSPARAMS); | |
370 | DPRINTF(("ehci_init: sparams=0x%x\n", sparams)); | 371 | DPRINTF(("ehci_init: sparams=0x%x\n", sparams)); | |
371 | sc->sc_npcomp = EHCI_HCS_N_PCC(sparams); | 372 | sc->sc_npcomp = EHCI_HCS_N_PCC(sparams); | |
372 | ncomp = EHCI_HCS_N_CC(sparams); | 373 | ncomp = EHCI_HCS_N_CC(sparams); | |
373 | if (ncomp != sc->sc_ncomp) { | 374 | if (ncomp != sc->sc_ncomp) { | |
374 | aprint_verbose("%s: wrong number of companions (%d != %d)\n", | 375 | aprint_verbose("%s: wrong number of companions (%d != %d)\n", | |
375 | device_xname(sc->sc_dev), ncomp, sc->sc_ncomp); | 376 | device_xname(sc->sc_dev), ncomp, sc->sc_ncomp); | |
376 | #if NOHCI == 0 || NUHCI == 0 | 377 | #if NOHCI == 0 || NUHCI == 0 | |
377 | aprint_error("%s: ohci or uhci probably not configured\n", | 378 | aprint_error("%s: ohci or uhci probably not configured\n", | |
378 | device_xname(sc->sc_dev)); | 379 | device_xname(sc->sc_dev)); | |
379 | #endif | 380 | #endif | |
380 | if (ncomp < sc->sc_ncomp) | 381 | if (ncomp < sc->sc_ncomp) | |
381 | sc->sc_ncomp = ncomp; | 382 | sc->sc_ncomp = ncomp; | |
382 | } | 383 | } | |
383 | if (sc->sc_ncomp > 0) { | 384 | if (sc->sc_ncomp > 0) { | |
384 | KASSERT(!(sc->sc_flags & EHCIF_ETTF)); | 385 | KASSERT(!(sc->sc_flags & EHCIF_ETTF)); | |
385 | aprint_normal("%s: companion controller%s, %d port%s each:", | 386 | aprint_normal("%s: companion controller%s, %d port%s each:", | |
386 | device_xname(sc->sc_dev), sc->sc_ncomp!=1 ? "s" : "", | 387 | device_xname(sc->sc_dev), sc->sc_ncomp!=1 ? "s" : "", | |
387 | EHCI_HCS_N_PCC(sparams), | 388 | EHCI_HCS_N_PCC(sparams), | |
388 | EHCI_HCS_N_PCC(sparams)!=1 ? "s" : ""); | 389 | EHCI_HCS_N_PCC(sparams)!=1 ? "s" : ""); | |
389 | for (i = 0; i < sc->sc_ncomp; i++) | 390 | for (i = 0; i < sc->sc_ncomp; i++) | |
390 | aprint_normal(" %s", device_xname(sc->sc_comps[i])); | 391 | aprint_normal(" %s", device_xname(sc->sc_comps[i])); | |
391 | aprint_normal("\n"); | 392 | aprint_normal("\n"); | |
392 | } | 393 | } | |
393 | sc->sc_noport = EHCI_HCS_N_PORTS(sparams); | 394 | sc->sc_noport = EHCI_HCS_N_PORTS(sparams); | |
394 | cparams = EREAD4(sc, EHCI_HCCPARAMS); | 395 | cparams = EREAD4(sc, EHCI_HCCPARAMS); | |
395 | DPRINTF(("ehci_init: cparams=0x%x\n", cparams)); | 396 | DPRINTF(("ehci_init: cparams=0x%x\n", cparams)); | |
396 | sc->sc_hasppc = EHCI_HCS_PPC(sparams); | 397 | sc->sc_hasppc = EHCI_HCS_PPC(sparams); | |
397 | 398 | |||
398 | if (EHCI_HCC_64BIT(cparams)) { | 399 | if (EHCI_HCC_64BIT(cparams)) { | |
399 | /* MUST clear segment register if 64 bit capable. */ | 400 | /* MUST clear segment register if 64 bit capable. */ | |
400 | EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0); | 401 | EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0); | |
401 | } | 402 | } | |
402 | 403 | |||
403 | sc->sc_bus.usbrev = USBREV_2_0; | 404 | sc->sc_bus.usbrev = USBREV_2_0; | |
404 | 405 | |||
405 | usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag, | 406 | usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag, | |
406 | USB_MEM_RESERVE); | 407 | USB_MEM_RESERVE); | |
407 | 408 | |||
408 | /* Reset the controller */ | 409 | /* Reset the controller */ | |
409 | DPRINTF(("%s: resetting\n", device_xname(sc->sc_dev))); | 410 | DPRINTF(("%s: resetting\n", device_xname(sc->sc_dev))); | |
410 | EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ | 411 | EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ | |
411 | usb_delay_ms(&sc->sc_bus, 1); | 412 | usb_delay_ms(&sc->sc_bus, 1); | |
412 | EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); | 413 | EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); | |
413 | for (i = 0; i < 100; i++) { | 414 | for (i = 0; i < 100; i++) { | |
414 | usb_delay_ms(&sc->sc_bus, 1); | 415 | usb_delay_ms(&sc->sc_bus, 1); | |
415 | hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET; | 416 | hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET; | |
416 | if (!hcr) | 417 | if (!hcr) | |
417 | break; | 418 | break; | |
418 | } | 419 | } | |
419 | if (hcr) { | 420 | if (hcr) { | |
420 | aprint_error("%s: reset timeout\n", device_xname(sc->sc_dev)); | 421 | aprint_error("%s: reset timeout\n", device_xname(sc->sc_dev)); | |
421 | return (USBD_IOERROR); | 422 | return (USBD_IOERROR); | |
422 | } | 423 | } | |
423 | if (sc->sc_vendor_init) | 424 | if (sc->sc_vendor_init) | |
424 | sc->sc_vendor_init(sc); | 425 | sc->sc_vendor_init(sc); | |
425 | 426 | |||
426 | /* | 427 | /* | |
427 | * If we are doing embedded transaction translation function, force | 428 | * If we are doing embedded transaction translation function, force | |
428 | * the controller to host mode. | 429 | * the controller to host mode. | |
429 | */ | 430 | */ | |
430 | if (sc->sc_flags & EHCIF_ETTF) { | 431 | if (sc->sc_flags & EHCIF_ETTF) { | |
431 | uint32_t usbmode = EREAD4(sc, EHCI_USBMODE); | 432 | uint32_t usbmode = EREAD4(sc, EHCI_USBMODE); | |
432 | usbmode &= ~EHCI_USBMODE_CM; | 433 | usbmode &= ~EHCI_USBMODE_CM; | |
433 | usbmode |= EHCI_USBMODE_CM_HOST; | 434 | usbmode |= EHCI_USBMODE_CM_HOST; | |
434 | EWRITE4(sc, EHCI_USBMODE, usbmode); | 435 | EWRITE4(sc, EHCI_USBMODE, usbmode); | |
435 | } | 436 | } | |
436 | 437 | |||
437 | /* XXX need proper intr scheduling */ | 438 | /* XXX need proper intr scheduling */ | |
438 | sc->sc_rand = 96; | 439 | sc->sc_rand = 96; | |
439 | 440 | |||
440 | /* frame list size at default, read back what we got and use that */ | 441 | /* frame list size at default, read back what we got and use that */ | |
441 | switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) { | 442 | switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) { | |
442 | case 0: sc->sc_flsize = 1024; break; | 443 | case 0: sc->sc_flsize = 1024; break; | |
443 | case 1: sc->sc_flsize = 512; break; | 444 | case 1: sc->sc_flsize = 512; break; | |
444 | case 2: sc->sc_flsize = 256; break; | 445 | case 2: sc->sc_flsize = 256; break; | |
445 | case 3: return (USBD_IOERROR); | 446 | case 3: return (USBD_IOERROR); | |
446 | } | 447 | } | |
447 | err = usb_allocmem(&sc->sc_bus, sc->sc_flsize * sizeof(ehci_link_t), | 448 | err = usb_allocmem(&sc->sc_bus, sc->sc_flsize * sizeof(ehci_link_t), | |
448 | EHCI_FLALIGN_ALIGN, &sc->sc_fldma); | 449 | EHCI_FLALIGN_ALIGN, &sc->sc_fldma); | |
449 | if (err) | 450 | if (err) | |
450 | return (err); | 451 | return (err); | |
451 | DPRINTF(("%s: flsize=%d\n", device_xname(sc->sc_dev),sc->sc_flsize)); | 452 | DPRINTF(("%s: flsize=%d\n", device_xname(sc->sc_dev),sc->sc_flsize)); | |
452 | sc->sc_flist = KERNADDR(&sc->sc_fldma, 0); | 453 | sc->sc_flist = KERNADDR(&sc->sc_fldma, 0); | |
453 | 454 | |||
454 | for (i = 0; i < sc->sc_flsize; i++) { | 455 | for (i = 0; i < sc->sc_flsize; i++) { | |
455 | sc->sc_flist[i] = EHCI_NULL; | 456 | sc->sc_flist[i] = EHCI_NULL; | |
456 | } | 457 | } | |
457 | 458 | |||
458 | EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); | 459 | EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); | |
459 | 460 | |||
460 | sc->sc_softitds = kmem_zalloc(sc->sc_flsize * sizeof(ehci_soft_itd_t *), | 461 | sc->sc_softitds = kmem_zalloc(sc->sc_flsize * sizeof(ehci_soft_itd_t *), | |
461 | KM_SLEEP); | 462 | KM_SLEEP); | |
462 | if (sc->sc_softitds == NULL) | 463 | if (sc->sc_softitds == NULL) | |
463 | return ENOMEM; | 464 | return ENOMEM; | |
464 | LIST_INIT(&sc->sc_freeitds); | 465 | LIST_INIT(&sc->sc_freeitds); | |
465 | TAILQ_INIT(&sc->sc_intrhead); | 466 | TAILQ_INIT(&sc->sc_intrhead); | |
466 | 467 | |||
467 | /* Set up the bus struct. */ | 468 | /* Set up the bus struct. */ | |
468 | sc->sc_bus.methods = &ehci_bus_methods; | 469 | sc->sc_bus.methods = &ehci_bus_methods; | |
469 | sc->sc_bus.pipe_size = sizeof(struct ehci_pipe); | 470 | sc->sc_bus.pipe_size = sizeof(struct ehci_pipe); | |
470 | 471 | |||
471 | sc->sc_eintrs = EHCI_NORMAL_INTRS; | 472 | sc->sc_eintrs = EHCI_NORMAL_INTRS; | |
472 | 473 | |||
473 | /* | 474 | /* | |
474 | * Allocate the interrupt dummy QHs. These are arranged to give poll | 475 | * Allocate the interrupt dummy QHs. These are arranged to give poll | |
475 | * intervals that are powers of 2 times 1ms. | 476 | * intervals that are powers of 2 times 1ms. | |
476 | */ | 477 | */ | |
477 | for (i = 0; i < EHCI_INTRQHS; i++) { | 478 | for (i = 0; i < EHCI_INTRQHS; i++) { | |
478 | sqh = ehci_alloc_sqh(sc); | 479 | sqh = ehci_alloc_sqh(sc); | |
479 | if (sqh == NULL) { | 480 | if (sqh == NULL) { | |
480 | err = USBD_NOMEM; | 481 | err = USBD_NOMEM; | |
481 | goto bad1; | 482 | goto bad1; | |
482 | } | 483 | } | |
483 | sc->sc_islots[i].sqh = sqh; | 484 | sc->sc_islots[i].sqh = sqh; | |
484 | } | 485 | } | |
485 | for (i = 0; i < EHCI_INTRQHS; i++) { | 486 | for (i = 0; i < EHCI_INTRQHS; i++) { | |
486 | sqh = sc->sc_islots[i].sqh; | 487 | sqh = sc->sc_islots[i].sqh; | |
487 | if (i == 0) { | 488 | if (i == 0) { | |
488 | /* The last (1ms) QH terminates. */ | 489 | /* The last (1ms) QH terminates. */ | |
489 | sqh->qh.qh_link = EHCI_NULL; | 490 | sqh->qh.qh_link = EHCI_NULL; | |
490 | sqh->next = NULL; | 491 | sqh->next = NULL; | |
491 | } else { | 492 | } else { | |
492 | /* Otherwise the next QH has half the poll interval */ | 493 | /* Otherwise the next QH has half the poll interval */ | |
493 | sqh->next = sc->sc_islots[(i + 1) / 2 - 1].sqh; | 494 | sqh->next = sc->sc_islots[(i + 1) / 2 - 1].sqh; | |
494 | sqh->qh.qh_link = htole32(sqh->next->physaddr | | 495 | sqh->qh.qh_link = htole32(sqh->next->physaddr | | |
495 | EHCI_LINK_QH); | 496 | EHCI_LINK_QH); | |
496 | } | 497 | } | |
497 | sqh->qh.qh_endp = htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH)); | 498 | sqh->qh.qh_endp = htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH)); | |
498 | sqh->qh.qh_curqtd = EHCI_NULL; | 499 | sqh->qh.qh_curqtd = EHCI_NULL; | |
499 | sqh->next = NULL; | 500 | sqh->next = NULL; | |
500 | sqh->qh.qh_qtd.qtd_next = EHCI_NULL; | 501 | sqh->qh.qh_qtd.qtd_next = EHCI_NULL; | |
501 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; | 502 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; | |
502 | sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); | 503 | sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); | |
503 | sqh->sqtd = NULL; | 504 | sqh->sqtd = NULL; | |
504 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 505 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
505 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 506 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
506 | } | 507 | } | |
507 | /* Point the frame list at the last level (128ms). */ | 508 | /* Point the frame list at the last level (128ms). */ | |
508 | for (i = 0; i < sc->sc_flsize; i++) { | 509 | for (i = 0; i < sc->sc_flsize; i++) { | |
509 | int j; | 510 | int j; | |
510 | 511 | |||
511 | j = (i & ~(EHCI_MAX_POLLRATE-1)) | | 512 | j = (i & ~(EHCI_MAX_POLLRATE-1)) | | |
512 | revbits[i & (EHCI_MAX_POLLRATE-1)]; | 513 | revbits[i & (EHCI_MAX_POLLRATE-1)]; | |
513 | sc->sc_flist[j] = htole32(EHCI_LINK_QH | | 514 | sc->sc_flist[j] = htole32(EHCI_LINK_QH | | |
514 | sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1, | 515 | sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1, | |
515 | i)].sqh->physaddr); | 516 | i)].sqh->physaddr); | |
516 | } | 517 | } | |
517 | usb_syncmem(&sc->sc_fldma, 0, sc->sc_flsize * sizeof(ehci_link_t), | 518 | usb_syncmem(&sc->sc_fldma, 0, sc->sc_flsize * sizeof(ehci_link_t), | |
518 | BUS_DMASYNC_PREWRITE); | 519 | BUS_DMASYNC_PREWRITE); | |
519 | 520 | |||
520 | /* Allocate dummy QH that starts the async list. */ | 521 | /* Allocate dummy QH that starts the async list. */ | |
521 | sqh = ehci_alloc_sqh(sc); | 522 | sqh = ehci_alloc_sqh(sc); | |
522 | if (sqh == NULL) { | 523 | if (sqh == NULL) { | |
523 | err = USBD_NOMEM; | 524 | err = USBD_NOMEM; | |
524 | goto bad1; | 525 | goto bad1; | |
525 | } | 526 | } | |
526 | /* Fill the QH */ | 527 | /* Fill the QH */ | |
527 | sqh->qh.qh_endp = | 528 | sqh->qh.qh_endp = | |
528 | htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL); | 529 | htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL); | |
529 | sqh->qh.qh_link = | 530 | sqh->qh.qh_link = | |
530 | htole32(sqh->physaddr | EHCI_LINK_QH); | 531 | htole32(sqh->physaddr | EHCI_LINK_QH); | |
531 | sqh->qh.qh_curqtd = EHCI_NULL; | 532 | sqh->qh.qh_curqtd = EHCI_NULL; | |
532 | sqh->next = NULL; | 533 | sqh->next = NULL; | |
533 | /* Fill the overlay qTD */ | 534 | /* Fill the overlay qTD */ | |
534 | sqh->qh.qh_qtd.qtd_next = EHCI_NULL; | 535 | sqh->qh.qh_qtd.qtd_next = EHCI_NULL; | |
535 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; | 536 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; | |
536 | sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); | 537 | sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); | |
537 | sqh->sqtd = NULL; | 538 | sqh->sqtd = NULL; | |
538 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 539 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
539 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 540 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
540 | #ifdef EHCI_DEBUG | 541 | #ifdef EHCI_DEBUG | |
541 | if (ehcidebug) { | 542 | if (ehcidebug) { | |
542 | ehci_dump_sqh(sqh); | 543 | ehci_dump_sqh(sqh); | |
543 | } | 544 | } | |
544 | #endif | 545 | #endif | |
545 | 546 | |||
546 | /* Point to async list */ | 547 | /* Point to async list */ | |
547 | sc->sc_async_head = sqh; | 548 | sc->sc_async_head = sqh; | |
548 | EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH); | 549 | EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH); | |
549 | 550 | |||
550 | callout_init(&(sc->sc_tmo_intrlist), CALLOUT_MPSAFE); | 551 | callout_init(&(sc->sc_tmo_intrlist), CALLOUT_MPSAFE); | |
551 | 552 | |||
552 | /* Turn on controller */ | 553 | /* Turn on controller */ | |
553 | EOWRITE4(sc, EHCI_USBCMD, | 554 | EOWRITE4(sc, EHCI_USBCMD, | |
554 | EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */ | 555 | EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */ | |
555 | (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) | | 556 | (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) | | |
556 | EHCI_CMD_ASE | | 557 | EHCI_CMD_ASE | | |
557 | EHCI_CMD_PSE | | 558 | EHCI_CMD_PSE | | |
558 | EHCI_CMD_RS); | 559 | EHCI_CMD_RS); | |
559 | 560 | |||
560 | /* Take over port ownership */ | 561 | /* Take over port ownership */ | |
561 | EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF); | 562 | EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF); | |
562 | 563 | |||
563 | for (i = 0; i < 100; i++) { | 564 | for (i = 0; i < 100; i++) { | |
564 | usb_delay_ms(&sc->sc_bus, 1); | 565 | usb_delay_ms(&sc->sc_bus, 1); | |
565 | hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; | 566 | hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; | |
566 | if (!hcr) | 567 | if (!hcr) | |
567 | break; | 568 | break; | |
568 | } | 569 | } | |
569 | if (hcr) { | 570 | if (hcr) { | |
570 | aprint_error("%s: run timeout\n", device_xname(sc->sc_dev)); | 571 | aprint_error("%s: run timeout\n", device_xname(sc->sc_dev)); | |
571 | return (USBD_IOERROR); | 572 | return (USBD_IOERROR); | |
572 | } | 573 | } | |
573 | 574 | |||
574 | /* Enable interrupts */ | 575 | /* Enable interrupts */ | |
575 | DPRINTFN(1,("ehci_init: enabling\n")); | 576 | DPRINTFN(1,("ehci_init: enabling\n")); | |
576 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); | 577 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); | |
577 | 578 | |||
578 | return (USBD_NORMAL_COMPLETION); | 579 | return (USBD_NORMAL_COMPLETION); | |
579 | 580 | |||
580 | #if 0 | 581 | #if 0 | |
581 | bad2: | 582 | bad2: | |
582 | ehci_free_sqh(sc, sc->sc_async_head); | 583 | ehci_free_sqh(sc, sc->sc_async_head); | |
583 | #endif | 584 | #endif | |
584 | bad1: | 585 | bad1: | |
585 | usb_freemem(&sc->sc_bus, &sc->sc_fldma); | 586 | usb_freemem(&sc->sc_bus, &sc->sc_fldma); | |
586 | return (err); | 587 | return (err); | |
587 | } | 588 | } | |
588 | 589 | |||
589 | int | 590 | int | |
590 | ehci_intr(void *v) | 591 | ehci_intr(void *v) | |
591 | { | 592 | { | |
592 | ehci_softc_t *sc = v; | 593 | ehci_softc_t *sc = v; | |
593 | int ret = 0; | 594 | int ret = 0; | |
594 | 595 | |||
595 | if (sc == NULL) | 596 | if (sc == NULL) | |
596 | return 0; | 597 | return 0; | |
597 | 598 | |||
598 | mutex_spin_enter(&sc->sc_intr_lock); | 599 | mutex_spin_enter(&sc->sc_intr_lock); | |
599 | 600 | |||
600 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) | 601 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) | |
601 | goto done; | 602 | goto done; | |
602 | 603 | |||
603 | /* If we get an interrupt while polling, then just ignore it. */ | 604 | /* If we get an interrupt while polling, then just ignore it. */ | |
604 | if (sc->sc_bus.use_polling) { | 605 | if (sc->sc_bus.use_polling) { | |
605 | u_int32_t intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); | 606 | u_int32_t intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); | |
606 | 607 | |||
607 | if (intrs) | 608 | if (intrs) | |
608 | EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ | 609 | EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ | |
609 | #ifdef DIAGNOSTIC | 610 | #ifdef DIAGNOSTIC | |
610 | DPRINTFN(16, ("ehci_intr: ignored interrupt while polling\n")); | 611 | DPRINTFN(16, ("ehci_intr: ignored interrupt while polling\n")); | |
611 | #endif | 612 | #endif | |
612 | goto done; | 613 | goto done; | |
613 | } | 614 | } | |
614 | 615 | |||
615 | ret = ehci_intr1(sc); | 616 | ret = ehci_intr1(sc); | |
616 | 617 | |||
617 | done: | 618 | done: | |
618 | mutex_spin_exit(&sc->sc_intr_lock); | 619 | mutex_spin_exit(&sc->sc_intr_lock); | |
619 | return ret; | 620 | return ret; | |
620 | } | 621 | } | |
621 | 622 | |||
622 | Static int | 623 | Static int | |
623 | ehci_intr1(ehci_softc_t *sc) | 624 | ehci_intr1(ehci_softc_t *sc) | |
624 | { | 625 | { | |
625 | u_int32_t intrs, eintrs; | 626 | u_int32_t intrs, eintrs; | |
626 | 627 | |||
627 | DPRINTFN(20,("ehci_intr1: enter\n")); | 628 | DPRINTFN(20,("ehci_intr1: enter\n")); | |
628 | 629 | |||
629 | /* In case the interrupt occurs before initialization has completed. */ | 630 | /* In case the interrupt occurs before initialization has completed. */ | |
630 | if (sc == NULL) { | 631 | if (sc == NULL) { | |
631 | #ifdef DIAGNOSTIC | 632 | #ifdef DIAGNOSTIC | |
632 | printf("ehci_intr1: sc == NULL\n"); | 633 | printf("ehci_intr1: sc == NULL\n"); | |
633 | #endif | 634 | #endif | |
634 | return (0); | 635 | return (0); | |
635 | } | 636 | } | |
636 | 637 | |||
637 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | 638 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | |
638 | 639 | |||
639 | intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); | 640 | intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); | |
640 | if (!intrs) | 641 | if (!intrs) | |
641 | return (0); | 642 | return (0); | |
642 | 643 | |||
643 | eintrs = intrs & sc->sc_eintrs; | 644 | eintrs = intrs & sc->sc_eintrs; | |
644 | DPRINTFN(7, ("ehci_intr1: sc=%p intrs=0x%x(0x%x) eintrs=0x%x\n", | 645 | DPRINTFN(7, ("ehci_intr1: sc=%p intrs=0x%x(0x%x) eintrs=0x%x\n", | |
645 | sc, (u_int)intrs, EOREAD4(sc, EHCI_USBSTS), | 646 | sc, (u_int)intrs, EOREAD4(sc, EHCI_USBSTS), | |
646 | (u_int)eintrs)); | 647 | (u_int)eintrs)); | |
647 | if (!eintrs) | 648 | if (!eintrs) | |
648 | return (0); | 649 | return (0); | |
649 | 650 | |||
650 | EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ | 651 | EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ | |
651 | sc->sc_bus.intr_context++; | 652 | sc->sc_bus.intr_context++; | |
652 | sc->sc_bus.no_intrs++; | 653 | sc->sc_bus.no_intrs++; | |
653 | if (eintrs & EHCI_STS_IAA) { | 654 | if (eintrs & EHCI_STS_IAA) { | |
654 | DPRINTF(("ehci_intr1: door bell\n")); | 655 | DPRINTF(("ehci_intr1: door bell\n")); | |
655 | kpreempt_disable(); | 656 | kpreempt_disable(); | |
656 | softint_schedule(sc->sc_doorbell_si); | 657 | softint_schedule(sc->sc_doorbell_si); | |
657 | kpreempt_enable(); | 658 | kpreempt_enable(); | |
658 | eintrs &= ~EHCI_STS_IAA; | 659 | eintrs &= ~EHCI_STS_IAA; | |
659 | } | 660 | } | |
660 | if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) { | 661 | if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) { | |
661 | DPRINTFN(5,("ehci_intr1: %s %s\n", | 662 | DPRINTFN(5,("ehci_intr1: %s %s\n", | |
662 | eintrs & EHCI_STS_INT ? "INT" : "", | 663 | eintrs & EHCI_STS_INT ? "INT" : "", | |
663 | eintrs & EHCI_STS_ERRINT ? "ERRINT" : "")); | 664 | eintrs & EHCI_STS_ERRINT ? "ERRINT" : "")); | |
664 | usb_schedsoftintr(&sc->sc_bus); | 665 | usb_schedsoftintr(&sc->sc_bus); | |
665 | eintrs &= ~(EHCI_STS_INT | EHCI_STS_ERRINT); | 666 | eintrs &= ~(EHCI_STS_INT | EHCI_STS_ERRINT); | |
666 | } | 667 | } | |
667 | if (eintrs & EHCI_STS_HSE) { | 668 | if (eintrs & EHCI_STS_HSE) { | |
668 | printf("%s: unrecoverable error, controller halted\n", | 669 | printf("%s: unrecoverable error, controller halted\n", | |
669 | device_xname(sc->sc_dev)); | 670 | device_xname(sc->sc_dev)); | |
670 | /* XXX what else */ | 671 | /* XXX what else */ | |
671 | } | 672 | } | |
672 | if (eintrs & EHCI_STS_PCD) { | 673 | if (eintrs & EHCI_STS_PCD) { | |
673 | kpreempt_disable(); | 674 | kpreempt_disable(); | |
674 | softint_schedule(sc->sc_pcd_si); | 675 | softint_schedule(sc->sc_pcd_si); | |
675 | kpreempt_enable(); | 676 | kpreempt_enable(); | |
676 | eintrs &= ~EHCI_STS_PCD; | 677 | eintrs &= ~EHCI_STS_PCD; | |
677 | } | 678 | } | |
678 | 679 | |||
679 | sc->sc_bus.intr_context--; | 680 | sc->sc_bus.intr_context--; | |
680 | 681 | |||
681 | if (eintrs != 0) { | 682 | if (eintrs != 0) { | |
682 | /* Block unprocessed interrupts. */ | 683 | /* Block unprocessed interrupts. */ | |
683 | sc->sc_eintrs &= ~eintrs; | 684 | sc->sc_eintrs &= ~eintrs; | |
684 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); | 685 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); | |
685 | printf("%s: blocking intrs 0x%x\n", | 686 | printf("%s: blocking intrs 0x%x\n", | |
686 | device_xname(sc->sc_dev), eintrs); | 687 | device_xname(sc->sc_dev), eintrs); | |
687 | } | 688 | } | |
688 | 689 | |||
689 | return (1); | 690 | return (1); | |
690 | } | 691 | } | |
691 | 692 | |||
692 | Static void | 693 | Static void | |
693 | ehci_doorbell(void *addr) | 694 | ehci_doorbell(void *addr) | |
694 | { | 695 | { | |
695 | ehci_softc_t *sc = addr; | 696 | ehci_softc_t *sc = addr; | |
696 | 697 | |||
697 | mutex_enter(&sc->sc_lock); | 698 | mutex_enter(&sc->sc_lock); | |
698 | cv_broadcast(&sc->sc_doorbell); | 699 | cv_broadcast(&sc->sc_doorbell); | |
699 | mutex_exit(&sc->sc_lock); | 700 | mutex_exit(&sc->sc_lock); | |
700 | } | 701 | } | |
701 | 702 | |||
702 | Static void | 703 | Static void | |
703 | ehci_pcd(void *addr) | 704 | ehci_pcd(void *addr) | |
704 | { | 705 | { | |
705 | ehci_softc_t *sc = addr; | 706 | ehci_softc_t *sc = addr; | |
706 | usbd_xfer_handle xfer; | 707 | usbd_xfer_handle xfer; | |
707 | usbd_pipe_handle pipe; | 708 | usbd_pipe_handle pipe; | |
708 | u_char *p; | 709 | u_char *p; | |
709 | int i, m; | 710 | int i, m; | |
710 | 711 | |||
711 | mutex_enter(&sc->sc_lock); | 712 | mutex_enter(&sc->sc_lock); | |
712 | xfer = sc->sc_intrxfer; | 713 | xfer = sc->sc_intrxfer; | |
713 | 714 | |||
714 | if (xfer == NULL) { | 715 | if (xfer == NULL) { | |
715 | /* Just ignore the change. */ | 716 | /* Just ignore the change. */ | |
716 | goto done; | 717 | goto done; | |
717 | } | 718 | } | |
718 | 719 | |||
719 | pipe = xfer->pipe; | 720 | pipe = xfer->pipe; | |
720 | 721 | |||
721 | p = KERNADDR(&xfer->dmabuf, 0); | 722 | p = KERNADDR(&xfer->dmabuf, 0); | |
722 | m = min(sc->sc_noport, xfer->length * 8 - 1); | 723 | m = min(sc->sc_noport, xfer->length * 8 - 1); | |
723 | memset(p, 0, xfer->length); | 724 | memset(p, 0, xfer->length); | |
724 | for (i = 1; i <= m; i++) { | 725 | for (i = 1; i <= m; i++) { | |
725 | /* Pick out CHANGE bits from the status reg. */ | 726 | /* Pick out CHANGE bits from the status reg. */ | |
726 | if (EOREAD4(sc, EHCI_PORTSC(i)) & EHCI_PS_CLEAR) | 727 | if (EOREAD4(sc, EHCI_PORTSC(i)) & EHCI_PS_CLEAR) | |
727 | p[i/8] |= 1 << (i%8); | 728 | p[i/8] |= 1 << (i%8); | |
728 | } | 729 | } | |
729 | DPRINTF(("ehci_pcd: change=0x%02x\n", *p)); | 730 | DPRINTF(("ehci_pcd: change=0x%02x\n", *p)); | |
730 | xfer->actlen = xfer->length; | 731 | xfer->actlen = xfer->length; | |
731 | xfer->status = USBD_NORMAL_COMPLETION; | 732 | xfer->status = USBD_NORMAL_COMPLETION; | |
732 | 733 | |||
733 | usb_transfer_complete(xfer); | 734 | usb_transfer_complete(xfer); | |
734 | 735 | |||
735 | done: | 736 | done: | |
736 | mutex_exit(&sc->sc_lock); | 737 | mutex_exit(&sc->sc_lock); | |
737 | } | 738 | } | |
738 | 739 | |||
739 | Static void | 740 | Static void | |
740 | ehci_softintr(void *v) | 741 | ehci_softintr(void *v) | |
741 | { | 742 | { | |
742 | struct usbd_bus *bus = v; | 743 | struct usbd_bus *bus = v; | |
743 | ehci_softc_t *sc = bus->hci_private; | 744 | ehci_softc_t *sc = bus->hci_private; | |
744 | struct ehci_xfer *ex, *nextex; | 745 | struct ehci_xfer *ex, *nextex; | |
745 | 746 | |||
746 | DPRINTFN(10,("%s: ehci_softintr (%d)\n", device_xname(sc->sc_dev), | 747 | DPRINTFN(10,("%s: ehci_softintr (%d)\n", device_xname(sc->sc_dev), | |
747 | sc->sc_bus.intr_context)); | 748 | sc->sc_bus.intr_context)); | |
748 | 749 | |||
749 | mutex_enter(&sc->sc_lock); | 750 | mutex_enter(&sc->sc_lock); | |
750 | 751 | |||
751 | sc->sc_bus.intr_context++; | 752 | sc->sc_bus.intr_context++; | |
752 | 753 | |||
753 | /* | 754 | /* | |
754 | * The only explanation I can think of for why EHCI is as brain dead | 755 | * The only explanation I can think of for why EHCI is as brain dead | |
755 | * as UHCI interrupt-wise is that Intel was involved in both. | 756 | * as UHCI interrupt-wise is that Intel was involved in both. | |
756 | * An interrupt just tells us that something is done, we have no | 757 | * An interrupt just tells us that something is done, we have no | |
757 | * clue what, so we need to scan through all active transfers. :-( | 758 | * clue what, so we need to scan through all active transfers. :-( | |
758 | */ | 759 | */ | |
759 | for (ex = TAILQ_FIRST(&sc->sc_intrhead); ex; ex = nextex) { | 760 | for (ex = TAILQ_FIRST(&sc->sc_intrhead); ex; ex = nextex) { | |
760 | nextex = TAILQ_NEXT(ex, inext); | 761 | nextex = TAILQ_NEXT(ex, inext); | |
761 | ehci_check_intr(sc, ex); | 762 | ehci_check_intr(sc, ex); | |
762 | } | 763 | } | |
763 | 764 | |||
764 | /* Schedule a callout to catch any dropped transactions. */ | 765 | /* Schedule a callout to catch any dropped transactions. */ | |
765 | if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) && | 766 | if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) && | |
766 | !TAILQ_EMPTY(&sc->sc_intrhead)) | 767 | !TAILQ_EMPTY(&sc->sc_intrhead)) | |
767 | callout_reset(&(sc->sc_tmo_intrlist), | 768 | callout_reset(&(sc->sc_tmo_intrlist), | |
768 | (hz), (ehci_intrlist_timeout), (sc)); | 769 | (hz), (ehci_intrlist_timeout), (sc)); | |
769 | 770 | |||
770 | if (sc->sc_softwake) { | 771 | if (sc->sc_softwake) { | |
771 | sc->sc_softwake = 0; | 772 | sc->sc_softwake = 0; | |
772 | cv_broadcast(&sc->sc_softwake_cv); | 773 | cv_broadcast(&sc->sc_softwake_cv); | |
773 | } | 774 | } | |
774 | 775 | |||
775 | sc->sc_bus.intr_context--; | 776 | sc->sc_bus.intr_context--; | |
776 | 777 | |||
777 | mutex_exit(&sc->sc_lock); | 778 | mutex_exit(&sc->sc_lock); | |
778 | } | 779 | } | |
779 | 780 | |||
780 | /* Check for an interrupt. */ | 781 | /* Check for an interrupt. */ | |
781 | Static void | 782 | Static void | |
782 | ehci_check_intr(ehci_softc_t *sc, struct ehci_xfer *ex) | 783 | ehci_check_intr(ehci_softc_t *sc, struct ehci_xfer *ex) | |
783 | { | 784 | { | |
784 | int attr; | 785 | int attr; | |
785 | 786 | |||
786 | DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex)); | 787 | DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex)); | |
787 | 788 | |||
788 | KASSERT(mutex_owned(&sc->sc_lock)); | 789 | KASSERT(mutex_owned(&sc->sc_lock)); | |
789 | 790 | |||
790 | attr = ex->xfer.pipe->endpoint->edesc->bmAttributes; | 791 | attr = ex->xfer.pipe->endpoint->edesc->bmAttributes; | |
791 | if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS) | 792 | if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS) | |
792 | ehci_check_itd_intr(sc, ex); | 793 | ehci_check_itd_intr(sc, ex); | |
793 | else | 794 | else | |
794 | ehci_check_qh_intr(sc, ex); | 795 | ehci_check_qh_intr(sc, ex); | |
795 | 796 | |||
796 | return; | 797 | return; | |
797 | } | 798 | } | |
798 | 799 | |||
799 | Static void | 800 | Static void | |
800 | ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex) | 801 | ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex) | |
801 | { | 802 | { | |
802 | ehci_soft_qtd_t *sqtd, *lsqtd; | 803 | ehci_soft_qtd_t *sqtd, *lsqtd; | |
803 | __uint32_t status; | 804 | __uint32_t status; | |
804 | 805 | |||
805 | KASSERT(mutex_owned(&sc->sc_lock)); | 806 | KASSERT(mutex_owned(&sc->sc_lock)); | |
806 | 807 | |||
807 | if (ex->sqtdstart == NULL) { | 808 | if (ex->sqtdstart == NULL) { | |
808 | printf("ehci_check_qh_intr: not valid sqtd\n"); | 809 | printf("ehci_check_qh_intr: not valid sqtd\n"); | |
809 | return; | 810 | return; | |
810 | } | 811 | } | |
811 | 812 | |||
812 | lsqtd = ex->sqtdend; | 813 | lsqtd = ex->sqtdend; | |
813 | #ifdef DIAGNOSTIC | 814 | #ifdef DIAGNOSTIC | |
814 | if (lsqtd == NULL) { | 815 | if (lsqtd == NULL) { | |
815 | printf("ehci_check_qh_intr: lsqtd==0\n"); | 816 | printf("ehci_check_qh_intr: lsqtd==0\n"); | |
816 | return; | 817 | return; | |
817 | } | 818 | } | |
818 | #endif | 819 | #endif | |
819 | /* | 820 | /* | |
820 | * If the last TD is still active we need to check whether there | 821 | * If the last TD is still active we need to check whether there | |
821 | * is a an error somewhere in the middle, or whether there was a | 822 | * is a an error somewhere in the middle, or whether there was a | |
822 | * short packet (SPD and not ACTIVE). | 823 | * short packet (SPD and not ACTIVE). | |
823 | */ | 824 | */ | |
824 | usb_syncmem(&lsqtd->dma, | 825 | usb_syncmem(&lsqtd->dma, | |
825 | lsqtd->offs + offsetof(ehci_qtd_t, qtd_status), | 826 | lsqtd->offs + offsetof(ehci_qtd_t, qtd_status), | |
826 | sizeof(lsqtd->qtd.qtd_status), | 827 | sizeof(lsqtd->qtd.qtd_status), | |
827 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 828 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
828 | if (le32toh(lsqtd->qtd.qtd_status) & EHCI_QTD_ACTIVE) { | 829 | if (le32toh(lsqtd->qtd.qtd_status) & EHCI_QTD_ACTIVE) { | |
829 | DPRINTFN(12, ("ehci_check_intr: active ex=%p\n", ex)); | 830 | DPRINTFN(12, ("ehci_check_intr: active ex=%p\n", ex)); | |
830 | for (sqtd = ex->sqtdstart; sqtd != lsqtd; sqtd=sqtd->nextqtd) { | 831 | for (sqtd = ex->sqtdstart; sqtd != lsqtd; sqtd=sqtd->nextqtd) { | |
831 | usb_syncmem(&sqtd->dma, | 832 | usb_syncmem(&sqtd->dma, | |
832 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | 833 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | |
833 | sizeof(sqtd->qtd.qtd_status), | 834 | sizeof(sqtd->qtd.qtd_status), | |
834 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 835 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
835 | status = le32toh(sqtd->qtd.qtd_status); | 836 | status = le32toh(sqtd->qtd.qtd_status); | |
836 | usb_syncmem(&sqtd->dma, | 837 | usb_syncmem(&sqtd->dma, | |
837 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | 838 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | |
838 | sizeof(sqtd->qtd.qtd_status), BUS_DMASYNC_PREREAD); | 839 | sizeof(sqtd->qtd.qtd_status), BUS_DMASYNC_PREREAD); | |
839 | /* If there's an active QTD the xfer isn't done. */ | 840 | /* If there's an active QTD the xfer isn't done. */ | |
840 | if (status & EHCI_QTD_ACTIVE) | 841 | if (status & EHCI_QTD_ACTIVE) | |
841 | break; | 842 | break; | |
842 | /* Any kind of error makes the xfer done. */ | 843 | /* Any kind of error makes the xfer done. */ | |
843 | if (status & EHCI_QTD_HALTED) | 844 | if (status & EHCI_QTD_HALTED) | |
844 | goto done; | 845 | goto done; | |
845 | /* We want short packets, and it is short: it's done */ | 846 | /* We want short packets, and it is short: it's done */ | |
846 | if (EHCI_QTD_GET_BYTES(status) != 0) | 847 | if (EHCI_QTD_GET_BYTES(status) != 0) | |
847 | goto done; | 848 | goto done; | |
848 | } | 849 | } | |
849 | DPRINTFN(12, ("ehci_check_intr: ex=%p std=%p still active\n", | 850 | DPRINTFN(12, ("ehci_check_intr: ex=%p std=%p still active\n", | |
850 | ex, ex->sqtdstart)); | 851 | ex, ex->sqtdstart)); | |
851 | usb_syncmem(&lsqtd->dma, | 852 | usb_syncmem(&lsqtd->dma, | |
852 | lsqtd->offs + offsetof(ehci_qtd_t, qtd_status), | 853 | lsqtd->offs + offsetof(ehci_qtd_t, qtd_status), | |
853 | sizeof(lsqtd->qtd.qtd_status), BUS_DMASYNC_PREREAD); | 854 | sizeof(lsqtd->qtd.qtd_status), BUS_DMASYNC_PREREAD); | |
854 | return; | 855 | return; | |
855 | } | 856 | } | |
856 | done: | 857 | done: | |
857 | DPRINTFN(12, ("ehci_check_intr: ex=%p done\n", ex)); | 858 | DPRINTFN(12, ("ehci_check_intr: ex=%p done\n", ex)); | |
858 | callout_stop(&ex->xfer.timeout_handle); | 859 | callout_stop(&ex->xfer.timeout_handle); | |
859 | ehci_idone(ex); | 860 | ehci_idone(ex); | |
860 | } | 861 | } | |
861 | 862 | |||
862 | Static void | 863 | Static void | |
863 | ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) { | 864 | ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) { | |
864 | ehci_soft_itd_t *itd; | 865 | ehci_soft_itd_t *itd; | |
865 | int i; | 866 | int i; | |
866 | 867 | |||
867 | KASSERT(mutex_owned(&sc->sc_lock)); | 868 | KASSERT(mutex_owned(&sc->sc_lock)); | |
868 | 869 | |||
869 | if (&ex->xfer != SIMPLEQ_FIRST(&ex->xfer.pipe->queue)) | 870 | if (&ex->xfer != SIMPLEQ_FIRST(&ex->xfer.pipe->queue)) | |
870 | return; | 871 | return; | |
871 | 872 | |||
872 | if (ex->itdstart == NULL) { | 873 | if (ex->itdstart == NULL) { | |
873 | printf("ehci_check_itd_intr: not valid itd\n"); | 874 | printf("ehci_check_itd_intr: not valid itd\n"); | |
874 | return; | 875 | return; | |
875 | } | 876 | } | |
876 | 877 | |||
877 | itd = ex->itdend; | 878 | itd = ex->itdend; | |
878 | #ifdef DIAGNOSTIC | 879 | #ifdef DIAGNOSTIC | |
879 | if (itd == NULL) { | 880 | if (itd == NULL) { | |
880 | printf("ehci_check_itd_intr: itdend == 0\n"); | 881 | printf("ehci_check_itd_intr: itdend == 0\n"); | |
881 | return; | 882 | return; | |
882 | } | 883 | } | |
883 | #endif | 884 | #endif | |
884 | 885 | |||
885 | /* | 886 | /* | |
886 | * check no active transfers in last itd, meaning we're finished | 887 | * check no active transfers in last itd, meaning we're finished | |
887 | */ | 888 | */ | |
888 | 889 | |||
889 | usb_syncmem(&itd->dma, itd->offs + offsetof(ehci_itd_t, itd_ctl), | 890 | usb_syncmem(&itd->dma, itd->offs + offsetof(ehci_itd_t, itd_ctl), | |
890 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_POSTWRITE | | 891 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_POSTWRITE | | |
891 | BUS_DMASYNC_POSTREAD); | 892 | BUS_DMASYNC_POSTREAD); | |
892 | 893 | |||
893 | for (i = 0; i < EHCI_ITD_NUFRAMES; i++) { | 894 | for (i = 0; i < EHCI_ITD_NUFRAMES; i++) { | |
894 | if (le32toh(itd->itd.itd_ctl[i]) & EHCI_ITD_ACTIVE) | 895 | if (le32toh(itd->itd.itd_ctl[i]) & EHCI_ITD_ACTIVE) | |
895 | break; | 896 | break; | |
896 | } | 897 | } | |
897 | 898 | |||
898 | if (i == EHCI_ITD_NUFRAMES) { | 899 | if (i == EHCI_ITD_NUFRAMES) { | |
899 | goto done; /* All 8 descriptors inactive, it's done */ | 900 | goto done; /* All 8 descriptors inactive, it's done */ | |
900 | } | 901 | } | |
901 | 902 | |||
902 | DPRINTFN(12, ("ehci_check_itd_intr: ex %p itd %p still active\n", ex, | 903 | DPRINTFN(12, ("ehci_check_itd_intr: ex %p itd %p still active\n", ex, | |
903 | ex->itdstart)); | 904 | ex->itdstart)); | |
904 | return; | 905 | return; | |
905 | done: | 906 | done: | |
906 | DPRINTFN(12, ("ehci_check_itd_intr: ex=%p done\n", ex)); | 907 | DPRINTFN(12, ("ehci_check_itd_intr: ex=%p done\n", ex)); | |
907 | callout_stop(&ex->xfer.timeout_handle); | 908 | callout_stop(&ex->xfer.timeout_handle); | |
908 | ehci_idone(ex); | 909 | ehci_idone(ex); | |
909 | } | 910 | } | |
910 | 911 | |||
911 | Static void | 912 | Static void | |
912 | ehci_idone(struct ehci_xfer *ex) | 913 | ehci_idone(struct ehci_xfer *ex) | |
913 | { | 914 | { | |
914 | usbd_xfer_handle xfer = &ex->xfer; | 915 | usbd_xfer_handle xfer = &ex->xfer; | |
915 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | 916 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | |
916 | struct ehci_softc *sc = xfer->pipe->device->bus->hci_private; | 917 | struct ehci_softc *sc = xfer->pipe->device->bus->hci_private; | |
917 | ehci_soft_qtd_t *sqtd, *lsqtd; | 918 | ehci_soft_qtd_t *sqtd, *lsqtd; | |
918 | u_int32_t status = 0, nstatus = 0; | 919 | u_int32_t status = 0, nstatus = 0; | |
919 | int actlen; | 920 | int actlen; | |
920 | 921 | |||
921 | KASSERT(mutex_owned(&sc->sc_lock)); | 922 | KASSERT(mutex_owned(&sc->sc_lock)); | |
922 | 923 | |||
923 | DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex)); | 924 | DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex)); | |
924 | 925 | |||
925 | #ifdef DIAGNOSTIC | 926 | #ifdef DIAGNOSTIC | |
926 | { | 927 | { | |
927 | if (ex->isdone) { | 928 | if (ex->isdone) { | |
928 | #ifdef EHCI_DEBUG | 929 | #ifdef EHCI_DEBUG | |
929 | printf("ehci_idone: ex is done!\n "); | 930 | printf("ehci_idone: ex is done!\n "); | |
930 | ehci_dump_exfer(ex); | 931 | ehci_dump_exfer(ex); | |
931 | #else | 932 | #else | |
932 | printf("ehci_idone: ex=%p is done!\n", ex); | 933 | printf("ehci_idone: ex=%p is done!\n", ex); | |
933 | #endif | 934 | #endif | |
934 | return; | 935 | return; | |
935 | } | 936 | } | |
936 | ex->isdone = 1; | 937 | ex->isdone = 1; | |
937 | } | 938 | } | |
938 | #endif | 939 | #endif | |
939 | if (xfer->status == USBD_CANCELLED || | 940 | if (xfer->status == USBD_CANCELLED || | |
940 | xfer->status == USBD_TIMEOUT) { | 941 | xfer->status == USBD_TIMEOUT) { | |
941 | DPRINTF(("ehci_idone: aborted xfer=%p\n", xfer)); | 942 | DPRINTF(("ehci_idone: aborted xfer=%p\n", xfer)); | |
942 | return; | 943 | return; | |
943 | } | 944 | } | |
944 | 945 | |||
945 | #ifdef EHCI_DEBUG | 946 | #ifdef EHCI_DEBUG | |
946 | DPRINTFN(/*10*/2, ("ehci_idone: xfer=%p, pipe=%p ready\n", xfer, epipe)); | 947 | DPRINTFN(/*10*/2, ("ehci_idone: xfer=%p, pipe=%p ready\n", xfer, epipe)); | |
947 | if (ehcidebug > 10) | 948 | if (ehcidebug > 10) | |
948 | ehci_dump_sqtds(ex->sqtdstart); | 949 | ehci_dump_sqtds(ex->sqtdstart); | |
949 | #endif | 950 | #endif | |
950 | 951 | |||
951 | /* The transfer is done, compute actual length and status. */ | 952 | /* The transfer is done, compute actual length and status. */ | |
952 | 953 | |||
953 | if (UE_GET_XFERTYPE(xfer->pipe->endpoint->edesc->bmAttributes) | 954 | if (UE_GET_XFERTYPE(xfer->pipe->endpoint->edesc->bmAttributes) | |
954 | == UE_ISOCHRONOUS) { | 955 | == UE_ISOCHRONOUS) { | |
955 | /* Isoc transfer */ | 956 | /* Isoc transfer */ | |
956 | struct ehci_soft_itd *itd; | 957 | struct ehci_soft_itd *itd; | |
957 | int i, nframes, len, uframes; | 958 | int i, nframes, len, uframes; | |
958 | 959 | |||
959 | nframes = 0; | 960 | nframes = 0; | |
960 | actlen = 0; | 961 | actlen = 0; | |
961 | 962 | |||
962 | i = xfer->pipe->endpoint->edesc->bInterval; | 963 | i = xfer->pipe->endpoint->edesc->bInterval; | |
963 | uframes = min(1 << (i - 1), USB_UFRAMES_PER_FRAME); | 964 | uframes = min(1 << (i - 1), USB_UFRAMES_PER_FRAME); | |
964 | 965 | |||
965 | for (itd = ex->itdstart; itd != NULL; itd = itd->xfer_next) { | 966 | for (itd = ex->itdstart; itd != NULL; itd = itd->xfer_next) { | |
966 | usb_syncmem(&itd->dma,itd->offs + offsetof(ehci_itd_t,itd_ctl), | 967 | usb_syncmem(&itd->dma,itd->offs + offsetof(ehci_itd_t,itd_ctl), | |
967 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_POSTWRITE | | 968 | sizeof(itd->itd.itd_ctl), BUS_DMASYNC_POSTWRITE | | |
968 | BUS_DMASYNC_POSTREAD); | 969 | BUS_DMASYNC_POSTREAD); | |
969 | 970 | |||
970 | for (i = 0; i < EHCI_ITD_NUFRAMES; i += uframes) { | 971 | for (i = 0; i < EHCI_ITD_NUFRAMES; i += uframes) { | |
971 | /* XXX - driver didn't fill in the frame full | 972 | /* XXX - driver didn't fill in the frame full | |
972 | * of uframes. This leads to scheduling | 973 | * of uframes. This leads to scheduling | |
973 | * inefficiencies, but working around | 974 | * inefficiencies, but working around | |
974 | * this doubles complexity of tracking | 975 | * this doubles complexity of tracking | |
975 | * an xfer. | 976 | * an xfer. | |
976 | */ | 977 | */ | |
977 | if (nframes >= xfer->nframes) | 978 | if (nframes >= xfer->nframes) | |
978 | break; | 979 | break; | |
979 | 980 | |||
980 | status = le32toh(itd->itd.itd_ctl[i]); | 981 | status = le32toh(itd->itd.itd_ctl[i]); | |
981 | len = EHCI_ITD_GET_LEN(status); | 982 | len = EHCI_ITD_GET_LEN(status); | |
982 | if (EHCI_ITD_GET_STATUS(status) != 0) | 983 | if (EHCI_ITD_GET_STATUS(status) != 0) | |
983 | len = 0; /*No valid data on error*/ | 984 | len = 0; /*No valid data on error*/ | |
984 | 985 | |||
985 | xfer->frlengths[nframes++] = len; | 986 | xfer->frlengths[nframes++] = len; | |
986 | actlen += len; | 987 | actlen += len; | |
987 | } | 988 | } | |
988 | 989 | |||
989 | if (nframes >= xfer->nframes) | 990 | if (nframes >= xfer->nframes) | |
990 | break; | 991 | break; | |
991 | } | 992 | } | |
992 | 993 | |||
993 | xfer->actlen = actlen; | 994 | xfer->actlen = actlen; | |
994 | xfer->status = USBD_NORMAL_COMPLETION; | 995 | xfer->status = USBD_NORMAL_COMPLETION; | |
995 | goto end; | 996 | goto end; | |
996 | } | 997 | } | |
997 | 998 | |||
998 | /* Continue processing xfers using queue heads */ | 999 | /* Continue processing xfers using queue heads */ | |
999 | 1000 | |||
1000 | lsqtd = ex->sqtdend; | 1001 | lsqtd = ex->sqtdend; | |
1001 | actlen = 0; | 1002 | actlen = 0; | |
1002 | for (sqtd = ex->sqtdstart; sqtd != lsqtd->nextqtd; sqtd = sqtd->nextqtd) { | 1003 | for (sqtd = ex->sqtdstart; sqtd != lsqtd->nextqtd; sqtd = sqtd->nextqtd) { | |
1003 | usb_syncmem(&sqtd->dma, sqtd->offs, sizeof(sqtd->qtd), | 1004 | usb_syncmem(&sqtd->dma, sqtd->offs, sizeof(sqtd->qtd), | |
1004 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1005 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1005 | nstatus = le32toh(sqtd->qtd.qtd_status); | 1006 | nstatus = le32toh(sqtd->qtd.qtd_status); | |
1006 | if (nstatus & EHCI_QTD_ACTIVE) | 1007 | if (nstatus & EHCI_QTD_ACTIVE) | |
1007 | break; | 1008 | break; | |
1008 | 1009 | |||
1009 | status = nstatus; | 1010 | status = nstatus; | |
1010 | if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP) | 1011 | if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP) | |
1011 | actlen += sqtd->len - EHCI_QTD_GET_BYTES(status); | 1012 | actlen += sqtd->len - EHCI_QTD_GET_BYTES(status); | |
1012 | } | 1013 | } | |
1013 | 1014 | |||
1014 | 1015 | |||
1015 | /* | 1016 | /* | |
1016 | * If there are left over TDs we need to update the toggle. | 1017 | * If there are left over TDs we need to update the toggle. | |
1017 | * The default pipe doesn't need it since control transfers | 1018 | * The default pipe doesn't need it since control transfers | |
1018 | * start the toggle at 0 every time. | 1019 | * start the toggle at 0 every time. | |
1019 | * For a short transfer we need to update the toggle for the missing | 1020 | * For a short transfer we need to update the toggle for the missing | |
1020 | * packets within the qTD. | 1021 | * packets within the qTD. | |
1021 | */ | 1022 | */ | |
1022 | if ((sqtd != lsqtd->nextqtd || EHCI_QTD_GET_BYTES(status)) && | 1023 | if ((sqtd != lsqtd->nextqtd || EHCI_QTD_GET_BYTES(status)) && | |
1023 | xfer->pipe->device->default_pipe != xfer->pipe) { | 1024 | xfer->pipe->device->default_pipe != xfer->pipe) { | |
1024 | DPRINTFN(2, ("ehci_idone: need toggle update " | 1025 | DPRINTFN(2, ("ehci_idone: need toggle update " | |
1025 | "status=%08x nstatus=%08x\n", status, nstatus)); | 1026 | "status=%08x nstatus=%08x\n", status, nstatus)); | |
1026 | #if 0 | 1027 | #if 0 | |
1027 | ehci_dump_sqh(epipe->sqh); | 1028 | ehci_dump_sqh(epipe->sqh); | |
1028 | ehci_dump_sqtds(ex->sqtdstart); | 1029 | ehci_dump_sqtds(ex->sqtdstart); | |
1029 | #endif | 1030 | #endif | |
1030 | epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(nstatus); | 1031 | epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(nstatus); | |
1031 | } | 1032 | } | |
1032 | 1033 | |||
1033 | DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n", | 1034 | DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n", | |
1034 | xfer->length, actlen, status)); | 1035 | xfer->length, actlen, status)); | |
1035 | xfer->actlen = actlen; | 1036 | xfer->actlen = actlen; | |
1036 | if (status & EHCI_QTD_HALTED) { | 1037 | if (status & EHCI_QTD_HALTED) { | |
1037 | #ifdef EHCI_DEBUG | 1038 | #ifdef EHCI_DEBUG | |
1038 | char sbuf[128]; | 1039 | char sbuf[128]; | |
1039 | 1040 | |||
1040 | snprintb(sbuf, sizeof(sbuf), | 1041 | snprintb(sbuf, sizeof(sbuf), | |
1041 | "\20\7HALTED\6BUFERR\5BABBLE\4XACTERR\3MISSED\1PINGSTATE", | 1042 | "\20\7HALTED\6BUFERR\5BABBLE\4XACTERR\3MISSED\1PINGSTATE", | |
1042 | (u_int32_t)status); | 1043 | (u_int32_t)status); | |
1043 | 1044 | |||
1044 | DPRINTFN(2, ("ehci_idone: error, addr=%d, endpt=0x%02x, " | 1045 | DPRINTFN(2, ("ehci_idone: error, addr=%d, endpt=0x%02x, " | |
1045 | "status 0x%s\n", | 1046 | "status 0x%s\n", | |
1046 | xfer->pipe->device->address, | 1047 | xfer->pipe->device->address, | |
1047 | xfer->pipe->endpoint->edesc->bEndpointAddress, | 1048 | xfer->pipe->endpoint->edesc->bEndpointAddress, | |
1048 | sbuf)); | 1049 | sbuf)); | |
1049 | if (ehcidebug > 2) { | 1050 | if (ehcidebug > 2) { | |
1050 | ehci_dump_sqh(epipe->sqh); | 1051 | ehci_dump_sqh(epipe->sqh); | |
1051 | ehci_dump_sqtds(ex->sqtdstart); | 1052 | ehci_dump_sqtds(ex->sqtdstart); | |
1052 | } | 1053 | } | |
1053 | #endif | 1054 | #endif | |
1054 | /* low&full speed has an extra error flag */ | 1055 | /* low&full speed has an extra error flag */ | |
1055 | if (EHCI_QH_GET_EPS(epipe->sqh->qh.qh_endp) != | 1056 | if (EHCI_QH_GET_EPS(epipe->sqh->qh.qh_endp) != | |
1056 | EHCI_QH_SPEED_HIGH) | 1057 | EHCI_QH_SPEED_HIGH) | |
1057 | status &= EHCI_QTD_STATERRS | EHCI_QTD_PINGSTATE; | 1058 | status &= EHCI_QTD_STATERRS | EHCI_QTD_PINGSTATE; | |
1058 | else | 1059 | else | |
1059 | status &= EHCI_QTD_STATERRS; | 1060 | status &= EHCI_QTD_STATERRS; | |
1060 | if (status == 0) /* no other errors means a stall */ { | 1061 | if (status == 0) /* no other errors means a stall */ { | |
1061 | xfer->status = USBD_STALLED; | 1062 | xfer->status = USBD_STALLED; | |
1062 | } else { | 1063 | } else { | |
1063 | xfer->status = USBD_IOERROR; /* more info XXX */ | 1064 | xfer->status = USBD_IOERROR; /* more info XXX */ | |
1064 | } | 1065 | } | |
1065 | /* XXX need to reset TT on missed microframe */ | 1066 | /* XXX need to reset TT on missed microframe */ | |
1066 | if (status & EHCI_QTD_MISSEDMICRO) { | 1067 | if (status & EHCI_QTD_MISSEDMICRO) { | |
1067 | printf("%s: missed microframe, TT reset not " | 1068 | printf("%s: missed microframe, TT reset not " | |
1068 | "implemented, hub might be inoperational\n", | 1069 | "implemented, hub might be inoperational\n", | |
1069 | device_xname(sc->sc_dev)); | 1070 | device_xname(sc->sc_dev)); | |
1070 | } | 1071 | } | |
1071 | } else { | 1072 | } else { | |
1072 | xfer->status = USBD_NORMAL_COMPLETION; | 1073 | xfer->status = USBD_NORMAL_COMPLETION; | |
1073 | } | 1074 | } | |
1074 | 1075 | |||
1075 | end: | 1076 | end: | |
1076 | /* XXX transfer_complete memcpys out transfer data (for in endpoints) | 1077 | /* XXX transfer_complete memcpys out transfer data (for in endpoints) | |
1077 | * during this call, before methods->done is called: dma sync required | 1078 | * during this call, before methods->done is called: dma sync required | |
1078 | * beforehand? */ | 1079 | * beforehand? */ | |
1079 | usb_transfer_complete(xfer); | 1080 | usb_transfer_complete(xfer); | |
1080 | DPRINTFN(/*12*/2, ("ehci_idone: ex=%p done\n", ex)); | 1081 | DPRINTFN(/*12*/2, ("ehci_idone: ex=%p done\n", ex)); | |
1081 | } | 1082 | } | |
1082 | 1083 | |||
1083 | /* | 1084 | /* | |
1084 | * Wait here until controller claims to have an interrupt. | 1085 | * Wait here until controller claims to have an interrupt. | |
1085 | * Then call ehci_intr and return. Use timeout to avoid waiting | 1086 | * Then call ehci_intr and return. Use timeout to avoid waiting | |
1086 | * too long. | 1087 | * too long. | |
1087 | */ | 1088 | */ | |
1088 | Static void | 1089 | Static void | |
1089 | ehci_waitintr(ehci_softc_t *sc, usbd_xfer_handle xfer) | 1090 | ehci_waitintr(ehci_softc_t *sc, usbd_xfer_handle xfer) | |
1090 | { | 1091 | { | |
1091 | int timo; | 1092 | int timo; | |
1092 | u_int32_t intrs; | 1093 | u_int32_t intrs; | |
1093 | 1094 | |||
1094 | xfer->status = USBD_IN_PROGRESS; | 1095 | xfer->status = USBD_IN_PROGRESS; | |
1095 | for (timo = xfer->timeout; timo >= 0; timo--) { | 1096 | for (timo = xfer->timeout; timo >= 0; timo--) { | |
1096 | usb_delay_ms(&sc->sc_bus, 1); | 1097 | usb_delay_ms(&sc->sc_bus, 1); | |
1097 | if (sc->sc_dying) | 1098 | if (sc->sc_dying) | |
1098 | break; | 1099 | break; | |
1099 | intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)) & | 1100 | intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)) & | |
1100 | sc->sc_eintrs; | 1101 | sc->sc_eintrs; | |
1101 | DPRINTFN(15,("ehci_waitintr: 0x%04x\n", intrs)); | 1102 | DPRINTFN(15,("ehci_waitintr: 0x%04x\n", intrs)); | |
1102 | #ifdef EHCI_DEBUG | 1103 | #ifdef EHCI_DEBUG | |
1103 | if (ehcidebug > 15) | 1104 | if (ehcidebug > 15) | |
1104 | ehci_dump_regs(sc); | 1105 | ehci_dump_regs(sc); | |
1105 | #endif | 1106 | #endif | |
1106 | if (intrs) { | 1107 | if (intrs) { | |
1107 | mutex_spin_enter(&sc->sc_intr_lock); | 1108 | mutex_spin_enter(&sc->sc_intr_lock); | |
1108 | ehci_intr1(sc); | 1109 | ehci_intr1(sc); | |
1109 | mutex_spin_exit(&sc->sc_intr_lock); | 1110 | mutex_spin_exit(&sc->sc_intr_lock); | |
1110 | if (xfer->status != USBD_IN_PROGRESS) | 1111 | if (xfer->status != USBD_IN_PROGRESS) | |
1111 | return; | 1112 | return; | |
1112 | } | 1113 | } | |
1113 | } | 1114 | } | |
1114 | 1115 | |||
1115 | /* Timeout */ | 1116 | /* Timeout */ | |
1116 | DPRINTF(("ehci_waitintr: timeout\n")); | 1117 | DPRINTF(("ehci_waitintr: timeout\n")); | |
1117 | xfer->status = USBD_TIMEOUT; | 1118 | xfer->status = USBD_TIMEOUT; | |
1118 | usb_transfer_complete(xfer); | 1119 | usb_transfer_complete(xfer); | |
1119 | /* XXX should free TD */ | 1120 | /* XXX should free TD */ | |
1120 | } | 1121 | } | |
1121 | 1122 | |||
1122 | Static void | 1123 | Static void | |
1123 | ehci_poll(struct usbd_bus *bus) | 1124 | ehci_poll(struct usbd_bus *bus) | |
1124 | { | 1125 | { | |
1125 | ehci_softc_t *sc = bus->hci_private; | 1126 | ehci_softc_t *sc = bus->hci_private; | |
1126 | #ifdef EHCI_DEBUG | 1127 | #ifdef EHCI_DEBUG | |
1127 | static int last; | 1128 | static int last; | |
1128 | int new; | 1129 | int new; | |
1129 | new = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); | 1130 | new = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); | |
1130 | if (new != last) { | 1131 | if (new != last) { | |
1131 | DPRINTFN(10,("ehci_poll: intrs=0x%04x\n", new)); | 1132 | DPRINTFN(10,("ehci_poll: intrs=0x%04x\n", new)); | |
1132 | last = new; | 1133 | last = new; | |
1133 | } | 1134 | } | |
1134 | #endif | 1135 | #endif | |
1135 | 1136 | |||
1136 | if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs) { | 1137 | if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs) { | |
1137 | mutex_spin_enter(&sc->sc_intr_lock); | 1138 | mutex_spin_enter(&sc->sc_intr_lock); | |
1138 | ehci_intr1(sc); | 1139 | ehci_intr1(sc); | |
1139 | mutex_spin_exit(&sc->sc_intr_lock); | 1140 | mutex_spin_exit(&sc->sc_intr_lock); | |
1140 | } | 1141 | } | |
1141 | } | 1142 | } | |
1142 | 1143 | |||
1143 | void | 1144 | void | |
1144 | ehci_childdet(device_t self, device_t child) | 1145 | ehci_childdet(device_t self, device_t child) | |
1145 | { | 1146 | { | |
1146 | struct ehci_softc *sc = device_private(self); | 1147 | struct ehci_softc *sc = device_private(self); | |
1147 | 1148 | |||
1148 | KASSERT(sc->sc_child == child); | 1149 | KASSERT(sc->sc_child == child); | |
1149 | sc->sc_child = NULL; | 1150 | sc->sc_child = NULL; | |
1150 | } | 1151 | } | |
1151 | 1152 | |||
1152 | int | 1153 | int | |
1153 | ehci_detach(struct ehci_softc *sc, int flags) | 1154 | ehci_detach(struct ehci_softc *sc, int flags) | |
1154 | { | 1155 | { | |
1155 | usbd_xfer_handle xfer; | 1156 | usbd_xfer_handle xfer; | |
1156 | int rv = 0; | 1157 | int rv = 0; | |
1157 | 1158 | |||
1158 | if (sc->sc_child != NULL) | 1159 | if (sc->sc_child != NULL) | |
1159 | rv = config_detach(sc->sc_child, flags); | 1160 | rv = config_detach(sc->sc_child, flags); | |
1160 | 1161 | |||
1161 | if (rv != 0) | 1162 | if (rv != 0) | |
1162 | return (rv); | 1163 | return (rv); | |
1163 | 1164 | |||
1164 | callout_halt(&sc->sc_tmo_intrlist, NULL); | 1165 | callout_halt(&sc->sc_tmo_intrlist, NULL); | |
1165 | callout_destroy(&sc->sc_tmo_intrlist); | 1166 | callout_destroy(&sc->sc_tmo_intrlist); | |
1166 | 1167 | |||
1167 | /* XXX free other data structures XXX */ | 1168 | /* XXX free other data structures XXX */ | |
1168 | if (sc->sc_softitds) | 1169 | if (sc->sc_softitds) | |
1169 | kmem_free(sc->sc_softitds, | 1170 | kmem_free(sc->sc_softitds, | |
1170 | sc->sc_flsize * sizeof(ehci_soft_itd_t *)); | 1171 | sc->sc_flsize * sizeof(ehci_soft_itd_t *)); | |
1171 | cv_destroy(&sc->sc_doorbell); | 1172 | cv_destroy(&sc->sc_doorbell); | |
1172 | cv_destroy(&sc->sc_softwake_cv); | 1173 | cv_destroy(&sc->sc_softwake_cv); | |
1173 | 1174 | |||
1174 | softint_disestablish(sc->sc_doorbell_si); | 1175 | softint_disestablish(sc->sc_doorbell_si); | |
1175 | softint_disestablish(sc->sc_pcd_si); | 1176 | softint_disestablish(sc->sc_pcd_si); | |
1176 | 1177 | |||
1177 | while ((xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers)) != NULL) { | 1178 | while ((xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers)) != NULL) { | |
1178 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | 1179 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | |
1179 | kmem_free(xfer, sizeof(struct ehci_xfer)); | 1180 | kmem_free(xfer, sizeof(struct ehci_xfer)); | |
1180 | } | 1181 | } | |
1181 | 1182 | |||
1182 | EOWRITE4(sc, EHCI_CONFIGFLAG, 0); | 1183 | EOWRITE4(sc, EHCI_CONFIGFLAG, 0); | |
1183 | 1184 | |||
1184 | return (rv); | 1185 | return (rv); | |
1185 | } | 1186 | } | |
1186 | 1187 | |||
1187 | 1188 | |||
1188 | int | 1189 | int | |
1189 | ehci_activate(device_t self, enum devact act) | 1190 | ehci_activate(device_t self, enum devact act) | |
1190 | { | 1191 | { | |
1191 | struct ehci_softc *sc = device_private(self); | 1192 | struct ehci_softc *sc = device_private(self); | |
1192 | 1193 | |||
1193 | switch (act) { | 1194 | switch (act) { | |
1194 | case DVACT_DEACTIVATE: | 1195 | case DVACT_DEACTIVATE: | |
1195 | sc->sc_dying = 1; | 1196 | sc->sc_dying = 1; | |
1196 | return 0; | 1197 | return 0; | |
1197 | default: | 1198 | default: | |
1198 | return EOPNOTSUPP; | 1199 | return EOPNOTSUPP; | |
1199 | } | 1200 | } | |
1200 | } | 1201 | } | |
1201 | 1202 | |||
1202 | /* | 1203 | /* | |
1203 | * Handle suspend/resume. | 1204 | * Handle suspend/resume. | |
1204 | * | 1205 | * | |
1205 | * We need to switch to polling mode here, because this routine is | 1206 | * We need to switch to polling mode here, because this routine is | |
1206 | * called from an interrupt context. This is all right since we | 1207 | * called from an interrupt context. This is all right since we | |
1207 | * are almost suspended anyway. | 1208 | * are almost suspended anyway. | |
1208 | * | 1209 | * | |
1209 | * Note that this power handler isn't to be registered directly; the | 1210 | * Note that this power handler isn't to be registered directly; the | |
1210 | * bus glue needs to call out to it. | 1211 | * bus glue needs to call out to it. | |
1211 | */ | 1212 | */ | |
1212 | bool | 1213 | bool | |
1213 | ehci_suspend(device_t dv, const pmf_qual_t *qual) | 1214 | ehci_suspend(device_t dv, const pmf_qual_t *qual) | |
1214 | { | 1215 | { | |
1215 | ehci_softc_t *sc = device_private(dv); | 1216 | ehci_softc_t *sc = device_private(dv); | |
1216 | int i; | 1217 | int i; | |
1217 | uint32_t cmd, hcr; | 1218 | uint32_t cmd, hcr; | |
1218 | 1219 | |||
1219 | mutex_spin_enter(&sc->sc_intr_lock); | 1220 | mutex_spin_enter(&sc->sc_intr_lock); | |
1220 | sc->sc_bus.use_polling++; | 1221 | sc->sc_bus.use_polling++; | |
1221 | mutex_spin_exit(&sc->sc_intr_lock); | 1222 | mutex_spin_exit(&sc->sc_intr_lock); | |
1222 | 1223 | |||
1223 | for (i = 1; i <= sc->sc_noport; i++) { | 1224 | for (i = 1; i <= sc->sc_noport; i++) { | |
1224 | cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR; | 1225 | cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR; | |
1225 | if ((cmd & EHCI_PS_PO) == 0 && (cmd & EHCI_PS_PE) == EHCI_PS_PE) | 1226 | if ((cmd & EHCI_PS_PO) == 0 && (cmd & EHCI_PS_PE) == EHCI_PS_PE) | |
1226 | EOWRITE4(sc, EHCI_PORTSC(i), cmd | EHCI_PS_SUSP); | 1227 | EOWRITE4(sc, EHCI_PORTSC(i), cmd | EHCI_PS_SUSP); | |
1227 | } | 1228 | } | |
1228 | 1229 | |||
1229 | sc->sc_cmd = EOREAD4(sc, EHCI_USBCMD); | 1230 | sc->sc_cmd = EOREAD4(sc, EHCI_USBCMD); | |
1230 | 1231 | |||
1231 | cmd = sc->sc_cmd & ~(EHCI_CMD_ASE | EHCI_CMD_PSE); | 1232 | cmd = sc->sc_cmd & ~(EHCI_CMD_ASE | EHCI_CMD_PSE); | |
1232 | EOWRITE4(sc, EHCI_USBCMD, cmd); | 1233 | EOWRITE4(sc, EHCI_USBCMD, cmd); | |
1233 | 1234 | |||
1234 | for (i = 0; i < 100; i++) { | 1235 | for (i = 0; i < 100; i++) { | |
1235 | hcr = EOREAD4(sc, EHCI_USBSTS) & (EHCI_STS_ASS | EHCI_STS_PSS); | 1236 | hcr = EOREAD4(sc, EHCI_USBSTS) & (EHCI_STS_ASS | EHCI_STS_PSS); | |
1236 | if (hcr == 0) | 1237 | if (hcr == 0) | |
1237 | break; | 1238 | break; | |
1238 | 1239 | |||
1239 | usb_delay_ms(&sc->sc_bus, 1); | 1240 | usb_delay_ms(&sc->sc_bus, 1); | |
1240 | } | 1241 | } | |
1241 | if (hcr != 0) | 1242 | if (hcr != 0) | |
1242 | printf("%s: reset timeout\n", device_xname(dv)); | 1243 | printf("%s: reset timeout\n", device_xname(dv)); | |
1243 | 1244 | |||
1244 | cmd &= ~EHCI_CMD_RS; | 1245 | cmd &= ~EHCI_CMD_RS; | |
1245 | EOWRITE4(sc, EHCI_USBCMD, cmd); | 1246 | EOWRITE4(sc, EHCI_USBCMD, cmd); | |
1246 | 1247 | |||
1247 | for (i = 0; i < 100; i++) { | 1248 | for (i = 0; i < 100; i++) { | |
1248 | hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; | 1249 | hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; | |
1249 | if (hcr == EHCI_STS_HCH) | 1250 | if (hcr == EHCI_STS_HCH) | |
1250 | break; | 1251 | break; | |
1251 | 1252 | |||
1252 | usb_delay_ms(&sc->sc_bus, 1); | 1253 | usb_delay_ms(&sc->sc_bus, 1); | |
1253 | } | 1254 | } | |
1254 | if (hcr != EHCI_STS_HCH) | 1255 | if (hcr != EHCI_STS_HCH) | |
1255 | printf("%s: config timeout\n", device_xname(dv)); | 1256 | printf("%s: config timeout\n", device_xname(dv)); | |
1256 | 1257 | |||
1257 | mutex_spin_enter(&sc->sc_intr_lock); | 1258 | mutex_spin_enter(&sc->sc_intr_lock); | |
1258 | sc->sc_bus.use_polling--; | 1259 | sc->sc_bus.use_polling--; | |
1259 | mutex_spin_exit(&sc->sc_intr_lock); | 1260 | mutex_spin_exit(&sc->sc_intr_lock); | |
1260 | 1261 | |||
1261 | return true; | 1262 | return true; | |
1262 | } | 1263 | } | |
1263 | 1264 | |||
1264 | bool | 1265 | bool | |
1265 | ehci_resume(device_t dv, const pmf_qual_t *qual) | 1266 | ehci_resume(device_t dv, const pmf_qual_t *qual) | |
1266 | { | 1267 | { | |
1267 | ehci_softc_t *sc = device_private(dv); | 1268 | ehci_softc_t *sc = device_private(dv); | |
1268 | int i; | 1269 | int i; | |
1269 | uint32_t cmd, hcr; | 1270 | uint32_t cmd, hcr; | |
1270 | 1271 | |||
1271 | /* restore things in case the bios sucks */ | 1272 | /* restore things in case the bios sucks */ | |
1272 | EOWRITE4(sc, EHCI_CTRLDSSEGMENT, 0); | 1273 | EOWRITE4(sc, EHCI_CTRLDSSEGMENT, 0); | |
1273 | EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); | 1274 | EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); | |
1274 | EOWRITE4(sc, EHCI_ASYNCLISTADDR, | 1275 | EOWRITE4(sc, EHCI_ASYNCLISTADDR, | |
1275 | sc->sc_async_head->physaddr | EHCI_LINK_QH); | 1276 | sc->sc_async_head->physaddr | EHCI_LINK_QH); | |
1276 | 1277 | |||
1277 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs & ~EHCI_INTR_PCIE); | 1278 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs & ~EHCI_INTR_PCIE); | |
1278 | 1279 | |||
1279 | EOWRITE4(sc, EHCI_USBCMD, sc->sc_cmd); | 1280 | EOWRITE4(sc, EHCI_USBCMD, sc->sc_cmd); | |
1280 | 1281 | |||
1281 | hcr = 0; | 1282 | hcr = 0; | |
1282 | for (i = 1; i <= sc->sc_noport; i++) { | 1283 | for (i = 1; i <= sc->sc_noport; i++) { | |
1283 | cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR; | 1284 | cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR; | |
1284 | if ((cmd & EHCI_PS_PO) == 0 && | 1285 | if ((cmd & EHCI_PS_PO) == 0 && | |
1285 | (cmd & EHCI_PS_SUSP) == EHCI_PS_SUSP) { | 1286 | (cmd & EHCI_PS_SUSP) == EHCI_PS_SUSP) { | |
1286 | EOWRITE4(sc, EHCI_PORTSC(i), cmd | EHCI_PS_FPR); | 1287 | EOWRITE4(sc, EHCI_PORTSC(i), cmd | EHCI_PS_FPR); | |
1287 | hcr = 1; | 1288 | hcr = 1; | |
1288 | } | 1289 | } | |
1289 | } | 1290 | } | |
1290 | 1291 | |||
1291 | if (hcr) { | 1292 | if (hcr) { | |
1292 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); | 1293 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); | |
1293 | 1294 | |||
1294 | for (i = 1; i <= sc->sc_noport; i++) { | 1295 | for (i = 1; i <= sc->sc_noport; i++) { | |
1295 | cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR; | 1296 | cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR; | |
1296 | if ((cmd & EHCI_PS_PO) == 0 && | 1297 | if ((cmd & EHCI_PS_PO) == 0 && | |
1297 | (cmd & EHCI_PS_SUSP) == EHCI_PS_SUSP) | 1298 | (cmd & EHCI_PS_SUSP) == EHCI_PS_SUSP) | |
1298 | EOWRITE4(sc, EHCI_PORTSC(i), | 1299 | EOWRITE4(sc, EHCI_PORTSC(i), | |
1299 | cmd & ~EHCI_PS_FPR); | 1300 | cmd & ~EHCI_PS_FPR); | |
1300 | } | 1301 | } | |
1301 | } | 1302 | } | |
1302 | 1303 | |||
1303 | EOWRITE4(sc, EHCI_USBCMD, sc->sc_cmd); | 1304 | EOWRITE4(sc, EHCI_USBCMD, sc->sc_cmd); | |
1304 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); | 1305 | EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); | |
1305 | 1306 | |||
1306 | for (i = 0; i < 100; i++) { | 1307 | for (i = 0; i < 100; i++) { | |
1307 | hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; | 1308 | hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; | |
1308 | if (hcr != EHCI_STS_HCH) | 1309 | if (hcr != EHCI_STS_HCH) | |
1309 | break; | 1310 | break; | |
1310 | 1311 | |||
1311 | usb_delay_ms(&sc->sc_bus, 1); | 1312 | usb_delay_ms(&sc->sc_bus, 1); | |
1312 | } | 1313 | } | |
1313 | if (hcr == EHCI_STS_HCH) | 1314 | if (hcr == EHCI_STS_HCH) | |
1314 | printf("%s: config timeout\n", device_xname(dv)); | 1315 | printf("%s: config timeout\n", device_xname(dv)); | |
1315 | 1316 | |||
1316 | return true; | 1317 | return true; | |
1317 | } | 1318 | } | |
1318 | 1319 | |||
1319 | /* | 1320 | /* | |
1320 | * Shut down the controller when the system is going down. | 1321 | * Shut down the controller when the system is going down. | |
1321 | */ | 1322 | */ | |
1322 | bool | 1323 | bool | |
1323 | ehci_shutdown(device_t self, int flags) | 1324 | ehci_shutdown(device_t self, int flags) | |
1324 | { | 1325 | { | |
1325 | ehci_softc_t *sc = device_private(self); | 1326 | ehci_softc_t *sc = device_private(self); | |
1326 | 1327 | |||
1327 | DPRINTF(("ehci_shutdown: stopping the HC\n")); | 1328 | DPRINTF(("ehci_shutdown: stopping the HC\n")); | |
1328 | EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ | 1329 | EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ | |
1329 | EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); | 1330 | EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); | |
1330 | return true; | 1331 | return true; | |
1331 | } | 1332 | } | |
1332 | 1333 | |||
1333 | Static usbd_status | 1334 | Static usbd_status | |
1334 | ehci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) | 1335 | ehci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) | |
1335 | { | 1336 | { | |
1336 | struct ehci_softc *sc = bus->hci_private; | 1337 | struct ehci_softc *sc = bus->hci_private; | |
1337 | usbd_status err; | 1338 | usbd_status err; | |
1338 | 1339 | |||
1339 | err = usb_allocmem(&sc->sc_bus, size, 0, dma); | 1340 | err = usb_allocmem(&sc->sc_bus, size, 0, dma); | |
1340 | if (err == USBD_NOMEM) | 1341 | if (err == USBD_NOMEM) | |
1341 | err = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size); | 1342 | err = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size); | |
1342 | #ifdef EHCI_DEBUG | 1343 | #ifdef EHCI_DEBUG | |
1343 | if (err) | 1344 | if (err) | |
1344 | printf("ehci_allocm: usb_allocmem()=%d\n", err); | 1345 | printf("ehci_allocm: usb_allocmem()=%d\n", err); | |
1345 | #endif | 1346 | #endif | |
1346 | return (err); | 1347 | return (err); | |
1347 | } | 1348 | } | |
1348 | 1349 | |||
1349 | Static void | 1350 | Static void | |
1350 | ehci_freem(struct usbd_bus *bus, usb_dma_t *dma) | 1351 | ehci_freem(struct usbd_bus *bus, usb_dma_t *dma) | |
1351 | { | 1352 | { | |
1352 | struct ehci_softc *sc = bus->hci_private; | 1353 | struct ehci_softc *sc = bus->hci_private; | |
1353 | 1354 | |||
1354 | if (dma->block->flags & USB_DMA_RESERVE) { | 1355 | if (dma->block->flags & USB_DMA_RESERVE) { | |
1355 | usb_reserve_freem(&sc->sc_dma_reserve, | 1356 | usb_reserve_freem(&sc->sc_dma_reserve, | |
1356 | dma); | 1357 | dma); | |
1357 | return; | 1358 | return; | |
1358 | } | 1359 | } | |
1359 | usb_freemem(&sc->sc_bus, dma); | 1360 | usb_freemem(&sc->sc_bus, dma); | |
1360 | } | 1361 | } | |
1361 | 1362 | |||
1362 | Static usbd_xfer_handle | 1363 | Static usbd_xfer_handle | |
1363 | ehci_allocx(struct usbd_bus *bus) | 1364 | ehci_allocx(struct usbd_bus *bus) | |
1364 | { | 1365 | { | |
1365 | struct ehci_softc *sc = bus->hci_private; | 1366 | struct ehci_softc *sc = bus->hci_private; | |
1366 | usbd_xfer_handle xfer; | 1367 | usbd_xfer_handle xfer; | |
1367 | 1368 | |||
1368 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | 1369 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | |
1369 | if (xfer != NULL) { | 1370 | if (xfer != NULL) { | |
1370 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | 1371 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | |
1371 | #ifdef DIAGNOSTIC | 1372 | #ifdef DIAGNOSTIC | |
1372 | if (xfer->busy_free != XFER_FREE) { | 1373 | if (xfer->busy_free != XFER_FREE) { | |
1373 | printf("ehci_allocx: xfer=%p not free, 0x%08x\n", xfer, | 1374 | printf("ehci_allocx: xfer=%p not free, 0x%08x\n", xfer, | |
1374 | xfer->busy_free); | 1375 | xfer->busy_free); | |
1375 | } | 1376 | } | |
1376 | #endif | 1377 | #endif | |
1377 | } else { | 1378 | } else { | |
1378 | xfer = kmem_alloc(sizeof(struct ehci_xfer), KM_SLEEP); | 1379 | xfer = kmem_alloc(sizeof(struct ehci_xfer), KM_SLEEP); | |
1379 | } | 1380 | } | |
1380 | if (xfer != NULL) { | 1381 | if (xfer != NULL) { | |
1381 | memset(xfer, 0, sizeof(struct ehci_xfer)); | 1382 | memset(xfer, 0, sizeof(struct ehci_xfer)); | |
1382 | #ifdef DIAGNOSTIC | 1383 | #ifdef DIAGNOSTIC | |
1383 | EXFER(xfer)->isdone = 1; | 1384 | EXFER(xfer)->isdone = 1; | |
1384 | xfer->busy_free = XFER_BUSY; | 1385 | xfer->busy_free = XFER_BUSY; | |
1385 | #endif | 1386 | #endif | |
1386 | } | 1387 | } | |
1387 | return (xfer); | 1388 | return (xfer); | |
1388 | } | 1389 | } | |
1389 | 1390 | |||
1390 | Static void | 1391 | Static void | |
1391 | ehci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) | 1392 | ehci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) | |
1392 | { | 1393 | { | |
1393 | struct ehci_softc *sc = bus->hci_private; | 1394 | struct ehci_softc *sc = bus->hci_private; | |
1394 | 1395 | |||
1395 | #ifdef DIAGNOSTIC | 1396 | #ifdef DIAGNOSTIC | |
1396 | if (xfer->busy_free != XFER_BUSY) { | 1397 | if (xfer->busy_free != XFER_BUSY) { | |
1397 | printf("ehci_freex: xfer=%p not busy, 0x%08x\n", xfer, | 1398 | printf("ehci_freex: xfer=%p not busy, 0x%08x\n", xfer, | |
1398 | xfer->busy_free); | 1399 | xfer->busy_free); | |
1399 | } | 1400 | } | |
1400 | xfer->busy_free = XFER_FREE; | 1401 | xfer->busy_free = XFER_FREE; | |
1401 | if (!EXFER(xfer)->isdone) { | 1402 | if (!EXFER(xfer)->isdone) { | |
1402 | printf("ehci_freex: !isdone\n"); | 1403 | printf("ehci_freex: !isdone\n"); | |
1403 | } | 1404 | } | |
1404 | #endif | 1405 | #endif | |
1405 | SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next); | 1406 | SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next); | |
1406 | } | 1407 | } | |
1407 | 1408 | |||
1408 | Static void | 1409 | Static void | |
1409 | ehci_get_locks(struct usbd_bus *bus, kmutex_t **intr, kmutex_t **thread) | 1410 | ehci_get_locks(struct usbd_bus *bus, kmutex_t **intr, kmutex_t **thread) | |
1410 | { | 1411 | { | |
1411 | struct ehci_softc *sc = bus->hci_private; | 1412 | struct ehci_softc *sc = bus->hci_private; | |
1412 | 1413 | |||
1413 | *intr = &sc->sc_intr_lock; | 1414 | *intr = &sc->sc_intr_lock; | |
1414 | *thread = &sc->sc_lock; | 1415 | *thread = &sc->sc_lock; | |
1415 | } | 1416 | } | |
1416 | 1417 | |||
1417 | Static void | 1418 | Static void | |
1418 | ehci_device_clear_toggle(usbd_pipe_handle pipe) | 1419 | ehci_device_clear_toggle(usbd_pipe_handle pipe) | |
1419 | { | 1420 | { | |
1420 | struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; | 1421 | struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; | |
1421 | 1422 | |||
1422 | DPRINTF(("ehci_device_clear_toggle: epipe=%p status=0x%x\n", | 1423 | DPRINTF(("ehci_device_clear_toggle: epipe=%p status=0x%x\n", | |
1423 | epipe, epipe->sqh->qh.qh_qtd.qtd_status)); | 1424 | epipe, epipe->sqh->qh.qh_qtd.qtd_status)); | |
1424 | #ifdef EHCI_DEBUG | 1425 | #ifdef EHCI_DEBUG | |
1425 | if (ehcidebug) | 1426 | if (ehcidebug) | |
1426 | usbd_dump_pipe(pipe); | 1427 | usbd_dump_pipe(pipe); | |
1427 | #endif | 1428 | #endif | |
1428 | epipe->nexttoggle = 0; | 1429 | epipe->nexttoggle = 0; | |
1429 | } | 1430 | } | |
1430 | 1431 | |||
1431 | Static void | 1432 | Static void | |
1432 | ehci_noop(usbd_pipe_handle pipe) | 1433 | ehci_noop(usbd_pipe_handle pipe) | |
1433 | { | 1434 | { | |
1434 | } | 1435 | } | |
1435 | 1436 | |||
1436 | #ifdef EHCI_DEBUG | 1437 | #ifdef EHCI_DEBUG | |
1437 | Static void | 1438 | Static void | |
1438 | ehci_dump_regs(ehci_softc_t *sc) | 1439 | ehci_dump_regs(ehci_softc_t *sc) | |
1439 | { | 1440 | { | |
1440 | int i; | 1441 | int i; | |
1441 | printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n", | 1442 | printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n", | |
1442 | EOREAD4(sc, EHCI_USBCMD), | 1443 | EOREAD4(sc, EHCI_USBCMD), | |
1443 | EOREAD4(sc, EHCI_USBSTS), | 1444 | EOREAD4(sc, EHCI_USBSTS), | |
1444 | EOREAD4(sc, EHCI_USBINTR)); | 1445 | EOREAD4(sc, EHCI_USBINTR)); | |
1445 | printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n", | 1446 | printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n", | |
1446 | EOREAD4(sc, EHCI_FRINDEX), | 1447 | EOREAD4(sc, EHCI_FRINDEX), | |
1447 | EOREAD4(sc, EHCI_CTRLDSSEGMENT), | 1448 | EOREAD4(sc, EHCI_CTRLDSSEGMENT), | |
1448 | EOREAD4(sc, EHCI_PERIODICLISTBASE), | 1449 | EOREAD4(sc, EHCI_PERIODICLISTBASE), | |
1449 | EOREAD4(sc, EHCI_ASYNCLISTADDR)); | 1450 | EOREAD4(sc, EHCI_ASYNCLISTADDR)); | |
1450 | for (i = 1; i <= sc->sc_noport; i++) | 1451 | for (i = 1; i <= sc->sc_noport; i++) | |
1451 | printf("port %d status=0x%08x\n", i, | 1452 | printf("port %d status=0x%08x\n", i, | |
1452 | EOREAD4(sc, EHCI_PORTSC(i))); | 1453 | EOREAD4(sc, EHCI_PORTSC(i))); | |
1453 | } | 1454 | } | |
1454 | 1455 | |||
1455 | /* | 1456 | /* | |
1456 | * Unused function - this is meant to be called from a kernel | 1457 | * Unused function - this is meant to be called from a kernel | |
1457 | * debugger. | 1458 | * debugger. | |
1458 | */ | 1459 | */ | |
1459 | void | 1460 | void | |
1460 | ehci_dump(void) | 1461 | ehci_dump(void) | |
1461 | { | 1462 | { | |
1462 | ehci_dump_regs(theehci); | 1463 | ehci_dump_regs(theehci); | |
1463 | } | 1464 | } | |
1464 | 1465 | |||
1465 | Static void | 1466 | Static void | |
1466 | ehci_dump_link(ehci_link_t link, int type) | 1467 | ehci_dump_link(ehci_link_t link, int type) | |
1467 | { | 1468 | { | |
1468 | link = le32toh(link); | 1469 | link = le32toh(link); | |
1469 | printf("0x%08x", link); | 1470 | printf("0x%08x", link); | |
1470 | if (link & EHCI_LINK_TERMINATE) | 1471 | if (link & EHCI_LINK_TERMINATE) | |
1471 | printf("<T>"); | 1472 | printf("<T>"); | |
1472 | else { | 1473 | else { | |
1473 | printf("<"); | 1474 | printf("<"); | |
1474 | if (type) { | 1475 | if (type) { | |
1475 | switch (EHCI_LINK_TYPE(link)) { | 1476 | switch (EHCI_LINK_TYPE(link)) { | |
1476 | case EHCI_LINK_ITD: printf("ITD"); break; | 1477 | case EHCI_LINK_ITD: printf("ITD"); break; | |
1477 | case EHCI_LINK_QH: printf("QH"); break; | 1478 | case EHCI_LINK_QH: printf("QH"); break; | |
1478 | case EHCI_LINK_SITD: printf("SITD"); break; | 1479 | case EHCI_LINK_SITD: printf("SITD"); break; | |
1479 | case EHCI_LINK_FSTN: printf("FSTN"); break; | 1480 | case EHCI_LINK_FSTN: printf("FSTN"); break; | |
1480 | } | 1481 | } | |
1481 | } | 1482 | } | |
1482 | printf(">"); | 1483 | printf(">"); | |
1483 | } | 1484 | } | |
1484 | } | 1485 | } | |
1485 | 1486 | |||
1486 | Static void | 1487 | Static void | |
1487 | ehci_dump_sqtds(ehci_soft_qtd_t *sqtd) | 1488 | ehci_dump_sqtds(ehci_soft_qtd_t *sqtd) | |
1488 | { | 1489 | { | |
1489 | int i; | 1490 | int i; | |
1490 | u_int32_t stop; | 1491 | u_int32_t stop; | |
1491 | 1492 | |||
1492 | stop = 0; | 1493 | stop = 0; | |
1493 | for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) { | 1494 | for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) { | |
1494 | ehci_dump_sqtd(sqtd); | 1495 | ehci_dump_sqtd(sqtd); | |
1495 | usb_syncmem(&sqtd->dma, | 1496 | usb_syncmem(&sqtd->dma, | |
1496 | sqtd->offs + offsetof(ehci_qtd_t, qtd_next), | 1497 | sqtd->offs + offsetof(ehci_qtd_t, qtd_next), | |
1497 | sizeof(sqtd->qtd), | 1498 | sizeof(sqtd->qtd), | |
1498 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1499 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1499 | stop = sqtd->qtd.qtd_next & htole32(EHCI_LINK_TERMINATE); | 1500 | stop = sqtd->qtd.qtd_next & htole32(EHCI_LINK_TERMINATE); | |
1500 | usb_syncmem(&sqtd->dma, | 1501 | usb_syncmem(&sqtd->dma, | |
1501 | sqtd->offs + offsetof(ehci_qtd_t, qtd_next), | 1502 | sqtd->offs + offsetof(ehci_qtd_t, qtd_next), | |
1502 | sizeof(sqtd->qtd), BUS_DMASYNC_PREREAD); | 1503 | sizeof(sqtd->qtd), BUS_DMASYNC_PREREAD); | |
1503 | } | 1504 | } | |
1504 | if (sqtd) | 1505 | if (sqtd) | |
1505 | printf("dump aborted, too many TDs\n"); | 1506 | printf("dump aborted, too many TDs\n"); | |
1506 | } | 1507 | } | |
1507 | 1508 | |||
1508 | Static void | 1509 | Static void | |
1509 | ehci_dump_sqtd(ehci_soft_qtd_t *sqtd) | 1510 | ehci_dump_sqtd(ehci_soft_qtd_t *sqtd) | |
1510 | { | 1511 | { | |
1511 | usb_syncmem(&sqtd->dma, sqtd->offs, | 1512 | usb_syncmem(&sqtd->dma, sqtd->offs, | |
1512 | sizeof(sqtd->qtd), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1513 | sizeof(sqtd->qtd), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1513 | printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr); | 1514 | printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr); | |
1514 | ehci_dump_qtd(&sqtd->qtd); | 1515 | ehci_dump_qtd(&sqtd->qtd); | |
1515 | usb_syncmem(&sqtd->dma, sqtd->offs, | 1516 | usb_syncmem(&sqtd->dma, sqtd->offs, | |
1516 | sizeof(sqtd->qtd), BUS_DMASYNC_PREREAD); | 1517 | sizeof(sqtd->qtd), BUS_DMASYNC_PREREAD); | |
1517 | } | 1518 | } | |
1518 | 1519 | |||
1519 | Static void | 1520 | Static void | |
1520 | ehci_dump_qtd(ehci_qtd_t *qtd) | 1521 | ehci_dump_qtd(ehci_qtd_t *qtd) | |
1521 | { | 1522 | { | |
1522 | u_int32_t s; | 1523 | u_int32_t s; | |
1523 | char sbuf[128]; | 1524 | char sbuf[128]; | |
1524 | 1525 | |||
1525 | printf(" next="); ehci_dump_link(qtd->qtd_next, 0); | 1526 | printf(" next="); ehci_dump_link(qtd->qtd_next, 0); | |
1526 | printf(" altnext="); ehci_dump_link(qtd->qtd_altnext, 0); | 1527 | printf(" altnext="); ehci_dump_link(qtd->qtd_altnext, 0); | |
1527 | printf("\n"); | 1528 | printf("\n"); | |
1528 | s = le32toh(qtd->qtd_status); | 1529 | s = le32toh(qtd->qtd_status); | |
1529 | snprintb(sbuf, sizeof(sbuf), | 1530 | snprintb(sbuf, sizeof(sbuf), | |
1530 | "\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR" | 1531 | "\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR" | |
1531 | "\3MISSED\2SPLIT\1PING", EHCI_QTD_GET_STATUS(s)); | 1532 | "\3MISSED\2SPLIT\1PING", EHCI_QTD_GET_STATUS(s)); | |
1532 | printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n", | 1533 | printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n", | |
1533 | s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s), | 1534 | s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s), | |
1534 | EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s)); | 1535 | EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s)); | |
1535 | printf(" cerr=%d pid=%d stat=0x%s\n", EHCI_QTD_GET_CERR(s), | 1536 | printf(" cerr=%d pid=%d stat=0x%s\n", EHCI_QTD_GET_CERR(s), | |
1536 | EHCI_QTD_GET_PID(s), sbuf); | 1537 | EHCI_QTD_GET_PID(s), sbuf); | |
1537 | for (s = 0; s < 5; s++) | 1538 | for (s = 0; s < 5; s++) | |
1538 | printf(" buffer[%d]=0x%08x\n", s, le32toh(qtd->qtd_buffer[s])); | 1539 | printf(" buffer[%d]=0x%08x\n", s, le32toh(qtd->qtd_buffer[s])); | |
1539 | } | 1540 | } | |
1540 | 1541 | |||
1541 | Static void | 1542 | Static void | |
1542 | ehci_dump_sqh(ehci_soft_qh_t *sqh) | 1543 | ehci_dump_sqh(ehci_soft_qh_t *sqh) | |
1543 | { | 1544 | { | |
1544 | ehci_qh_t *qh = &sqh->qh; | 1545 | ehci_qh_t *qh = &sqh->qh; | |
1545 | u_int32_t endp, endphub; | 1546 | u_int32_t endp, endphub; | |
1546 | 1547 | |||
1547 | usb_syncmem(&sqh->dma, sqh->offs, | 1548 | usb_syncmem(&sqh->dma, sqh->offs, | |
1548 | sizeof(sqh->qh), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1549 | sizeof(sqh->qh), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1549 | printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr); | 1550 | printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr); | |
1550 | printf(" link="); ehci_dump_link(qh->qh_link, 1); printf("\n"); | 1551 | printf(" link="); ehci_dump_link(qh->qh_link, 1); printf("\n"); | |
1551 | endp = le32toh(qh->qh_endp); | 1552 | endp = le32toh(qh->qh_endp); | |
1552 | printf(" endp=0x%08x\n", endp); | 1553 | printf(" endp=0x%08x\n", endp); | |
1553 | printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n", | 1554 | printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n", | |
1554 | EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp), | 1555 | EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp), | |
1555 | EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp), | 1556 | EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp), | |
1556 | EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp)); | 1557 | EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp)); | |
1557 | printf(" mpl=0x%x ctl=%d nrl=%d\n", | 1558 | printf(" mpl=0x%x ctl=%d nrl=%d\n", | |
1558 | EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp), | 1559 | EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp), | |
1559 | EHCI_QH_GET_NRL(endp)); | 1560 | EHCI_QH_GET_NRL(endp)); | |
1560 | endphub = le32toh(qh->qh_endphub); | 1561 | endphub = le32toh(qh->qh_endphub); | |
1561 | printf(" endphub=0x%08x\n", endphub); | 1562 | printf(" endphub=0x%08x\n", endphub); | |
1562 | printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n", | 1563 | printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n", | |
1563 | EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub), | 1564 | EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub), | |
1564 | EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub), | 1565 | EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub), | |
1565 | EHCI_QH_GET_MULT(endphub)); | 1566 | EHCI_QH_GET_MULT(endphub)); | |
1566 | printf(" curqtd="); ehci_dump_link(qh->qh_curqtd, 0); printf("\n"); | 1567 | printf(" curqtd="); ehci_dump_link(qh->qh_curqtd, 0); printf("\n"); | |
1567 | printf("Overlay qTD:\n"); | 1568 | printf("Overlay qTD:\n"); | |
1568 | ehci_dump_qtd(&qh->qh_qtd); | 1569 | ehci_dump_qtd(&qh->qh_qtd); | |
1569 | usb_syncmem(&sqh->dma, sqh->offs, | 1570 | usb_syncmem(&sqh->dma, sqh->offs, | |
1570 | sizeof(sqh->qh), BUS_DMASYNC_PREREAD); | 1571 | sizeof(sqh->qh), BUS_DMASYNC_PREREAD); | |
1571 | } | 1572 | } | |
1572 | 1573 | |||
1573 | #if notyet | 1574 | #if notyet | |
1574 | Static void | 1575 | Static void | |
1575 | ehci_dump_itd(struct ehci_soft_itd *itd) | 1576 | ehci_dump_itd(struct ehci_soft_itd *itd) | |
1576 | { | 1577 | { | |
1577 | ehci_isoc_trans_t t; | 1578 | ehci_isoc_trans_t t; | |
1578 | ehci_isoc_bufr_ptr_t b, b2, b3; | 1579 | ehci_isoc_bufr_ptr_t b, b2, b3; | |
1579 | int i; | 1580 | int i; | |
1580 | 1581 | |||
1581 | printf("ITD: next phys=%X\n", itd->itd.itd_next); | 1582 | printf("ITD: next phys=%X\n", itd->itd.itd_next); | |
1582 | 1583 | |||
1583 | for (i = 0; i < EHCI_ITD_NUFRAMES; i++) { | 1584 | for (i = 0; i < EHCI_ITD_NUFRAMES; i++) { | |
1584 | t = le32toh(itd->itd.itd_ctl[i]); | 1585 | t = le32toh(itd->itd.itd_ctl[i]); | |
1585 | printf("ITDctl %d: stat=%X len=%X ioc=%X pg=%X offs=%X\n", i, | 1586 | printf("ITDctl %d: stat=%X len=%X ioc=%X pg=%X offs=%X\n", i, | |
1586 | EHCI_ITD_GET_STATUS(t), EHCI_ITD_GET_LEN(t), | 1587 | EHCI_ITD_GET_STATUS(t), EHCI_ITD_GET_LEN(t), | |
1587 | EHCI_ITD_GET_IOC(t), EHCI_ITD_GET_PG(t), | 1588 | EHCI_ITD_GET_IOC(t), EHCI_ITD_GET_PG(t), | |
1588 | EHCI_ITD_GET_OFFS(t)); | 1589 | EHCI_ITD_GET_OFFS(t)); | |
1589 | } | 1590 | } | |
1590 | printf("ITDbufr: "); | 1591 | printf("ITDbufr: "); | |
1591 | for (i = 0; i < EHCI_ITD_NBUFFERS; i++) | 1592 | for (i = 0; i < EHCI_ITD_NBUFFERS; i++) | |
1592 | printf("%X,", EHCI_ITD_GET_BPTR(le32toh(itd->itd.itd_bufr[i]))); | 1593 | printf("%X,", EHCI_ITD_GET_BPTR(le32toh(itd->itd.itd_bufr[i]))); | |
1593 | 1594 | |||
1594 | b = le32toh(itd->itd.itd_bufr[0]); | 1595 | b = le32toh(itd->itd.itd_bufr[0]); | |
1595 | b2 = le32toh(itd->itd.itd_bufr[1]); | 1596 | b2 = le32toh(itd->itd.itd_bufr[1]); | |
1596 | b3 = le32toh(itd->itd.itd_bufr[2]); | 1597 | b3 = le32toh(itd->itd.itd_bufr[2]); | |
1597 | printf("\nep=%X daddr=%X dir=%d maxpkt=%X multi=%X\n", | 1598 | printf("\nep=%X daddr=%X dir=%d maxpkt=%X multi=%X\n", | |
1598 | EHCI_ITD_GET_EP(b), EHCI_ITD_GET_DADDR(b), EHCI_ITD_GET_DIR(b2), | 1599 | EHCI_ITD_GET_EP(b), EHCI_ITD_GET_DADDR(b), EHCI_ITD_GET_DIR(b2), | |
1599 | EHCI_ITD_GET_MAXPKT(b2), EHCI_ITD_GET_MULTI(b3)); | 1600 | EHCI_ITD_GET_MAXPKT(b2), EHCI_ITD_GET_MULTI(b3)); | |
1600 | } | 1601 | } | |
1601 | 1602 | |||
1602 | Static void | 1603 | Static void | |
1603 | ehci_dump_sitd(struct ehci_soft_itd *itd) | 1604 | ehci_dump_sitd(struct ehci_soft_itd *itd) | |
1604 | { | 1605 | { | |
1605 | printf("SITD %p next=%p prev=%p xfernext=%p physaddr=%X slot=%d\n", | 1606 | printf("SITD %p next=%p prev=%p xfernext=%p physaddr=%X slot=%d\n", | |
1606 | itd, itd->u.frame_list.next, itd->u.frame_list.prev, | 1607 | itd, itd->u.frame_list.next, itd->u.frame_list.prev, | |
1607 | itd->xfer_next, itd->physaddr, itd->slot); | 1608 | itd->xfer_next, itd->physaddr, itd->slot); | |
1608 | } | 1609 | } | |
1609 | #endif | 1610 | #endif | |
1610 | 1611 | |||
1611 | #ifdef DIAGNOSTIC | 1612 | #ifdef DIAGNOSTIC | |
1612 | Static void | 1613 | Static void | |
1613 | ehci_dump_exfer(struct ehci_xfer *ex) | 1614 | ehci_dump_exfer(struct ehci_xfer *ex) | |
1614 | { | 1615 | { | |
1615 | printf("ehci_dump_exfer: ex=%p sqtdstart=%p end=%p itdstart=%p end=%p isdone=%d\n", ex, ex->sqtdstart, ex->sqtdend, ex->itdstart, ex->itdend, ex->isdone); | 1616 | printf("ehci_dump_exfer: ex=%p sqtdstart=%p end=%p itdstart=%p end=%p isdone=%d\n", ex, ex->sqtdstart, ex->sqtdend, ex->itdstart, ex->itdend, ex->isdone); | |
1616 | } | 1617 | } | |
1617 | #endif | 1618 | #endif | |
1618 | #endif | 1619 | #endif | |
1619 | 1620 | |||
1620 | Static usbd_status | 1621 | Static usbd_status | |
1621 | ehci_open(usbd_pipe_handle pipe) | 1622 | ehci_open(usbd_pipe_handle pipe) | |
1622 | { | 1623 | { | |
1623 | usbd_device_handle dev = pipe->device; | 1624 | usbd_device_handle dev = pipe->device; | |
1624 | ehci_softc_t *sc = dev->bus->hci_private; | 1625 | ehci_softc_t *sc = dev->bus->hci_private; | |
1625 | usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc; | 1626 | usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc; | |
1626 | u_int8_t addr = dev->address; | 1627 | u_int8_t addr = dev->address; | |
1627 | u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE; | 1628 | u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE; | |
1628 | struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; | 1629 | struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; | |
1629 | ehci_soft_qh_t *sqh; | 1630 | ehci_soft_qh_t *sqh; | |
1630 | usbd_status err; | 1631 | usbd_status err; | |
1631 | int ival, speed, naks; | 1632 | int ival, speed, naks; | |
1632 | int hshubaddr, hshubport; | 1633 | int hshubaddr, hshubport; | |
1633 | 1634 | |||
1634 | DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", | 1635 | DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", | |
1635 | pipe, addr, ed->bEndpointAddress, sc->sc_addr)); | 1636 | pipe, addr, ed->bEndpointAddress, sc->sc_addr)); | |
1636 | 1637 | |||
1637 | if (dev->myhsport) { | 1638 | if (dev->myhsport) { | |
1638 | /* | 1639 | /* | |
1639 | * When directly attached FS/LS device while doing embedded | 1640 | * When directly attached FS/LS device while doing embedded | |
1640 | * transaction translations and we are the hub, set the hub | 1641 | * transaction translations and we are the hub, set the hub | |
1641 | * adddress to 0 (us). | 1642 | * adddress to 0 (us). | |
1642 | */ | 1643 | */ | |
1643 | if (!(sc->sc_flags & EHCIF_ETTF) | 1644 | if (!(sc->sc_flags & EHCIF_ETTF) | |
1644 | || (dev->myhsport->parent->address != sc->sc_addr)) { | 1645 | || (dev->myhsport->parent->address != sc->sc_addr)) { | |
1645 | hshubaddr = dev->myhsport->parent->address; | 1646 | hshubaddr = dev->myhsport->parent->address; | |
1646 | } else { | 1647 | } else { | |
1647 | hshubaddr = 0; | 1648 | hshubaddr = 0; | |
1648 | } | 1649 | } | |
1649 | hshubport = dev->myhsport->portno; | 1650 | hshubport = dev->myhsport->portno; | |
1650 | } else { | 1651 | } else { | |
1651 | hshubaddr = 0; | 1652 | hshubaddr = 0; | |
1652 | hshubport = 0; | 1653 | hshubport = 0; | |
1653 | } | 1654 | } | |
1654 | 1655 | |||
1655 | if (sc->sc_dying) | 1656 | if (sc->sc_dying) | |
1656 | return (USBD_IOERROR); | 1657 | return (USBD_IOERROR); | |
1657 | 1658 | |||
1658 | /* toggle state needed for bulk endpoints */ | 1659 | /* toggle state needed for bulk endpoints */ | |
1659 | epipe->nexttoggle = pipe->endpoint->datatoggle; | 1660 | epipe->nexttoggle = pipe->endpoint->datatoggle; | |
1660 | 1661 | |||
1661 | if (addr == sc->sc_addr) { | 1662 | if (addr == sc->sc_addr) { | |
1662 | switch (ed->bEndpointAddress) { | 1663 | switch (ed->bEndpointAddress) { | |
1663 | case USB_CONTROL_ENDPOINT: | 1664 | case USB_CONTROL_ENDPOINT: | |
1664 | pipe->methods = &ehci_root_ctrl_methods; | 1665 | pipe->methods = &ehci_root_ctrl_methods; | |
1665 | break; | 1666 | break; | |
1666 | case UE_DIR_IN | EHCI_INTR_ENDPT: | 1667 | case UE_DIR_IN | EHCI_INTR_ENDPT: | |
1667 | pipe->methods = &ehci_root_intr_methods; | 1668 | pipe->methods = &ehci_root_intr_methods; | |
1668 | break; | 1669 | break; | |
1669 | default: | 1670 | default: | |
1670 | DPRINTF(("ehci_open: bad bEndpointAddress 0x%02x\n", | 1671 | DPRINTF(("ehci_open: bad bEndpointAddress 0x%02x\n", | |
1671 | ed->bEndpointAddress)); | 1672 | ed->bEndpointAddress)); | |
1672 | return (USBD_INVAL); | 1673 | return (USBD_INVAL); | |
1673 | } | 1674 | } | |
1674 | return (USBD_NORMAL_COMPLETION); | 1675 | return (USBD_NORMAL_COMPLETION); | |
1675 | } | 1676 | } | |
1676 | 1677 | |||
1677 | /* XXX All this stuff is only valid for async. */ | 1678 | /* XXX All this stuff is only valid for async. */ | |
1678 | switch (dev->speed) { | 1679 | switch (dev->speed) { | |
1679 | case USB_SPEED_LOW: speed = EHCI_QH_SPEED_LOW; break; | 1680 | case USB_SPEED_LOW: speed = EHCI_QH_SPEED_LOW; break; | |
1680 | case USB_SPEED_FULL: speed = EHCI_QH_SPEED_FULL; break; | 1681 | case USB_SPEED_FULL: speed = EHCI_QH_SPEED_FULL; break; | |
1681 | case USB_SPEED_HIGH: speed = EHCI_QH_SPEED_HIGH; break; | 1682 | case USB_SPEED_HIGH: speed = EHCI_QH_SPEED_HIGH; break; | |
1682 | default: panic("ehci_open: bad device speed %d", dev->speed); | 1683 | default: panic("ehci_open: bad device speed %d", dev->speed); | |
1683 | } | 1684 | } | |
1684 | if (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_ISOCHRONOUS) { | 1685 | if (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_ISOCHRONOUS) { | |
1685 | aprint_error_dev(sc->sc_dev, "error opening low/full speed " | 1686 | aprint_error_dev(sc->sc_dev, "error opening low/full speed " | |
1686 | "isoc endpoint.\n"); | 1687 | "isoc endpoint.\n"); | |
1687 | aprint_normal_dev(sc->sc_dev, "a low/full speed device is " | 1688 | aprint_normal_dev(sc->sc_dev, "a low/full speed device is " | |
1688 | "attached to a USB2 hub, and transaction translations are " | 1689 | "attached to a USB2 hub, and transaction translations are " | |
1689 | "not yet supported.\n"); | 1690 | "not yet supported.\n"); | |
1690 | aprint_normal_dev(sc->sc_dev, "reattach the device to the " | 1691 | aprint_normal_dev(sc->sc_dev, "reattach the device to the " | |
1691 | "root hub instead.\n"); | 1692 | "root hub instead.\n"); | |
1692 | DPRINTFN(1,("ehci_open: hshubaddr=%d hshubport=%d\n", | 1693 | DPRINTFN(1,("ehci_open: hshubaddr=%d hshubport=%d\n", | |
1693 | hshubaddr, hshubport)); | 1694 | hshubaddr, hshubport)); | |
1694 | return USBD_INVAL; | 1695 | return USBD_INVAL; | |
1695 | } | 1696 | } | |
1696 | 1697 | |||
1697 | /* | 1698 | /* | |
1698 | * For interrupt transfer, nak throttling must be disabled, but for | 1699 | * For interrupt transfer, nak throttling must be disabled, but for | |
1699 | * the other transfer type, nak throttling should be enabled from the | 1700 | * the other transfer type, nak throttling should be enabled from the | |
1700 | * veiwpoint that avoids the memory thrashing. | 1701 | * veiwpoint that avoids the memory thrashing. | |
1701 | */ | 1702 | */ | |
1702 | naks = (xfertype == UE_INTERRUPT) ? 0 | 1703 | naks = (xfertype == UE_INTERRUPT) ? 0 | |
1703 | : ((speed == EHCI_QH_SPEED_HIGH) ? 4 : 0); | 1704 | : ((speed == EHCI_QH_SPEED_HIGH) ? 4 : 0); | |
1704 | 1705 | |||
1705 | /* Allocate sqh for everything, save isoc xfers */ | 1706 | /* Allocate sqh for everything, save isoc xfers */ | |
1706 | if (xfertype != UE_ISOCHRONOUS) { | 1707 | if (xfertype != UE_ISOCHRONOUS) { | |
1707 | sqh = ehci_alloc_sqh(sc); | 1708 | sqh = ehci_alloc_sqh(sc); | |
1708 | if (sqh == NULL) | 1709 | if (sqh == NULL) | |
1709 | return (USBD_NOMEM); | 1710 | return (USBD_NOMEM); | |
1710 | /* qh_link filled when the QH is added */ | 1711 | /* qh_link filled when the QH is added */ | |
1711 | sqh->qh.qh_endp = htole32( | 1712 | sqh->qh.qh_endp = htole32( | |
1712 | EHCI_QH_SET_ADDR(addr) | | 1713 | EHCI_QH_SET_ADDR(addr) | | |
1713 | EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) | | 1714 | EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) | | |
1714 | EHCI_QH_SET_EPS(speed) | | 1715 | EHCI_QH_SET_EPS(speed) | | |
1715 | EHCI_QH_DTC | | 1716 | EHCI_QH_DTC | | |
1716 | EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) | | 1717 | EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) | | |
1717 | (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ? | 1718 | (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ? | |
1718 | EHCI_QH_CTL : 0) | | 1719 | EHCI_QH_CTL : 0) | | |
1719 | EHCI_QH_SET_NRL(naks) | 1720 | EHCI_QH_SET_NRL(naks) | |
1720 | ); | 1721 | ); | |
1721 | sqh->qh.qh_endphub = htole32( | 1722 | sqh->qh.qh_endphub = htole32( | |
1722 | EHCI_QH_SET_MULT(1) | | 1723 | EHCI_QH_SET_MULT(1) | | |
1723 | EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x02 : 0) | 1724 | EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x02 : 0) | |
1724 | ); | 1725 | ); | |
1725 | if (speed != EHCI_QH_SPEED_HIGH) | 1726 | if (speed != EHCI_QH_SPEED_HIGH) | |
1726 | sqh->qh.qh_endphub |= htole32( | 1727 | sqh->qh.qh_endphub |= htole32( | |
1727 | EHCI_QH_SET_PORT(hshubport) | | 1728 | EHCI_QH_SET_PORT(hshubport) | | |
1728 | EHCI_QH_SET_HUBA(hshubaddr) | | 1729 | EHCI_QH_SET_HUBA(hshubaddr) | | |
1729 | EHCI_QH_SET_CMASK(0x08) /* XXX */ | 1730 | EHCI_QH_SET_CMASK(0x08) /* XXX */ | |
1730 | ); | 1731 | ); | |
1731 | sqh->qh.qh_curqtd = EHCI_NULL; | 1732 | sqh->qh.qh_curqtd = EHCI_NULL; | |
1732 | /* Fill the overlay qTD */ | 1733 | /* Fill the overlay qTD */ | |
1733 | sqh->qh.qh_qtd.qtd_next = EHCI_NULL; | 1734 | sqh->qh.qh_qtd.qtd_next = EHCI_NULL; | |
1734 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; | 1735 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; | |
1735 | sqh->qh.qh_qtd.qtd_status = htole32(0); | 1736 | sqh->qh.qh_qtd.qtd_status = htole32(0); | |
1736 | 1737 | |||
1737 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 1738 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
1738 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1739 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1739 | epipe->sqh = sqh; | 1740 | epipe->sqh = sqh; | |
1740 | } else { | 1741 | } else { | |
1741 | sqh = NULL; | 1742 | sqh = NULL; | |
1742 | } /*xfertype == UE_ISOC*/ | 1743 | } /*xfertype == UE_ISOC*/ | |
1743 | 1744 | |||
1744 | switch (xfertype) { | 1745 | switch (xfertype) { | |
1745 | case UE_CONTROL: | 1746 | case UE_CONTROL: | |
1746 | err = usb_allocmem(&sc->sc_bus, sizeof(usb_device_request_t), | 1747 | err = usb_allocmem(&sc->sc_bus, sizeof(usb_device_request_t), | |
1747 | 0, &epipe->u.ctl.reqdma); | 1748 | 0, &epipe->u.ctl.reqdma); | |
1748 | #ifdef EHCI_DEBUG | 1749 | #ifdef EHCI_DEBUG | |
1749 | if (err) | 1750 | if (err) | |
1750 | printf("ehci_open: usb_allocmem()=%d\n", err); | 1751 | printf("ehci_open: usb_allocmem()=%d\n", err); | |
1751 | #endif | 1752 | #endif | |
1752 | if (err) | 1753 | if (err) | |
1753 | goto bad; | 1754 | goto bad; | |
1754 | pipe->methods = &ehci_device_ctrl_methods; | 1755 | pipe->methods = &ehci_device_ctrl_methods; | |
1755 | mutex_enter(&sc->sc_lock); | 1756 | mutex_enter(&sc->sc_lock); | |
1756 | ehci_add_qh(sqh, sc->sc_async_head); | 1757 | ehci_add_qh(sc, sqh, sc->sc_async_head); | |
1757 | mutex_exit(&sc->sc_lock); | 1758 | mutex_exit(&sc->sc_lock); | |
1758 | break; | 1759 | break; | |
1759 | case UE_BULK: | 1760 | case UE_BULK: | |
1760 | pipe->methods = &ehci_device_bulk_methods; | 1761 | pipe->methods = &ehci_device_bulk_methods; | |
1761 | mutex_enter(&sc->sc_lock); | 1762 | mutex_enter(&sc->sc_lock); | |
1762 | ehci_add_qh(sqh, sc->sc_async_head); | 1763 | ehci_add_qh(sc, sqh, sc->sc_async_head); | |
1763 | mutex_exit(&sc->sc_lock); | 1764 | mutex_exit(&sc->sc_lock); | |
1764 | break; | 1765 | break; | |
1765 | case UE_INTERRUPT: | 1766 | case UE_INTERRUPT: | |
1766 | pipe->methods = &ehci_device_intr_methods; | 1767 | pipe->methods = &ehci_device_intr_methods; | |
1767 | ival = pipe->interval; | 1768 | ival = pipe->interval; | |
1768 | if (ival == USBD_DEFAULT_INTERVAL) { | 1769 | if (ival == USBD_DEFAULT_INTERVAL) { | |
1769 | if (speed == EHCI_QH_SPEED_HIGH) { | 1770 | if (speed == EHCI_QH_SPEED_HIGH) { | |
1770 | if (ed->bInterval > 16) { | 1771 | if (ed->bInterval > 16) { | |
1771 | /* | 1772 | /* | |
1772 | * illegal with high-speed, but there | 1773 | * illegal with high-speed, but there | |
1773 | * were documentation bugs in the spec, | 1774 | * were documentation bugs in the spec, | |
1774 | * so be generous | 1775 | * so be generous | |
1775 | */ | 1776 | */ | |
1776 | ival = 256; | 1777 | ival = 256; | |
1777 | } else | 1778 | } else | |
1778 | ival = (1 << (ed->bInterval - 1)) / 8; | 1779 | ival = (1 << (ed->bInterval - 1)) / 8; | |
1779 | } else | 1780 | } else | |
1780 | ival = ed->bInterval; | 1781 | ival = ed->bInterval; | |
1781 | } | 1782 | } | |
1782 | err = ehci_device_setintr(sc, sqh, ival); | 1783 | err = ehci_device_setintr(sc, sqh, ival); | |
1783 | if (err) | 1784 | if (err) | |
1784 | goto bad; | 1785 | goto bad; | |
1785 | break; | 1786 | break; | |
1786 | case UE_ISOCHRONOUS: | 1787 | case UE_ISOCHRONOUS: | |
1787 | pipe->methods = &ehci_device_isoc_methods; | 1788 | pipe->methods = &ehci_device_isoc_methods; | |
1788 | if (ed->bInterval == 0 || ed->bInterval > 16) { | 1789 | if (ed->bInterval == 0 || ed->bInterval > 16) { | |
1789 | printf("ehci: opening pipe with invalid bInterval\n"); | 1790 | printf("ehci: opening pipe with invalid bInterval\n"); | |
1790 | err = USBD_INVAL; | 1791 | err = USBD_INVAL; | |
1791 | goto bad; | 1792 | goto bad; | |
1792 | } | 1793 | } | |
1793 | if (UGETW(ed->wMaxPacketSize) == 0) { | 1794 | if (UGETW(ed->wMaxPacketSize) == 0) { | |
1794 | printf("ehci: zero length endpoint open request\n"); | 1795 | printf("ehci: zero length endpoint open request\n"); | |
1795 | err = USBD_INVAL; | 1796 | err = USBD_INVAL; | |
1796 | goto bad; | 1797 | goto bad; | |
1797 | } | 1798 | } | |
1798 | epipe->u.isoc.next_frame = 0; | 1799 | epipe->u.isoc.next_frame = 0; | |
1799 | epipe->u.isoc.cur_xfers = 0; | 1800 | epipe->u.isoc.cur_xfers = 0; | |
1800 | break; | 1801 | break; | |
1801 | default: | 1802 | default: | |
1802 | DPRINTF(("ehci: bad xfer type %d\n", xfertype)); | 1803 | DPRINTF(("ehci: bad xfer type %d\n", xfertype)); | |
1803 | err = USBD_INVAL; | 1804 | err = USBD_INVAL; | |
1804 | goto bad; | 1805 | goto bad; | |
1805 | } | 1806 | } | |
1806 | return (USBD_NORMAL_COMPLETION); | 1807 | return (USBD_NORMAL_COMPLETION); | |
1807 | 1808 | |||
1808 | bad: | 1809 | bad: | |
1809 | if (sqh != NULL) | 1810 | if (sqh != NULL) | |
1810 | ehci_free_sqh(sc, sqh); | 1811 | ehci_free_sqh(sc, sqh); | |
1811 | return (err); | 1812 | return (err); | |
1812 | } | 1813 | } | |
1813 | 1814 | |||
1814 | /* | 1815 | /* | |
1815 | * Add an ED to the schedule. Called at splusb(). | 1816 | * Add an ED to the schedule. Called at splusb(). | |
1816 | */ | 1817 | */ | |
1817 | Static void | 1818 | Static void | |
1818 | ehci_add_qh(ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) | 1819 | ehci_add_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) | |
1819 | { | 1820 | { | |
1820 | SPLUSBCHECK; | 1821 | ||
1822 | KASSERT(mutex_owned(&sc->sc_lock)); | |||
1821 | 1823 | |||
1822 | usb_syncmem(&head->dma, head->offs + offsetof(ehci_qh_t, qh_link), | 1824 | usb_syncmem(&head->dma, head->offs + offsetof(ehci_qh_t, qh_link), | |
1823 | sizeof(head->qh.qh_link), BUS_DMASYNC_POSTWRITE); | 1825 | sizeof(head->qh.qh_link), BUS_DMASYNC_POSTWRITE); | |
1824 | sqh->next = head->next; | 1826 | sqh->next = head->next; | |
1825 | sqh->qh.qh_link = head->qh.qh_link; | 1827 | sqh->qh.qh_link = head->qh.qh_link; | |
1826 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(ehci_qh_t, qh_link), | 1828 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(ehci_qh_t, qh_link), | |
1827 | sizeof(sqh->qh.qh_link), BUS_DMASYNC_PREWRITE); | 1829 | sizeof(sqh->qh.qh_link), BUS_DMASYNC_PREWRITE); | |
1828 | head->next = sqh; | 1830 | head->next = sqh; | |
1829 | head->qh.qh_link = htole32(sqh->physaddr | EHCI_LINK_QH); | 1831 | head->qh.qh_link = htole32(sqh->physaddr | EHCI_LINK_QH); | |
1830 | usb_syncmem(&head->dma, head->offs + offsetof(ehci_qh_t, qh_link), | 1832 | usb_syncmem(&head->dma, head->offs + offsetof(ehci_qh_t, qh_link), | |
1831 | sizeof(head->qh.qh_link), BUS_DMASYNC_PREWRITE); | 1833 | sizeof(head->qh.qh_link), BUS_DMASYNC_PREWRITE); | |
1832 | 1834 | |||
1833 | #ifdef EHCI_DEBUG | 1835 | #ifdef EHCI_DEBUG | |
1834 | if (ehcidebug > 5) { | 1836 | if (ehcidebug > 5) { | |
1835 | printf("ehci_add_qh:\n"); | 1837 | printf("ehci_add_qh:\n"); | |
1836 | ehci_dump_sqh(sqh); | 1838 | ehci_dump_sqh(sqh); | |
1837 | } | 1839 | } | |
1838 | #endif | 1840 | #endif | |
1839 | } | 1841 | } | |
1840 | 1842 | |||
1841 | /* | 1843 | /* | |
1842 | * Remove an ED from the schedule. Called at splusb(). | 1844 | * Remove an ED from the schedule. Called at splusb(). | |
1843 | */ | 1845 | */ | |
1844 | Static void | 1846 | Static void | |
1845 | ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) | 1847 | ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) | |
1846 | { | 1848 | { | |
1847 | ehci_soft_qh_t *p; | 1849 | ehci_soft_qh_t *p; | |
1848 | 1850 | |||
1849 | SPLUSBCHECK; | 1851 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1852 | ||||
1850 | /* XXX */ | 1853 | /* XXX */ | |
1851 | for (p = head; p != NULL && p->next != sqh; p = p->next) | 1854 | for (p = head; p != NULL && p->next != sqh; p = p->next) | |
1852 | ; | 1855 | ; | |
1853 | if (p == NULL) | 1856 | if (p == NULL) | |
1854 | panic("ehci_rem_qh: ED not found"); | 1857 | panic("ehci_rem_qh: ED not found"); | |
1855 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(ehci_qh_t, qh_link), | 1858 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(ehci_qh_t, qh_link), | |
1856 | sizeof(sqh->qh.qh_link), BUS_DMASYNC_POSTWRITE); | 1859 | sizeof(sqh->qh.qh_link), BUS_DMASYNC_POSTWRITE); | |
1857 | p->next = sqh->next; | 1860 | p->next = sqh->next; | |
1858 | p->qh.qh_link = sqh->qh.qh_link; | 1861 | p->qh.qh_link = sqh->qh.qh_link; | |
1859 | usb_syncmem(&p->dma, p->offs + offsetof(ehci_qh_t, qh_link), | 1862 | usb_syncmem(&p->dma, p->offs + offsetof(ehci_qh_t, qh_link), | |
1860 | sizeof(p->qh.qh_link), BUS_DMASYNC_PREWRITE); | 1863 | sizeof(p->qh.qh_link), BUS_DMASYNC_PREWRITE); | |
1861 | 1864 | |||
1862 | ehci_sync_hc(sc); | 1865 | ehci_sync_hc(sc); | |
1863 | } | 1866 | } | |
1864 | 1867 | |||
1865 | Static void | 1868 | Static void | |
1866 | ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd) | 1869 | ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd) | |
1867 | { | 1870 | { | |
1868 | int i; | 1871 | int i; | |
1869 | u_int32_t status; | 1872 | u_int32_t status; | |
1870 | 1873 | |||
1871 | /* Save toggle bit and ping status. */ | 1874 | /* Save toggle bit and ping status. */ | |
1872 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 1875 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
1873 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1876 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1874 | status = sqh->qh.qh_qtd.qtd_status & | 1877 | status = sqh->qh.qh_qtd.qtd_status & | |
1875 | htole32(EHCI_QTD_TOGGLE_MASK | | 1878 | htole32(EHCI_QTD_TOGGLE_MASK | | |
1876 | EHCI_QTD_SET_STATUS(EHCI_QTD_PINGSTATE)); | 1879 | EHCI_QTD_SET_STATUS(EHCI_QTD_PINGSTATE)); | |
1877 | /* Set HALTED to make hw leave it alone. */ | 1880 | /* Set HALTED to make hw leave it alone. */ | |
1878 | sqh->qh.qh_qtd.qtd_status = | 1881 | sqh->qh.qh_qtd.qtd_status = | |
1879 | htole32(EHCI_QTD_SET_STATUS(EHCI_QTD_HALTED)); | 1882 | htole32(EHCI_QTD_SET_STATUS(EHCI_QTD_HALTED)); | |
1880 | usb_syncmem(&sqh->dma, | 1883 | usb_syncmem(&sqh->dma, | |
1881 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | 1884 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | |
1882 | sizeof(sqh->qh.qh_qtd.qtd_status), | 1885 | sizeof(sqh->qh.qh_qtd.qtd_status), | |
1883 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1886 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1884 | sqh->qh.qh_curqtd = 0; | 1887 | sqh->qh.qh_curqtd = 0; | |
1885 | sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr); | 1888 | sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr); | |
1886 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; | 1889 | sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; | |
1887 | for (i = 0; i < EHCI_QTD_NBUFFERS; i++) | 1890 | for (i = 0; i < EHCI_QTD_NBUFFERS; i++) | |
1888 | sqh->qh.qh_qtd.qtd_buffer[i] = 0; | 1891 | sqh->qh.qh_qtd.qtd_buffer[i] = 0; | |
1889 | sqh->sqtd = sqtd; | 1892 | sqh->sqtd = sqtd; | |
1890 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 1893 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
1891 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1894 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1892 | /* Set !HALTED && !ACTIVE to start execution, preserve some fields */ | 1895 | /* Set !HALTED && !ACTIVE to start execution, preserve some fields */ | |
1893 | sqh->qh.qh_qtd.qtd_status = status; | 1896 | sqh->qh.qh_qtd.qtd_status = status; | |
1894 | usb_syncmem(&sqh->dma, | 1897 | usb_syncmem(&sqh->dma, | |
1895 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | 1898 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | |
1896 | sizeof(sqh->qh.qh_qtd.qtd_status), | 1899 | sizeof(sqh->qh.qh_qtd.qtd_status), | |
1897 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1900 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1898 | } | 1901 | } | |
1899 | 1902 | |||
1900 | /* | 1903 | /* | |
1901 | * Ensure that the HC has released all references to the QH. We do this | 1904 | * Ensure that the HC has released all references to the QH. We do this | |
1902 | * by asking for a Async Advance Doorbell interrupt and then we wait for | 1905 | * by asking for a Async Advance Doorbell interrupt and then we wait for | |
1903 | * the interrupt. | 1906 | * the interrupt. | |
1904 | * To make this easier we first obtain exclusive use of the doorbell. | 1907 | * To make this easier we first obtain exclusive use of the doorbell. | |
1905 | */ | 1908 | */ | |
1906 | Static void | 1909 | Static void | |
1907 | ehci_sync_hc(ehci_softc_t *sc) | 1910 | ehci_sync_hc(ehci_softc_t *sc) | |
1908 | { | 1911 | { | |
1909 | int error; | 1912 | int error; | |
1910 | 1913 | |||
1911 | KASSERT(mutex_owned(&sc->sc_lock)); | 1914 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1912 | 1915 | |||
1913 | if (sc->sc_dying) { | 1916 | if (sc->sc_dying) { | |
1914 | DPRINTFN(2,("ehci_sync_hc: dying\n")); | 1917 | DPRINTFN(2,("ehci_sync_hc: dying\n")); | |
1915 | return; | 1918 | return; | |
1916 | } | 1919 | } | |
1917 | DPRINTFN(2,("ehci_sync_hc: enter\n")); | 1920 | DPRINTFN(2,("ehci_sync_hc: enter\n")); | |
1918 | /* ask for doorbell */ | 1921 | /* ask for doorbell */ | |
1919 | EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD); | 1922 | EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD); | |
1920 | DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n", | 1923 | DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n", | |
1921 | EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); | 1924 | EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); | |
1922 | error = cv_timedwait(&sc->sc_doorbell, &sc->sc_lock, hz); /* bell wait */ | 1925 | error = cv_timedwait(&sc->sc_doorbell, &sc->sc_lock, hz); /* bell wait */ | |
1923 | DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n", | 1926 | DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n", | |
1924 | EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); | 1927 | EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); | |
1925 | #ifdef DIAGNOSTIC | 1928 | #ifdef DIAGNOSTIC | |
1926 | if (error) | 1929 | if (error) | |
1927 | printf("ehci_sync_hc: cv_timedwait() = %d\n", error); | 1930 | printf("ehci_sync_hc: cv_timedwait() = %d\n", error); | |
1928 | #endif | 1931 | #endif | |
1929 | DPRINTFN(2,("ehci_sync_hc: exit\n")); | 1932 | DPRINTFN(2,("ehci_sync_hc: exit\n")); | |
1930 | } | 1933 | } | |
1931 | 1934 | |||
1932 | /*Call at splusb*/ | 1935 | /*Call at splusb*/ | |
1933 | Static void | 1936 | Static void | |
1934 | ehci_rem_free_itd_chain(ehci_softc_t *sc, struct ehci_xfer *exfer) | 1937 | ehci_rem_free_itd_chain(ehci_softc_t *sc, struct ehci_xfer *exfer) | |
1935 | { | 1938 | { | |
1936 | struct ehci_soft_itd *itd, *prev; | 1939 | struct ehci_soft_itd *itd, *prev; | |
1937 | 1940 | |||
1938 | prev = NULL; | 1941 | prev = NULL; | |
1939 | 1942 | |||
1940 | if (exfer->itdstart == NULL || exfer->itdend == NULL) | 1943 | if (exfer->itdstart == NULL || exfer->itdend == NULL) | |
1941 | panic("ehci isoc xfer being freed, but with no itd chain\n"); | 1944 | panic("ehci isoc xfer being freed, but with no itd chain\n"); | |
1942 | 1945 | |||
1943 | for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) { | 1946 | for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) { | |
1944 | prev = itd->u.frame_list.prev; | 1947 | prev = itd->u.frame_list.prev; | |
1945 | /* Unlink itd from hardware chain, or frame array */ | 1948 | /* Unlink itd from hardware chain, or frame array */ | |
1946 | if (prev == NULL) { /* We're at the table head */ | 1949 | if (prev == NULL) { /* We're at the table head */ | |
1947 | sc->sc_softitds[itd->slot] = itd->u.frame_list.next; | 1950 | sc->sc_softitds[itd->slot] = itd->u.frame_list.next; | |
1948 | sc->sc_flist[itd->slot] = itd->itd.itd_next; | 1951 | sc->sc_flist[itd->slot] = itd->itd.itd_next; | |
1949 | usb_syncmem(&sc->sc_fldma, | 1952 | usb_syncmem(&sc->sc_fldma, | |
1950 | sizeof(ehci_link_t) * itd->slot, | 1953 | sizeof(ehci_link_t) * itd->slot, | |
1951 | sizeof(ehci_link_t), | 1954 | sizeof(ehci_link_t), | |
1952 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1955 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1953 | 1956 | |||
1954 | if (itd->u.frame_list.next != NULL) | 1957 | if (itd->u.frame_list.next != NULL) | |
1955 | itd->u.frame_list.next->u.frame_list.prev = NULL; | 1958 | itd->u.frame_list.next->u.frame_list.prev = NULL; | |
1956 | } else { | 1959 | } else { | |
1957 | /* XXX this part is untested... */ | 1960 | /* XXX this part is untested... */ | |
1958 | prev->itd.itd_next = itd->itd.itd_next; | 1961 | prev->itd.itd_next = itd->itd.itd_next; | |
1959 | usb_syncmem(&itd->dma, | 1962 | usb_syncmem(&itd->dma, | |
1960 | itd->offs + offsetof(ehci_itd_t, itd_next), | 1963 | itd->offs + offsetof(ehci_itd_t, itd_next), | |
1961 | sizeof(itd->itd.itd_next), BUS_DMASYNC_PREWRITE); | 1964 | sizeof(itd->itd.itd_next), BUS_DMASYNC_PREWRITE); | |
1962 | 1965 | |||
1963 | prev->u.frame_list.next = itd->u.frame_list.next; | 1966 | prev->u.frame_list.next = itd->u.frame_list.next; | |
1964 | if (itd->u.frame_list.next != NULL) | 1967 | if (itd->u.frame_list.next != NULL) | |
1965 | itd->u.frame_list.next->u.frame_list.prev = prev; | 1968 | itd->u.frame_list.next->u.frame_list.prev = prev; | |
1966 | } | 1969 | } | |
1967 | } | 1970 | } | |
1968 | 1971 | |||
1969 | prev = NULL; | 1972 | prev = NULL; | |
1970 | for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) { | 1973 | for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) { | |
1971 | if (prev != NULL) | 1974 | if (prev != NULL) | |
1972 | ehci_free_itd(sc, prev); | 1975 | ehci_free_itd(sc, prev); | |
1973 | prev = itd; | 1976 | prev = itd; | |
1974 | } | 1977 | } | |
1975 | if (prev) | 1978 | if (prev) | |
1976 | ehci_free_itd(sc, prev); | 1979 | ehci_free_itd(sc, prev); | |
1977 | exfer->itdstart = NULL; | 1980 | exfer->itdstart = NULL; | |
1978 | exfer->itdend = NULL; | 1981 | exfer->itdend = NULL; | |
1979 | } | 1982 | } | |
1980 | 1983 | |||
1981 | /***********/ | 1984 | /***********/ | |
1982 | 1985 | |||
1983 | /* | 1986 | /* | |
1984 | * Data structures and routines to emulate the root hub. | 1987 | * Data structures and routines to emulate the root hub. | |
1985 | */ | 1988 | */ | |
1986 | Static usb_device_descriptor_t ehci_devd = { | 1989 | Static usb_device_descriptor_t ehci_devd = { | |
1987 | USB_DEVICE_DESCRIPTOR_SIZE, | 1990 | USB_DEVICE_DESCRIPTOR_SIZE, | |
1988 | UDESC_DEVICE, /* type */ | 1991 | UDESC_DEVICE, /* type */ | |
1989 | {0x00, 0x02}, /* USB version */ | 1992 | {0x00, 0x02}, /* USB version */ | |
1990 | UDCLASS_HUB, /* class */ | 1993 | UDCLASS_HUB, /* class */ | |
1991 | UDSUBCLASS_HUB, /* subclass */ | 1994 | UDSUBCLASS_HUB, /* subclass */ | |
1992 | UDPROTO_HSHUBSTT, /* protocol */ | 1995 | UDPROTO_HSHUBSTT, /* protocol */ | |
1993 | 64, /* max packet */ | 1996 | 64, /* max packet */ | |
1994 | {0},{0},{0x00,0x01}, /* device id */ | 1997 | {0},{0},{0x00,0x01}, /* device id */ | |
1995 | 1,2,0, /* string indicies */ | 1998 | 1,2,0, /* string indicies */ | |
1996 | 1 /* # of configurations */ | 1999 | 1 /* # of configurations */ | |
1997 | }; | 2000 | }; | |
1998 | 2001 | |||
1999 | Static const usb_device_qualifier_t ehci_odevd = { | 2002 | Static const usb_device_qualifier_t ehci_odevd = { | |
2000 | USB_DEVICE_DESCRIPTOR_SIZE, | 2003 | USB_DEVICE_DESCRIPTOR_SIZE, | |
2001 | UDESC_DEVICE_QUALIFIER, /* type */ | 2004 | UDESC_DEVICE_QUALIFIER, /* type */ | |
2002 | {0x00, 0x02}, /* USB version */ | 2005 | {0x00, 0x02}, /* USB version */ | |
2003 | UDCLASS_HUB, /* class */ | 2006 | UDCLASS_HUB, /* class */ | |
2004 | UDSUBCLASS_HUB, /* subclass */ | 2007 | UDSUBCLASS_HUB, /* subclass */ | |
2005 | UDPROTO_FSHUB, /* protocol */ | 2008 | UDPROTO_FSHUB, /* protocol */ | |
2006 | 64, /* max packet */ | 2009 | 64, /* max packet */ | |
2007 | 1, /* # of configurations */ | 2010 | 1, /* # of configurations */ | |
2008 | 0 | 2011 | 0 | |
2009 | }; | 2012 | }; | |
2010 | 2013 | |||
2011 | Static const usb_config_descriptor_t ehci_confd = { | 2014 | Static const usb_config_descriptor_t ehci_confd = { | |
2012 | USB_CONFIG_DESCRIPTOR_SIZE, | 2015 | USB_CONFIG_DESCRIPTOR_SIZE, | |
2013 | UDESC_CONFIG, | 2016 | UDESC_CONFIG, | |
2014 | {USB_CONFIG_DESCRIPTOR_SIZE + | 2017 | {USB_CONFIG_DESCRIPTOR_SIZE + | |
2015 | USB_INTERFACE_DESCRIPTOR_SIZE + | 2018 | USB_INTERFACE_DESCRIPTOR_SIZE + | |
2016 | USB_ENDPOINT_DESCRIPTOR_SIZE}, | 2019 | USB_ENDPOINT_DESCRIPTOR_SIZE}, | |
2017 | 1, | 2020 | 1, | |
2018 | 1, | 2021 | 1, | |
2019 | 0, | 2022 | 0, | |
2020 | UC_ATTR_MBO | UC_SELF_POWERED, | 2023 | UC_ATTR_MBO | UC_SELF_POWERED, | |
2021 | 0 /* max power */ | 2024 | 0 /* max power */ | |
2022 | }; | 2025 | }; | |
2023 | 2026 | |||
2024 | Static const usb_interface_descriptor_t ehci_ifcd = { | 2027 | Static const usb_interface_descriptor_t ehci_ifcd = { | |
2025 | USB_INTERFACE_DESCRIPTOR_SIZE, | 2028 | USB_INTERFACE_DESCRIPTOR_SIZE, | |
2026 | UDESC_INTERFACE, | 2029 | UDESC_INTERFACE, | |
2027 | 0, | 2030 | 0, | |
2028 | 0, | 2031 | 0, | |
2029 | 1, | 2032 | 1, | |
2030 | UICLASS_HUB, | 2033 | UICLASS_HUB, | |
2031 | UISUBCLASS_HUB, | 2034 | UISUBCLASS_HUB, | |
2032 | UIPROTO_HSHUBSTT, | 2035 | UIPROTO_HSHUBSTT, | |
2033 | 0 | 2036 | 0 | |
2034 | }; | 2037 | }; | |
2035 | 2038 | |||
2036 | Static const usb_endpoint_descriptor_t ehci_endpd = { | 2039 | Static const usb_endpoint_descriptor_t ehci_endpd = { | |
2037 | USB_ENDPOINT_DESCRIPTOR_SIZE, | 2040 | USB_ENDPOINT_DESCRIPTOR_SIZE, | |
2038 | UDESC_ENDPOINT, | 2041 | UDESC_ENDPOINT, | |
2039 | UE_DIR_IN | EHCI_INTR_ENDPT, | 2042 | UE_DIR_IN | EHCI_INTR_ENDPT, | |
2040 | UE_INTERRUPT, | 2043 | UE_INTERRUPT, | |
2041 | {8, 0}, /* max packet */ | 2044 | {8, 0}, /* max packet */ | |
2042 | 12 | 2045 | 12 | |
2043 | }; | 2046 | }; | |
2044 | 2047 | |||
2045 | Static const usb_hub_descriptor_t ehci_hubd = { | 2048 | Static const usb_hub_descriptor_t ehci_hubd = { | |
2046 | USB_HUB_DESCRIPTOR_SIZE, | 2049 | USB_HUB_DESCRIPTOR_SIZE, | |
2047 | UDESC_HUB, | 2050 | UDESC_HUB, | |
2048 | 0, | 2051 | 0, | |
2049 | {0,0}, | 2052 | {0,0}, | |
2050 | 0, | 2053 | 0, | |
2051 | 0, | 2054 | 0, | |
2052 | {""}, | 2055 | {""}, | |
2053 | {""}, | 2056 | {""}, | |
2054 | }; | 2057 | }; | |
2055 | 2058 | |||
2056 | /* | 2059 | /* | |
2057 | * Simulate a hardware hub by handling all the necessary requests. | 2060 | * Simulate a hardware hub by handling all the necessary requests. | |
2058 | */ | 2061 | */ | |
2059 | Static usbd_status | 2062 | Static usbd_status | |
2060 | ehci_root_ctrl_transfer(usbd_xfer_handle xfer) | 2063 | ehci_root_ctrl_transfer(usbd_xfer_handle xfer) | |
2061 | { | 2064 | { | |
2062 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2065 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2063 | usbd_status err; | 2066 | usbd_status err; | |
2064 | 2067 | |||
2065 | /* Insert last in queue. */ | 2068 | /* Insert last in queue. */ | |
2066 | mutex_enter(&sc->sc_lock); | 2069 | mutex_enter(&sc->sc_lock); | |
2067 | err = usb_insert_transfer(xfer); | 2070 | err = usb_insert_transfer(xfer); | |
2068 | mutex_exit(&sc->sc_lock); | 2071 | mutex_exit(&sc->sc_lock); | |
2069 | if (err) | 2072 | if (err) | |
2070 | return (err); | 2073 | return (err); | |
2071 | 2074 | |||
2072 | /* Pipe isn't running, start first */ | 2075 | /* Pipe isn't running, start first */ | |
2073 | return (ehci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 2076 | return (ehci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
2074 | } | 2077 | } | |
2075 | 2078 | |||
2076 | Static usbd_status | 2079 | Static usbd_status | |
2077 | ehci_root_ctrl_start(usbd_xfer_handle xfer) | 2080 | ehci_root_ctrl_start(usbd_xfer_handle xfer) | |
2078 | { | 2081 | { | |
2079 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2082 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2080 | usb_device_request_t *req; | 2083 | usb_device_request_t *req; | |
2081 | void *buf = NULL; | 2084 | void *buf = NULL; | |
2082 | int port, i; | 2085 | int port, i; | |
2083 | int len, value, index, l, totlen = 0; | 2086 | int len, value, index, l, totlen = 0; | |
2084 | usb_port_status_t ps; | 2087 | usb_port_status_t ps; | |
2085 | usb_hub_descriptor_t hubd; | 2088 | usb_hub_descriptor_t hubd; | |
2086 | usbd_status err; | 2089 | usbd_status err; | |
2087 | u_int32_t v; | 2090 | u_int32_t v; | |
2088 | 2091 | |||
2089 | if (sc->sc_dying) | 2092 | if (sc->sc_dying) | |
2090 | return (USBD_IOERROR); | 2093 | return (USBD_IOERROR); | |
2091 | 2094 | |||
2092 | #ifdef DIAGNOSTIC | 2095 | #ifdef DIAGNOSTIC | |
2093 | if (!(xfer->rqflags & URQ_REQUEST)) | 2096 | if (!(xfer->rqflags & URQ_REQUEST)) | |
2094 | /* XXX panic */ | 2097 | /* XXX panic */ | |
2095 | return (USBD_INVAL); | 2098 | return (USBD_INVAL); | |
2096 | #endif | 2099 | #endif | |
2097 | req = &xfer->request; | 2100 | req = &xfer->request; | |
2098 | 2101 | |||
2099 | DPRINTFN(4,("ehci_root_ctrl_start: type=0x%02x request=%02x\n", | 2102 | DPRINTFN(4,("ehci_root_ctrl_start: type=0x%02x request=%02x\n", | |
2100 | req->bmRequestType, req->bRequest)); | 2103 | req->bmRequestType, req->bRequest)); | |
2101 | 2104 | |||
2102 | len = UGETW(req->wLength); | 2105 | len = UGETW(req->wLength); | |
2103 | value = UGETW(req->wValue); | 2106 | value = UGETW(req->wValue); | |
2104 | index = UGETW(req->wIndex); | 2107 | index = UGETW(req->wIndex); | |
2105 | 2108 | |||
2106 | if (len != 0) | 2109 | if (len != 0) | |
2107 | buf = KERNADDR(&xfer->dmabuf, 0); | 2110 | buf = KERNADDR(&xfer->dmabuf, 0); | |
2108 | 2111 | |||
2109 | #define C(x,y) ((x) | ((y) << 8)) | 2112 | #define C(x,y) ((x) | ((y) << 8)) | |
2110 | switch(C(req->bRequest, req->bmRequestType)) { | 2113 | switch(C(req->bRequest, req->bmRequestType)) { | |
2111 | case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): | 2114 | case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): | |
2112 | case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): | 2115 | case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): | |
2113 | case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): | 2116 | case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): | |
2114 | /* | 2117 | /* | |
2115 | * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops | 2118 | * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops | |
2116 | * for the integrated root hub. | 2119 | * for the integrated root hub. | |
2117 | */ | 2120 | */ | |
2118 | break; | 2121 | break; | |
2119 | case C(UR_GET_CONFIG, UT_READ_DEVICE): | 2122 | case C(UR_GET_CONFIG, UT_READ_DEVICE): | |
2120 | if (len > 0) { | 2123 | if (len > 0) { | |
2121 | *(u_int8_t *)buf = sc->sc_conf; | 2124 | *(u_int8_t *)buf = sc->sc_conf; | |
2122 | totlen = 1; | 2125 | totlen = 1; | |
2123 | } | 2126 | } | |
2124 | break; | 2127 | break; | |
2125 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): | 2128 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): | |
2126 | DPRINTFN(8,("ehci_root_ctrl_start: wValue=0x%04x\n", value)); | 2129 | DPRINTFN(8,("ehci_root_ctrl_start: wValue=0x%04x\n", value)); | |
2127 | if (len == 0) | 2130 | if (len == 0) | |
2128 | break; | 2131 | break; | |
2129 | switch(value >> 8) { | 2132 | switch(value >> 8) { | |
2130 | case UDESC_DEVICE: | 2133 | case UDESC_DEVICE: | |
2131 | if ((value & 0xff) != 0) { | 2134 | if ((value & 0xff) != 0) { | |
2132 | err = USBD_IOERROR; | 2135 | err = USBD_IOERROR; | |
2133 | goto ret; | 2136 | goto ret; | |
2134 | } | 2137 | } | |
2135 | totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); | 2138 | totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); | |
2136 | USETW(ehci_devd.idVendor, sc->sc_id_vendor); | 2139 | USETW(ehci_devd.idVendor, sc->sc_id_vendor); | |
2137 | memcpy(buf, &ehci_devd, l); | 2140 | memcpy(buf, &ehci_devd, l); | |
2138 | break; | 2141 | break; | |
2139 | /* | 2142 | /* | |
2140 | * We can't really operate at another speed, but the spec says | 2143 | * We can't really operate at another speed, but the spec says | |
2141 | * we need this descriptor. | 2144 | * we need this descriptor. | |
2142 | */ | 2145 | */ | |
2143 | case UDESC_DEVICE_QUALIFIER: | 2146 | case UDESC_DEVICE_QUALIFIER: | |
2144 | if ((value & 0xff) != 0) { | 2147 | if ((value & 0xff) != 0) { | |
2145 | err = USBD_IOERROR; | 2148 | err = USBD_IOERROR; | |
2146 | goto ret; | 2149 | goto ret; | |
2147 | } | 2150 | } | |
2148 | totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); | 2151 | totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); | |
2149 | memcpy(buf, &ehci_odevd, l); | 2152 | memcpy(buf, &ehci_odevd, l); | |
2150 | break; | 2153 | break; | |
2151 | /* | 2154 | /* | |
2152 | * We can't really operate at another speed, but the spec says | 2155 | * We can't really operate at another speed, but the spec says | |
2153 | * we need this descriptor. | 2156 | * we need this descriptor. | |
2154 | */ | 2157 | */ | |
2155 | case UDESC_OTHER_SPEED_CONFIGURATION: | 2158 | case UDESC_OTHER_SPEED_CONFIGURATION: | |
2156 | case UDESC_CONFIG: | 2159 | case UDESC_CONFIG: | |
2157 | if ((value & 0xff) != 0) { | 2160 | if ((value & 0xff) != 0) { | |
2158 | err = USBD_IOERROR; | 2161 | err = USBD_IOERROR; | |
2159 | goto ret; | 2162 | goto ret; | |
2160 | } | 2163 | } | |
2161 | totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE); | 2164 | totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE); | |
2162 | memcpy(buf, &ehci_confd, l); | 2165 | memcpy(buf, &ehci_confd, l); | |
2163 | ((usb_config_descriptor_t *)buf)->bDescriptorType = | 2166 | ((usb_config_descriptor_t *)buf)->bDescriptorType = | |
2164 | value >> 8; | 2167 | value >> 8; | |
2165 | buf = (char *)buf + l; | 2168 | buf = (char *)buf + l; | |
2166 | len -= l; | 2169 | len -= l; | |
2167 | l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE); | 2170 | l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE); | |
2168 | totlen += l; | 2171 | totlen += l; | |
2169 | memcpy(buf, &ehci_ifcd, l); | 2172 | memcpy(buf, &ehci_ifcd, l); | |
2170 | buf = (char *)buf + l; | 2173 | buf = (char *)buf + l; | |
2171 | len -= l; | 2174 | len -= l; | |
2172 | l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE); | 2175 | l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE); | |
2173 | totlen += l; | 2176 | totlen += l; | |
2174 | memcpy(buf, &ehci_endpd, l); | 2177 | memcpy(buf, &ehci_endpd, l); | |
2175 | break; | 2178 | break; | |
2176 | case UDESC_STRING: | 2179 | case UDESC_STRING: | |
2177 | #define sd ((usb_string_descriptor_t *)buf) | 2180 | #define sd ((usb_string_descriptor_t *)buf) | |
2178 | switch (value & 0xff) { | 2181 | switch (value & 0xff) { | |
2179 | case 0: /* Language table */ | 2182 | case 0: /* Language table */ | |
2180 | totlen = usb_makelangtbl(sd, len); | 2183 | totlen = usb_makelangtbl(sd, len); | |
2181 | break; | 2184 | break; | |
2182 | case 1: /* Vendor */ | 2185 | case 1: /* Vendor */ | |
2183 | totlen = usb_makestrdesc(sd, len, | 2186 | totlen = usb_makestrdesc(sd, len, | |
2184 | sc->sc_vendor); | 2187 | sc->sc_vendor); | |
2185 | break; | 2188 | break; | |
2186 | case 2: /* Product */ | 2189 | case 2: /* Product */ | |
2187 | totlen = usb_makestrdesc(sd, len, | 2190 | totlen = usb_makestrdesc(sd, len, | |
2188 | "EHCI root hub"); | 2191 | "EHCI root hub"); | |
2189 | break; | 2192 | break; | |
2190 | } | 2193 | } | |
2191 | #undef sd | 2194 | #undef sd | |
2192 | break; | 2195 | break; | |
2193 | default: | 2196 | default: | |
2194 | err = USBD_IOERROR; | 2197 | err = USBD_IOERROR; | |
2195 | goto ret; | 2198 | goto ret; | |
2196 | } | 2199 | } | |
2197 | break; | 2200 | break; | |
2198 | case C(UR_GET_INTERFACE, UT_READ_INTERFACE): | 2201 | case C(UR_GET_INTERFACE, UT_READ_INTERFACE): | |
2199 | if (len > 0) { | 2202 | if (len > 0) { | |
2200 | *(u_int8_t *)buf = 0; | 2203 | *(u_int8_t *)buf = 0; | |
2201 | totlen = 1; | 2204 | totlen = 1; | |
2202 | } | 2205 | } | |
2203 | break; | 2206 | break; | |
2204 | case C(UR_GET_STATUS, UT_READ_DEVICE): | 2207 | case C(UR_GET_STATUS, UT_READ_DEVICE): | |
2205 | if (len > 1) { | 2208 | if (len > 1) { | |
2206 | USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED); | 2209 | USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED); | |
2207 | totlen = 2; | 2210 | totlen = 2; | |
2208 | } | 2211 | } | |
2209 | break; | 2212 | break; | |
2210 | case C(UR_GET_STATUS, UT_READ_INTERFACE): | 2213 | case C(UR_GET_STATUS, UT_READ_INTERFACE): | |
2211 | case C(UR_GET_STATUS, UT_READ_ENDPOINT): | 2214 | case C(UR_GET_STATUS, UT_READ_ENDPOINT): | |
2212 | if (len > 1) { | 2215 | if (len > 1) { | |
2213 | USETW(((usb_status_t *)buf)->wStatus, 0); | 2216 | USETW(((usb_status_t *)buf)->wStatus, 0); | |
2214 | totlen = 2; | 2217 | totlen = 2; | |
2215 | } | 2218 | } | |
2216 | break; | 2219 | break; | |
2217 | case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): | 2220 | case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): | |
2218 | if (value >= USB_MAX_DEVICES) { | 2221 | if (value >= USB_MAX_DEVICES) { | |
2219 | err = USBD_IOERROR; | 2222 | err = USBD_IOERROR; | |
2220 | goto ret; | 2223 | goto ret; | |
2221 | } | 2224 | } | |
2222 | sc->sc_addr = value; | 2225 | sc->sc_addr = value; | |
2223 | break; | 2226 | break; | |
2224 | case C(UR_SET_CONFIG, UT_WRITE_DEVICE): | 2227 | case C(UR_SET_CONFIG, UT_WRITE_DEVICE): | |
2225 | if (value != 0 && value != 1) { | 2228 | if (value != 0 && value != 1) { | |
2226 | err = USBD_IOERROR; | 2229 | err = USBD_IOERROR; | |
2227 | goto ret; | 2230 | goto ret; | |
2228 | } | 2231 | } | |
2229 | sc->sc_conf = value; | 2232 | sc->sc_conf = value; | |
2230 | break; | 2233 | break; | |
2231 | case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): | 2234 | case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): | |
2232 | break; | 2235 | break; | |
2233 | case C(UR_SET_FEATURE, UT_WRITE_DEVICE): | 2236 | case C(UR_SET_FEATURE, UT_WRITE_DEVICE): | |
2234 | case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): | 2237 | case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): | |
2235 | case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): | 2238 | case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): | |
2236 | err = USBD_IOERROR; | 2239 | err = USBD_IOERROR; | |
2237 | goto ret; | 2240 | goto ret; | |
2238 | case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): | 2241 | case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): | |
2239 | break; | 2242 | break; | |
2240 | case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): | 2243 | case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): | |
2241 | break; | 2244 | break; | |
2242 | /* Hub requests */ | 2245 | /* Hub requests */ | |
2243 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): | 2246 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): | |
2244 | break; | 2247 | break; | |
2245 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): | 2248 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): | |
2246 | DPRINTFN(4, ("ehci_root_ctrl_start: UR_CLEAR_PORT_FEATURE " | 2249 | DPRINTFN(4, ("ehci_root_ctrl_start: UR_CLEAR_PORT_FEATURE " | |
2247 | "port=%d feature=%d\n", | 2250 | "port=%d feature=%d\n", | |
2248 | index, value)); | 2251 | index, value)); | |
2249 | if (index < 1 || index > sc->sc_noport) { | 2252 | if (index < 1 || index > sc->sc_noport) { | |
2250 | err = USBD_IOERROR; | 2253 | err = USBD_IOERROR; | |
2251 | goto ret; | 2254 | goto ret; | |
2252 | } | 2255 | } | |
2253 | port = EHCI_PORTSC(index); | 2256 | port = EHCI_PORTSC(index); | |
2254 | v = EOREAD4(sc, port); | 2257 | v = EOREAD4(sc, port); | |
2255 | DPRINTFN(4, ("ehci_root_ctrl_start: portsc=0x%08x\n", v)); | 2258 | DPRINTFN(4, ("ehci_root_ctrl_start: portsc=0x%08x\n", v)); | |
2256 | v &= ~EHCI_PS_CLEAR; | 2259 | v &= ~EHCI_PS_CLEAR; | |
2257 | switch(value) { | 2260 | switch(value) { | |
2258 | case UHF_PORT_ENABLE: | 2261 | case UHF_PORT_ENABLE: | |
2259 | EOWRITE4(sc, port, v &~ EHCI_PS_PE); | 2262 | EOWRITE4(sc, port, v &~ EHCI_PS_PE); | |
2260 | break; | 2263 | break; | |
2261 | case UHF_PORT_SUSPEND: | 2264 | case UHF_PORT_SUSPEND: | |
2262 | if (!(v & EHCI_PS_SUSP)) /* not suspended */ | 2265 | if (!(v & EHCI_PS_SUSP)) /* not suspended */ | |
2263 | break; | 2266 | break; | |
2264 | v &= ~EHCI_PS_SUSP; | 2267 | v &= ~EHCI_PS_SUSP; | |
2265 | EOWRITE4(sc, port, v | EHCI_PS_FPR); | 2268 | EOWRITE4(sc, port, v | EHCI_PS_FPR); | |
2266 | /* see USB2 spec ch. 7.1.7.7 */ | 2269 | /* see USB2 spec ch. 7.1.7.7 */ | |
2267 | usb_delay_ms(&sc->sc_bus, 20); | 2270 | usb_delay_ms(&sc->sc_bus, 20); | |
2268 | EOWRITE4(sc, port, v); | 2271 | EOWRITE4(sc, port, v); | |
2269 | usb_delay_ms(&sc->sc_bus, 2); | 2272 | usb_delay_ms(&sc->sc_bus, 2); | |
2270 | #ifdef DEBUG | 2273 | #ifdef DEBUG | |
2271 | v = EOREAD4(sc, port); | 2274 | v = EOREAD4(sc, port); | |
2272 | if (v & (EHCI_PS_FPR | EHCI_PS_SUSP)) | 2275 | if (v & (EHCI_PS_FPR | EHCI_PS_SUSP)) | |
2273 | printf("ehci: resume failed: %x\n", v); | 2276 | printf("ehci: resume failed: %x\n", v); | |
2274 | #endif | 2277 | #endif | |
2275 | break; | 2278 | break; | |
2276 | case UHF_PORT_POWER: | 2279 | case UHF_PORT_POWER: | |
2277 | if (sc->sc_hasppc) | 2280 | if (sc->sc_hasppc) | |
2278 | EOWRITE4(sc, port, v &~ EHCI_PS_PP); | 2281 | EOWRITE4(sc, port, v &~ EHCI_PS_PP); | |
2279 | break; | 2282 | break; | |
2280 | case UHF_PORT_TEST: | 2283 | case UHF_PORT_TEST: | |
2281 | DPRINTFN(2,("ehci_root_ctrl_start: clear port test " | 2284 | DPRINTFN(2,("ehci_root_ctrl_start: clear port test " | |
2282 | "%d\n", index)); | 2285 | "%d\n", index)); | |
2283 | break; | 2286 | break; | |
2284 | case UHF_PORT_INDICATOR: | 2287 | case UHF_PORT_INDICATOR: | |
2285 | DPRINTFN(2,("ehci_root_ctrl_start: clear port ind " | 2288 | DPRINTFN(2,("ehci_root_ctrl_start: clear port ind " | |
2286 | "%d\n", index)); | 2289 | "%d\n", index)); | |
2287 | EOWRITE4(sc, port, v &~ EHCI_PS_PIC); | 2290 | EOWRITE4(sc, port, v &~ EHCI_PS_PIC); | |
2288 | break; | 2291 | break; | |
2289 | case UHF_C_PORT_CONNECTION: | 2292 | case UHF_C_PORT_CONNECTION: | |
2290 | EOWRITE4(sc, port, v | EHCI_PS_CSC); | 2293 | EOWRITE4(sc, port, v | EHCI_PS_CSC); | |
2291 | break; | 2294 | break; | |
2292 | case UHF_C_PORT_ENABLE: | 2295 | case UHF_C_PORT_ENABLE: | |
2293 | EOWRITE4(sc, port, v | EHCI_PS_PEC); | 2296 | EOWRITE4(sc, port, v | EHCI_PS_PEC); | |
2294 | break; | 2297 | break; | |
2295 | case UHF_C_PORT_SUSPEND: | 2298 | case UHF_C_PORT_SUSPEND: | |
2296 | /* how? */ | 2299 | /* how? */ | |
2297 | break; | 2300 | break; | |
2298 | case UHF_C_PORT_OVER_CURRENT: | 2301 | case UHF_C_PORT_OVER_CURRENT: | |
2299 | EOWRITE4(sc, port, v | EHCI_PS_OCC); | 2302 | EOWRITE4(sc, port, v | EHCI_PS_OCC); | |
2300 | break; | 2303 | break; | |
2301 | case UHF_C_PORT_RESET: | 2304 | case UHF_C_PORT_RESET: | |
2302 | sc->sc_isreset[index] = 0; | 2305 | sc->sc_isreset[index] = 0; | |
2303 | break; | 2306 | break; | |
2304 | default: | 2307 | default: | |
2305 | err = USBD_IOERROR; | 2308 | err = USBD_IOERROR; | |
2306 | goto ret; | 2309 | goto ret; | |
2307 | } | 2310 | } | |
2308 | #if 0 | 2311 | #if 0 | |
2309 | switch(value) { | 2312 | switch(value) { | |
2310 | case UHF_C_PORT_CONNECTION: | 2313 | case UHF_C_PORT_CONNECTION: | |
2311 | case UHF_C_PORT_ENABLE: | 2314 | case UHF_C_PORT_ENABLE: | |
2312 | case UHF_C_PORT_SUSPEND: | 2315 | case UHF_C_PORT_SUSPEND: | |
2313 | case UHF_C_PORT_OVER_CURRENT: | 2316 | case UHF_C_PORT_OVER_CURRENT: | |
2314 | case UHF_C_PORT_RESET: | 2317 | case UHF_C_PORT_RESET: | |
2315 | default: | 2318 | default: | |
2316 | break; | 2319 | break; | |
2317 | } | 2320 | } | |
2318 | #endif | 2321 | #endif | |
2319 | break; | 2322 | break; | |
2320 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): | 2323 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): | |
2321 | if (len == 0) | 2324 | if (len == 0) | |
2322 | break; | 2325 | break; | |
2323 | if ((value & 0xff) != 0) { | 2326 | if ((value & 0xff) != 0) { | |
2324 | err = USBD_IOERROR; | 2327 | err = USBD_IOERROR; | |
2325 | goto ret; | 2328 | goto ret; | |
2326 | } | 2329 | } | |
2327 | hubd = ehci_hubd; | 2330 | hubd = ehci_hubd; | |
2328 | hubd.bNbrPorts = sc->sc_noport; | 2331 | hubd.bNbrPorts = sc->sc_noport; | |
2329 | v = EOREAD4(sc, EHCI_HCSPARAMS); | 2332 | v = EOREAD4(sc, EHCI_HCSPARAMS); | |
2330 | USETW(hubd.wHubCharacteristics, | 2333 | USETW(hubd.wHubCharacteristics, | |
2331 | EHCI_HCS_PPC(v) ? UHD_PWR_INDIVIDUAL : UHD_PWR_NO_SWITCH | | 2334 | EHCI_HCS_PPC(v) ? UHD_PWR_INDIVIDUAL : UHD_PWR_NO_SWITCH | | |
2332 | EHCI_HCS_P_INDICATOR(EREAD4(sc, EHCI_HCSPARAMS)) | 2335 | EHCI_HCS_P_INDICATOR(EREAD4(sc, EHCI_HCSPARAMS)) | |
2333 | ? UHD_PORT_IND : 0); | 2336 | ? UHD_PORT_IND : 0); | |
2334 | hubd.bPwrOn2PwrGood = 200; /* XXX can't find out? */ | 2337 | hubd.bPwrOn2PwrGood = 200; /* XXX can't find out? */ | |
2335 | for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8) | 2338 | for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8) | |
2336 | hubd.DeviceRemovable[i++] = 0; /* XXX can't find out? */ | 2339 | hubd.DeviceRemovable[i++] = 0; /* XXX can't find out? */ | |
2337 | hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i; | 2340 | hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i; | |
2338 | l = min(len, hubd.bDescLength); | 2341 | l = min(len, hubd.bDescLength); | |
2339 | totlen = l; | 2342 | totlen = l; | |
2340 | memcpy(buf, &hubd, l); | 2343 | memcpy(buf, &hubd, l); | |
2341 | break; | 2344 | break; | |
2342 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): | 2345 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): | |
2343 | if (len != 4) { | 2346 | if (len != 4) { | |
2344 | err = USBD_IOERROR; | 2347 | err = USBD_IOERROR; | |
2345 | goto ret; | 2348 | goto ret; | |
2346 | } | 2349 | } | |
2347 | memset(buf, 0, len); /* ? XXX */ | 2350 | memset(buf, 0, len); /* ? XXX */ | |
2348 | totlen = len; | 2351 | totlen = len; | |
2349 | break; | 2352 | break; | |
2350 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): | 2353 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): | |
2351 | DPRINTFN(8,("ehci_root_ctrl_start: get port status i=%d\n", | 2354 | DPRINTFN(8,("ehci_root_ctrl_start: get port status i=%d\n", | |
2352 | index)); | 2355 | index)); | |
2353 | if (index < 1 || index > sc->sc_noport) { | 2356 | if (index < 1 || index > sc->sc_noport) { | |
2354 | err = USBD_IOERROR; | 2357 | err = USBD_IOERROR; | |
2355 | goto ret; | 2358 | goto ret; | |
2356 | } | 2359 | } | |
2357 | if (len != 4) { | 2360 | if (len != 4) { | |
2358 | err = USBD_IOERROR; | 2361 | err = USBD_IOERROR; | |
2359 | goto ret; | 2362 | goto ret; | |
2360 | } | 2363 | } | |
2361 | v = EOREAD4(sc, EHCI_PORTSC(index)); | 2364 | v = EOREAD4(sc, EHCI_PORTSC(index)); | |
2362 | DPRINTFN(8,("ehci_root_ctrl_start: port status=0x%04x\n", v)); | 2365 | DPRINTFN(8,("ehci_root_ctrl_start: port status=0x%04x\n", v)); | |
2363 | 2366 | |||
2364 | i = UPS_HIGH_SPEED; | 2367 | i = UPS_HIGH_SPEED; | |
2365 | #if 0 | 2368 | #if 0 | |
2366 | if (sc->sc_flags & EHCIF_ETTF) { | 2369 | if (sc->sc_flags & EHCIF_ETTF) { | |
2367 | /* | 2370 | /* | |
2368 | * If we are doing embedded transaction translation, | 2371 | * If we are doing embedded transaction translation, | |
2369 | * then directly attached LS/FS devices are reset by | 2372 | * then directly attached LS/FS devices are reset by | |
2370 | * the EHCI controller itself. PSPD is encoded | 2373 | * the EHCI controller itself. PSPD is encoded | |
2371 | * the same way as in USBSTATUS. | 2374 | * the same way as in USBSTATUS. | |
2372 | */ | 2375 | */ | |
2373 | i = __SHIFTOUT(v, EHCI_PS_PSPD) * UPS_LOW_SPEED; | 2376 | i = __SHIFTOUT(v, EHCI_PS_PSPD) * UPS_LOW_SPEED; | |
2374 | } | 2377 | } | |
2375 | #endif | 2378 | #endif | |
2376 | if (v & EHCI_PS_CS) i |= UPS_CURRENT_CONNECT_STATUS; | 2379 | if (v & EHCI_PS_CS) i |= UPS_CURRENT_CONNECT_STATUS; | |
2377 | if (v & EHCI_PS_PE) i |= UPS_PORT_ENABLED; | 2380 | if (v & EHCI_PS_PE) i |= UPS_PORT_ENABLED; | |
2378 | if (v & EHCI_PS_SUSP) i |= UPS_SUSPEND; | 2381 | if (v & EHCI_PS_SUSP) i |= UPS_SUSPEND; | |
2379 | if (v & EHCI_PS_OCA) i |= UPS_OVERCURRENT_INDICATOR; | 2382 | if (v & EHCI_PS_OCA) i |= UPS_OVERCURRENT_INDICATOR; | |
2380 | if (v & EHCI_PS_PR) i |= UPS_RESET; | 2383 | if (v & EHCI_PS_PR) i |= UPS_RESET; | |
2381 | if (v & EHCI_PS_PP) i |= UPS_PORT_POWER; | 2384 | if (v & EHCI_PS_PP) i |= UPS_PORT_POWER; | |
2382 | if (sc->sc_vendor_port_status) | 2385 | if (sc->sc_vendor_port_status) | |
2383 | i = sc->sc_vendor_port_status(sc, v, i); | 2386 | i = sc->sc_vendor_port_status(sc, v, i); | |
2384 | USETW(ps.wPortStatus, i); | 2387 | USETW(ps.wPortStatus, i); | |
2385 | i = 0; | 2388 | i = 0; | |
2386 | if (v & EHCI_PS_CSC) i |= UPS_C_CONNECT_STATUS; | 2389 | if (v & EHCI_PS_CSC) i |= UPS_C_CONNECT_STATUS; | |
2387 | if (v & EHCI_PS_PEC) i |= UPS_C_PORT_ENABLED; | 2390 | if (v & EHCI_PS_PEC) i |= UPS_C_PORT_ENABLED; | |
2388 | if (v & EHCI_PS_OCC) i |= UPS_C_OVERCURRENT_INDICATOR; | 2391 | if (v & EHCI_PS_OCC) i |= UPS_C_OVERCURRENT_INDICATOR; | |
2389 | if (sc->sc_isreset[index]) i |= UPS_C_PORT_RESET; | 2392 | if (sc->sc_isreset[index]) i |= UPS_C_PORT_RESET; | |
2390 | USETW(ps.wPortChange, i); | 2393 | USETW(ps.wPortChange, i); | |
2391 | l = min(len, sizeof ps); | 2394 | l = min(len, sizeof ps); | |
2392 | memcpy(buf, &ps, l); | 2395 | memcpy(buf, &ps, l); | |
2393 | totlen = l; | 2396 | totlen = l; | |
2394 | break; | 2397 | break; | |
2395 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): | 2398 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): | |
2396 | err = USBD_IOERROR; | 2399 | err = USBD_IOERROR; | |
2397 | goto ret; | 2400 | goto ret; | |
2398 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): | 2401 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): | |
2399 | break; | 2402 | break; | |
2400 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): | 2403 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): | |
2401 | if (index < 1 || index > sc->sc_noport) { | 2404 | if (index < 1 || index > sc->sc_noport) { | |
2402 | err = USBD_IOERROR; | 2405 | err = USBD_IOERROR; | |
2403 | goto ret; | 2406 | goto ret; | |
2404 | } | 2407 | } | |
2405 | port = EHCI_PORTSC(index); | 2408 | port = EHCI_PORTSC(index); | |
2406 | v = EOREAD4(sc, port); | 2409 | v = EOREAD4(sc, port); | |
2407 | DPRINTFN(4, ("ehci_root_ctrl_start: portsc=0x%08x\n", v)); | 2410 | DPRINTFN(4, ("ehci_root_ctrl_start: portsc=0x%08x\n", v)); | |
2408 | v &= ~EHCI_PS_CLEAR; | 2411 | v &= ~EHCI_PS_CLEAR; | |
2409 | switch(value) { | 2412 | switch(value) { | |
2410 | case UHF_PORT_ENABLE: | 2413 | case UHF_PORT_ENABLE: | |
2411 | EOWRITE4(sc, port, v | EHCI_PS_PE); | 2414 | EOWRITE4(sc, port, v | EHCI_PS_PE); | |
2412 | break; | 2415 | break; | |
2413 | case UHF_PORT_SUSPEND: | 2416 | case UHF_PORT_SUSPEND: | |
2414 | EOWRITE4(sc, port, v | EHCI_PS_SUSP); | 2417 | EOWRITE4(sc, port, v | EHCI_PS_SUSP); | |
2415 | break; | 2418 | break; | |
2416 | case UHF_PORT_RESET: | 2419 | case UHF_PORT_RESET: | |
2417 | DPRINTFN(5,("ehci_root_ctrl_start: reset port %d\n", | 2420 | DPRINTFN(5,("ehci_root_ctrl_start: reset port %d\n", | |
2418 | index)); | 2421 | index)); | |
2419 | if (EHCI_PS_IS_LOWSPEED(v) | 2422 | if (EHCI_PS_IS_LOWSPEED(v) | |
2420 | && sc->sc_ncomp > 0 | 2423 | && sc->sc_ncomp > 0 | |
2421 | && !(sc->sc_flags & EHCIF_ETTF)) { | 2424 | && !(sc->sc_flags & EHCIF_ETTF)) { | |
2422 | /* | 2425 | /* | |
2423 | * Low speed device on non-ETTF controller or | 2426 | * Low speed device on non-ETTF controller or | |
2424 | * unaccompanied controller, give up ownership. | 2427 | * unaccompanied controller, give up ownership. | |
2425 | */ | 2428 | */ | |
2426 | ehci_disown(sc, index, 1); | 2429 | ehci_disown(sc, index, 1); | |
2427 | break; | 2430 | break; | |
2428 | } | 2431 | } | |
2429 | /* Start reset sequence. */ | 2432 | /* Start reset sequence. */ | |
2430 | v &= ~ (EHCI_PS_PE | EHCI_PS_PR); | 2433 | v &= ~ (EHCI_PS_PE | EHCI_PS_PR); | |
2431 | EOWRITE4(sc, port, v | EHCI_PS_PR); | 2434 | EOWRITE4(sc, port, v | EHCI_PS_PR); | |
2432 | /* Wait for reset to complete. */ | 2435 | /* Wait for reset to complete. */ | |
2433 | usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY); | 2436 | usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY); | |
2434 | if (sc->sc_dying) { | 2437 | if (sc->sc_dying) { | |
2435 | err = USBD_IOERROR; | 2438 | err = USBD_IOERROR; | |
2436 | goto ret; | 2439 | goto ret; | |
2437 | } | 2440 | } | |
2438 | /* | 2441 | /* | |
2439 | * An embedded transaction translater will automatically | 2442 | * An embedded transaction translater will automatically | |
2440 | * terminate the reset sequence so there's no need to | 2443 | * terminate the reset sequence so there's no need to | |
2441 | * it. | 2444 | * it. | |
2442 | */ | 2445 | */ | |
2443 | v = EOREAD4(sc, port); | 2446 | v = EOREAD4(sc, port); | |
2444 | if (v & EHCI_PS_PR) { | 2447 | if (v & EHCI_PS_PR) { | |
2445 | /* Terminate reset sequence. */ | 2448 | /* Terminate reset sequence. */ | |
2446 | EOWRITE4(sc, port, v & ~EHCI_PS_PR); | 2449 | EOWRITE4(sc, port, v & ~EHCI_PS_PR); | |
2447 | /* Wait for HC to complete reset. */ | 2450 | /* Wait for HC to complete reset. */ | |
2448 | usb_delay_ms(&sc->sc_bus, | 2451 | usb_delay_ms(&sc->sc_bus, | |
2449 | EHCI_PORT_RESET_COMPLETE); | 2452 | EHCI_PORT_RESET_COMPLETE); | |
2450 | if (sc->sc_dying) { | 2453 | if (sc->sc_dying) { | |
2451 | err = USBD_IOERROR; | 2454 | err = USBD_IOERROR; | |
2452 | goto ret; | 2455 | goto ret; | |
2453 | } | 2456 | } | |
2454 | } | 2457 | } | |
2455 | 2458 | |||
2456 | v = EOREAD4(sc, port); | 2459 | v = EOREAD4(sc, port); | |
2457 | DPRINTF(("ehci after reset, status=0x%08x\n", v)); | 2460 | DPRINTF(("ehci after reset, status=0x%08x\n", v)); | |
2458 | if (v & EHCI_PS_PR) { | 2461 | if (v & EHCI_PS_PR) { | |
2459 | printf("%s: port reset timeout\n", | 2462 | printf("%s: port reset timeout\n", | |
2460 | device_xname(sc->sc_dev)); | 2463 | device_xname(sc->sc_dev)); | |
2461 | return (USBD_TIMEOUT); | 2464 | return (USBD_TIMEOUT); | |
2462 | } | 2465 | } | |
2463 | if (!(v & EHCI_PS_PE)) { | 2466 | if (!(v & EHCI_PS_PE)) { | |
2464 | /* Not a high speed device, give up ownership.*/ | 2467 | /* Not a high speed device, give up ownership.*/ | |
2465 | ehci_disown(sc, index, 0); | 2468 | ehci_disown(sc, index, 0); | |
2466 | break; | 2469 | break; | |
2467 | } | 2470 | } | |
2468 | sc->sc_isreset[index] = 1; | 2471 | sc->sc_isreset[index] = 1; | |
2469 | DPRINTF(("ehci port %d reset, status = 0x%08x\n", | 2472 | DPRINTF(("ehci port %d reset, status = 0x%08x\n", | |
2470 | index, v)); | 2473 | index, v)); | |
2471 | break; | 2474 | break; | |
2472 | case UHF_PORT_POWER: | 2475 | case UHF_PORT_POWER: | |
2473 | DPRINTFN(2,("ehci_root_ctrl_start: set port power " | 2476 | DPRINTFN(2,("ehci_root_ctrl_start: set port power " | |
2474 | "%d (has PPC = %d)\n", index, | 2477 | "%d (has PPC = %d)\n", index, | |
2475 | sc->sc_hasppc)); | 2478 | sc->sc_hasppc)); | |
2476 | if (sc->sc_hasppc) | 2479 | if (sc->sc_hasppc) | |
2477 | EOWRITE4(sc, port, v | EHCI_PS_PP); | 2480 | EOWRITE4(sc, port, v | EHCI_PS_PP); | |
2478 | break; | 2481 | break; | |
2479 | case UHF_PORT_TEST: | 2482 | case UHF_PORT_TEST: | |
2480 | DPRINTFN(2,("ehci_root_ctrl_start: set port test " | 2483 | DPRINTFN(2,("ehci_root_ctrl_start: set port test " | |
2481 | "%d\n", index)); | 2484 | "%d\n", index)); | |
2482 | break; | 2485 | break; | |
2483 | case UHF_PORT_INDICATOR: | 2486 | case UHF_PORT_INDICATOR: | |
2484 | DPRINTFN(2,("ehci_root_ctrl_start: set port ind " | 2487 | DPRINTFN(2,("ehci_root_ctrl_start: set port ind " | |
2485 | "%d\n", index)); | 2488 | "%d\n", index)); | |
2486 | EOWRITE4(sc, port, v | EHCI_PS_PIC); | 2489 | EOWRITE4(sc, port, v | EHCI_PS_PIC); | |
2487 | break; | 2490 | break; | |
2488 | default: | 2491 | default: | |
2489 | err = USBD_IOERROR; | 2492 | err = USBD_IOERROR; | |
2490 | goto ret; | 2493 | goto ret; | |
2491 | } | 2494 | } | |
2492 | break; | 2495 | break; | |
2493 | case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER): | 2496 | case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER): | |
2494 | case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER): | 2497 | case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER): | |
2495 | case C(UR_GET_TT_STATE, UT_READ_CLASS_OTHER): | 2498 | case C(UR_GET_TT_STATE, UT_READ_CLASS_OTHER): | |
2496 | case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER): | 2499 | case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER): | |
2497 | break; | 2500 | break; | |
2498 | default: | 2501 | default: | |
2499 | err = USBD_IOERROR; | 2502 | err = USBD_IOERROR; | |
2500 | goto ret; | 2503 | goto ret; | |
2501 | } | 2504 | } | |
2502 | xfer->actlen = totlen; | 2505 | xfer->actlen = totlen; | |
2503 | err = USBD_NORMAL_COMPLETION; | 2506 | err = USBD_NORMAL_COMPLETION; | |
2504 | ret: | 2507 | ret: | |
2505 | mutex_enter(&sc->sc_lock); | 2508 | mutex_enter(&sc->sc_lock); | |
2506 | xfer->status = err; | 2509 | xfer->status = err; | |
2507 | usb_transfer_complete(xfer); | 2510 | usb_transfer_complete(xfer); | |
2508 | mutex_exit(&sc->sc_lock); | 2511 | mutex_exit(&sc->sc_lock); | |
2509 | return (USBD_IN_PROGRESS); | 2512 | return (USBD_IN_PROGRESS); | |
2510 | } | 2513 | } | |
2511 | 2514 | |||
2512 | Static void | 2515 | Static void | |
2513 | ehci_disown(ehci_softc_t *sc, int index, int lowspeed) | 2516 | ehci_disown(ehci_softc_t *sc, int index, int lowspeed) | |
2514 | { | 2517 | { | |
2515 | int port; | 2518 | int port; | |
2516 | u_int32_t v; | 2519 | u_int32_t v; | |
2517 | 2520 | |||
2518 | DPRINTF(("ehci_disown: index=%d lowspeed=%d\n", index, lowspeed)); | 2521 | DPRINTF(("ehci_disown: index=%d lowspeed=%d\n", index, lowspeed)); | |
2519 | #ifdef DIAGNOSTIC | 2522 | #ifdef DIAGNOSTIC | |
2520 | if (sc->sc_npcomp != 0) { | 2523 | if (sc->sc_npcomp != 0) { | |
2521 | int i = (index-1) / sc->sc_npcomp; | 2524 | int i = (index-1) / sc->sc_npcomp; | |
2522 | if (i >= sc->sc_ncomp) | 2525 | if (i >= sc->sc_ncomp) | |
2523 | printf("%s: strange port\n", | 2526 | printf("%s: strange port\n", | |
2524 | device_xname(sc->sc_dev)); | 2527 | device_xname(sc->sc_dev)); | |
2525 | else | 2528 | else | |
2526 | printf("%s: handing over %s speed device on " | 2529 | printf("%s: handing over %s speed device on " | |
2527 | "port %d to %s\n", | 2530 | "port %d to %s\n", | |
2528 | device_xname(sc->sc_dev), | 2531 | device_xname(sc->sc_dev), | |
2529 | lowspeed ? "low" : "full", | 2532 | lowspeed ? "low" : "full", | |
2530 | index, device_xname(sc->sc_comps[i])); | 2533 | index, device_xname(sc->sc_comps[i])); | |
2531 | } else { | 2534 | } else { | |
2532 | printf("%s: npcomp == 0\n", device_xname(sc->sc_dev)); | 2535 | printf("%s: npcomp == 0\n", device_xname(sc->sc_dev)); | |
2533 | } | 2536 | } | |
2534 | #endif | 2537 | #endif | |
2535 | port = EHCI_PORTSC(index); | 2538 | port = EHCI_PORTSC(index); | |
2536 | v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR; | 2539 | v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR; | |
2537 | EOWRITE4(sc, port, v | EHCI_PS_PO); | 2540 | EOWRITE4(sc, port, v | EHCI_PS_PO); | |
2538 | } | 2541 | } | |
2539 | 2542 | |||
2540 | /* Abort a root control request. */ | 2543 | /* Abort a root control request. */ | |
2541 | Static void | 2544 | Static void | |
2542 | ehci_root_ctrl_abort(usbd_xfer_handle xfer) | 2545 | ehci_root_ctrl_abort(usbd_xfer_handle xfer) | |
2543 | { | 2546 | { | |
2544 | /* Nothing to do, all transfers are synchronous. */ | 2547 | /* Nothing to do, all transfers are synchronous. */ | |
2545 | } | 2548 | } | |
2546 | 2549 | |||
2547 | /* Close the root pipe. */ | 2550 | /* Close the root pipe. */ | |
2548 | Static void | 2551 | Static void | |
2549 | ehci_root_ctrl_close(usbd_pipe_handle pipe) | 2552 | ehci_root_ctrl_close(usbd_pipe_handle pipe) | |
2550 | { | 2553 | { | |
2551 | DPRINTF(("ehci_root_ctrl_close\n")); | 2554 | DPRINTF(("ehci_root_ctrl_close\n")); | |
2552 | /* Nothing to do. */ | 2555 | /* Nothing to do. */ | |
2553 | } | 2556 | } | |
2554 | 2557 | |||
2555 | Static void | 2558 | Static void | |
2556 | ehci_root_intr_done(usbd_xfer_handle xfer) | 2559 | ehci_root_intr_done(usbd_xfer_handle xfer) | |
2557 | { | 2560 | { | |
2558 | xfer->hcpriv = NULL; | 2561 | xfer->hcpriv = NULL; | |
2559 | } | 2562 | } | |
2560 | 2563 | |||
2561 | Static usbd_status | 2564 | Static usbd_status | |
2562 | ehci_root_intr_transfer(usbd_xfer_handle xfer) | 2565 | ehci_root_intr_transfer(usbd_xfer_handle xfer) | |
2563 | { | 2566 | { | |
2564 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2567 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2565 | usbd_status err; | 2568 | usbd_status err; | |
2566 | 2569 | |||
2567 | /* Insert last in queue. */ | 2570 | /* Insert last in queue. */ | |
2568 | mutex_enter(&sc->sc_lock); | 2571 | mutex_enter(&sc->sc_lock); | |
2569 | err = usb_insert_transfer(xfer); | 2572 | err = usb_insert_transfer(xfer); | |
2570 | mutex_exit(&sc->sc_lock); | 2573 | mutex_exit(&sc->sc_lock); | |
2571 | if (err) | 2574 | if (err) | |
2572 | return (err); | 2575 | return (err); | |
2573 | 2576 | |||
2574 | /* Pipe isn't running, start first */ | 2577 | /* Pipe isn't running, start first */ | |
2575 | return (ehci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 2578 | return (ehci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
2576 | } | 2579 | } | |
2577 | 2580 | |||
2578 | Static usbd_status | 2581 | Static usbd_status | |
2579 | ehci_root_intr_start(usbd_xfer_handle xfer) | 2582 | ehci_root_intr_start(usbd_xfer_handle xfer) | |
2580 | { | 2583 | { | |
2581 | usbd_pipe_handle pipe = xfer->pipe; | 2584 | usbd_pipe_handle pipe = xfer->pipe; | |
2582 | ehci_softc_t *sc = pipe->device->bus->hci_private; | 2585 | ehci_softc_t *sc = pipe->device->bus->hci_private; | |
2583 | 2586 | |||
2584 | if (sc->sc_dying) | 2587 | if (sc->sc_dying) | |
2585 | return (USBD_IOERROR); | 2588 | return (USBD_IOERROR); | |
2586 | 2589 | |||
2587 | mutex_enter(&sc->sc_lock); | 2590 | mutex_enter(&sc->sc_lock); | |
2588 | sc->sc_intrxfer = xfer; | 2591 | sc->sc_intrxfer = xfer; | |
2589 | mutex_exit(&sc->sc_lock); | 2592 | mutex_exit(&sc->sc_lock); | |
2590 | 2593 | |||
2591 | return (USBD_IN_PROGRESS); | 2594 | return (USBD_IN_PROGRESS); | |
2592 | } | 2595 | } | |
2593 | 2596 | |||
2594 | /* Abort a root interrupt request. */ | 2597 | /* Abort a root interrupt request. */ | |
2595 | Static void | 2598 | Static void | |
2596 | ehci_root_intr_abort(usbd_xfer_handle xfer) | 2599 | ehci_root_intr_abort(usbd_xfer_handle xfer) | |
2597 | { | 2600 | { | |
2598 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2601 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2599 | 2602 | |||
2600 | mutex_enter(&sc->sc_lock); | 2603 | mutex_enter(&sc->sc_lock); | |
2601 | if (xfer->pipe->intrxfer == xfer) { | 2604 | if (xfer->pipe->intrxfer == xfer) { | |
2602 | DPRINTF(("ehci_root_intr_abort: remove\n")); | 2605 | DPRINTF(("ehci_root_intr_abort: remove\n")); | |
2603 | xfer->pipe->intrxfer = NULL; | 2606 | xfer->pipe->intrxfer = NULL; | |
2604 | } | 2607 | } | |
2605 | xfer->status = USBD_CANCELLED; | 2608 | xfer->status = USBD_CANCELLED; | |
2606 | usb_transfer_complete(xfer); | 2609 | usb_transfer_complete(xfer); | |
2607 | mutex_exit(&sc->sc_lock); | 2610 | mutex_exit(&sc->sc_lock); | |
2608 | } | 2611 | } | |
2609 | 2612 | |||
2610 | /* Close the root pipe. */ | 2613 | /* Close the root pipe. */ | |
2611 | Static void | 2614 | Static void | |
2612 | ehci_root_intr_close(usbd_pipe_handle pipe) | 2615 | ehci_root_intr_close(usbd_pipe_handle pipe) | |
2613 | { | 2616 | { | |
2614 | ehci_softc_t *sc = pipe->device->bus->hci_private; | 2617 | ehci_softc_t *sc = pipe->device->bus->hci_private; | |
2615 | 2618 | |||
2616 | DPRINTF(("ehci_root_intr_close\n")); | 2619 | DPRINTF(("ehci_root_intr_close\n")); | |
2617 | 2620 | |||
2618 | mutex_enter(&sc->sc_lock); | 2621 | mutex_enter(&sc->sc_lock); | |
2619 | sc->sc_intrxfer = NULL; | 2622 | sc->sc_intrxfer = NULL; | |
2620 | mutex_exit(&sc->sc_lock); | 2623 | mutex_exit(&sc->sc_lock); | |
2621 | } | 2624 | } | |
2622 | 2625 | |||
2623 | Static void | 2626 | Static void | |
2624 | ehci_root_ctrl_done(usbd_xfer_handle xfer) | 2627 | ehci_root_ctrl_done(usbd_xfer_handle xfer) | |
2625 | { | 2628 | { | |
2626 | xfer->hcpriv = NULL; | 2629 | xfer->hcpriv = NULL; | |
2627 | } | 2630 | } | |
2628 | 2631 | |||
2629 | /************************/ | 2632 | /************************/ | |
2630 | 2633 | |||
2631 | Static ehci_soft_qh_t * | 2634 | Static ehci_soft_qh_t * | |
2632 | ehci_alloc_sqh(ehci_softc_t *sc) | 2635 | ehci_alloc_sqh(ehci_softc_t *sc) | |
2633 | { | 2636 | { | |
2634 | ehci_soft_qh_t *sqh; | 2637 | ehci_soft_qh_t *sqh; | |
2635 | usbd_status err; | 2638 | usbd_status err; | |
2636 | int i, offs; | 2639 | int i, offs; | |
2637 | usb_dma_t dma; | 2640 | usb_dma_t dma; | |
2638 | 2641 | |||
2639 | if (sc->sc_freeqhs == NULL) { | 2642 | if (sc->sc_freeqhs == NULL) { | |
2640 | DPRINTFN(2, ("ehci_alloc_sqh: allocating chunk\n")); | 2643 | DPRINTFN(2, ("ehci_alloc_sqh: allocating chunk\n")); | |
2641 | err = usb_allocmem(&sc->sc_bus, EHCI_SQH_SIZE * EHCI_SQH_CHUNK, | 2644 | err = usb_allocmem(&sc->sc_bus, EHCI_SQH_SIZE * EHCI_SQH_CHUNK, | |
2642 | EHCI_PAGE_SIZE, &dma); | 2645 | EHCI_PAGE_SIZE, &dma); | |
2643 | #ifdef EHCI_DEBUG | 2646 | #ifdef EHCI_DEBUG | |
2644 | if (err) | 2647 | if (err) | |
2645 | printf("ehci_alloc_sqh: usb_allocmem()=%d\n", err); | 2648 | printf("ehci_alloc_sqh: usb_allocmem()=%d\n", err); | |
2646 | #endif | 2649 | #endif | |
2647 | if (err) | 2650 | if (err) | |
2648 | return (NULL); | 2651 | return (NULL); | |
2649 | for(i = 0; i < EHCI_SQH_CHUNK; i++) { | 2652 | for(i = 0; i < EHCI_SQH_CHUNK; i++) { | |
2650 | offs = i * EHCI_SQH_SIZE; | 2653 | offs = i * EHCI_SQH_SIZE; | |
2651 | sqh = KERNADDR(&dma, offs); | 2654 | sqh = KERNADDR(&dma, offs); | |
2652 | sqh->physaddr = DMAADDR(&dma, offs); | 2655 | sqh->physaddr = DMAADDR(&dma, offs); | |
2653 | sqh->dma = dma; | 2656 | sqh->dma = dma; | |
2654 | sqh->offs = offs; | 2657 | sqh->offs = offs; | |
2655 | sqh->next = sc->sc_freeqhs; | 2658 | sqh->next = sc->sc_freeqhs; | |
2656 | sc->sc_freeqhs = sqh; | 2659 | sc->sc_freeqhs = sqh; | |
2657 | } | 2660 | } | |
2658 | } | 2661 | } | |
2659 | sqh = sc->sc_freeqhs; | 2662 | sqh = sc->sc_freeqhs; | |
2660 | sc->sc_freeqhs = sqh->next; | 2663 | sc->sc_freeqhs = sqh->next; | |
2661 | memset(&sqh->qh, 0, sizeof(ehci_qh_t)); | 2664 | memset(&sqh->qh, 0, sizeof(ehci_qh_t)); | |
2662 | sqh->next = NULL; | 2665 | sqh->next = NULL; | |
2663 | return (sqh); | 2666 | return (sqh); | |
2664 | } | 2667 | } | |
2665 | 2668 | |||
2666 | Static void | 2669 | Static void | |
2667 | ehci_free_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh) | 2670 | ehci_free_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh) | |
2668 | { | 2671 | { | |
2669 | sqh->next = sc->sc_freeqhs; | 2672 | sqh->next = sc->sc_freeqhs; | |
2670 | sc->sc_freeqhs = sqh; | 2673 | sc->sc_freeqhs = sqh; | |
2671 | } | 2674 | } | |
2672 | 2675 | |||
2673 | Static ehci_soft_qtd_t * | 2676 | Static ehci_soft_qtd_t * | |
2674 | ehci_alloc_sqtd(ehci_softc_t *sc) | 2677 | ehci_alloc_sqtd(ehci_softc_t *sc) | |
2675 | { | 2678 | { | |
2676 | ehci_soft_qtd_t *sqtd = NULL; | 2679 | ehci_soft_qtd_t *sqtd = NULL; | |
2677 | usbd_status err; | 2680 | usbd_status err; | |
2678 | int i, offs; | 2681 | int i, offs; | |
2679 | usb_dma_t dma; | 2682 | usb_dma_t dma; | |
2680 | 2683 | |||
2681 | if (sc->sc_freeqtds == NULL) { | 2684 | if (sc->sc_freeqtds == NULL) { | |
2682 | DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n")); | 2685 | DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n")); | |
2683 | 2686 | |||
2684 | err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK, | 2687 | err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK, | |
2685 | EHCI_PAGE_SIZE, &dma); | 2688 | EHCI_PAGE_SIZE, &dma); | |
2686 | #ifdef EHCI_DEBUG | 2689 | #ifdef EHCI_DEBUG | |
2687 | if (err) | 2690 | if (err) | |
2688 | printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err); | 2691 | printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err); | |
2689 | #endif | 2692 | #endif | |
2690 | if (err) | 2693 | if (err) | |
2691 | goto done; | 2694 | goto done; | |
2692 | 2695 | |||
2693 | for(i = 0; i < EHCI_SQTD_CHUNK; i++) { | 2696 | for(i = 0; i < EHCI_SQTD_CHUNK; i++) { | |
2694 | offs = i * EHCI_SQTD_SIZE; | 2697 | offs = i * EHCI_SQTD_SIZE; | |
2695 | sqtd = KERNADDR(&dma, offs); | 2698 | sqtd = KERNADDR(&dma, offs); | |
2696 | sqtd->physaddr = DMAADDR(&dma, offs); | 2699 | sqtd->physaddr = DMAADDR(&dma, offs); | |
2697 | sqtd->dma = dma; | 2700 | sqtd->dma = dma; | |
2698 | sqtd->offs = offs; | 2701 | sqtd->offs = offs; | |
2699 | 2702 | |||
2700 | sqtd->nextqtd = sc->sc_freeqtds; | 2703 | sqtd->nextqtd = sc->sc_freeqtds; | |
2701 | sc->sc_freeqtds = sqtd; | 2704 | sc->sc_freeqtds = sqtd; | |
2702 | } | 2705 | } | |
2703 | } | 2706 | } | |
2704 | 2707 | |||
2705 | sqtd = sc->sc_freeqtds; | 2708 | sqtd = sc->sc_freeqtds; | |
2706 | sc->sc_freeqtds = sqtd->nextqtd; | 2709 | sc->sc_freeqtds = sqtd->nextqtd; | |
2707 | memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t)); | 2710 | memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t)); | |
2708 | sqtd->nextqtd = NULL; | 2711 | sqtd->nextqtd = NULL; | |
2709 | sqtd->xfer = NULL; | 2712 | sqtd->xfer = NULL; | |
2710 | 2713 | |||
2711 | done: | 2714 | done: | |
2712 | return (sqtd); | 2715 | return (sqtd); | |
2713 | } | 2716 | } | |
2714 | 2717 | |||
2715 | Static void | 2718 | Static void | |
2716 | ehci_free_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd) | 2719 | ehci_free_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd) | |
2717 | { | 2720 | { | |
2718 | 2721 | |||
2719 | KASSERT(mutex_owned(&sc->sc_lock)); | 2722 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2720 | 2723 | |||
2721 | sqtd->nextqtd = sc->sc_freeqtds; | 2724 | sqtd->nextqtd = sc->sc_freeqtds; | |
2722 | sc->sc_freeqtds = sqtd; | 2725 | sc->sc_freeqtds = sqtd; | |
2723 | } | 2726 | } | |
2724 | 2727 | |||
2725 | Static usbd_status | 2728 | Static usbd_status | |
2726 | ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, | 2729 | ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, | |
2727 | int alen, int rd, usbd_xfer_handle xfer, | 2730 | int alen, int rd, usbd_xfer_handle xfer, | |
2728 | ehci_soft_qtd_t **sp, ehci_soft_qtd_t **ep) | 2731 | ehci_soft_qtd_t **sp, ehci_soft_qtd_t **ep) | |
2729 | { | 2732 | { | |
2730 | ehci_soft_qtd_t *next, *cur; | 2733 | ehci_soft_qtd_t *next, *cur; | |
2731 | ehci_physaddr_t dataphys, dataphyspage, dataphyslastpage, nextphys; | 2734 | ehci_physaddr_t dataphys, dataphyspage, dataphyslastpage, nextphys; | |
2732 | u_int32_t qtdstatus; | 2735 | u_int32_t qtdstatus; | |
2733 | int len, curlen, mps; | 2736 | int len, curlen, mps; | |
2734 | int i, tog; | 2737 | int i, tog; | |
2735 | usb_dma_t *dma = &xfer->dmabuf; | 2738 | usb_dma_t *dma = &xfer->dmabuf; | |
2736 | u_int16_t flags = xfer->flags; | 2739 | u_int16_t flags = xfer->flags; | |
2737 | 2740 | |||
2738 | DPRINTFN(alen<4*4096,("ehci_alloc_sqtd_chain: start len=%d\n", alen)); | 2741 | DPRINTFN(alen<4*4096,("ehci_alloc_sqtd_chain: start len=%d\n", alen)); | |
2739 | 2742 | |||
2740 | len = alen; | 2743 | len = alen; | |
2741 | dataphys = DMAADDR(dma, 0); | 2744 | dataphys = DMAADDR(dma, 0); | |
2742 | dataphyslastpage = EHCI_PAGE(dataphys + len - 1); | 2745 | dataphyslastpage = EHCI_PAGE(dataphys + len - 1); | |
2743 | qtdstatus = EHCI_QTD_ACTIVE | | 2746 | qtdstatus = EHCI_QTD_ACTIVE | | |
2744 | EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) | | 2747 | EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) | | |
2745 | EHCI_QTD_SET_CERR(3) | 2748 | EHCI_QTD_SET_CERR(3) | |
2746 | /* IOC set below */ | 2749 | /* IOC set below */ | |
2747 | /* BYTES set below */ | 2750 | /* BYTES set below */ | |
2748 | ; | 2751 | ; | |
2749 | mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize); | 2752 | mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize); | |
2750 | tog = epipe->nexttoggle; | 2753 | tog = epipe->nexttoggle; | |
2751 | qtdstatus |= EHCI_QTD_SET_TOGGLE(tog); | 2754 | qtdstatus |= EHCI_QTD_SET_TOGGLE(tog); | |
2752 | 2755 | |||
2753 | cur = ehci_alloc_sqtd(sc); | 2756 | cur = ehci_alloc_sqtd(sc); | |
2754 | *sp = cur; | 2757 | *sp = cur; | |
2755 | if (cur == NULL) | 2758 | if (cur == NULL) | |
2756 | goto nomem; | 2759 | goto nomem; | |
2757 | 2760 | |||
2758 | usb_syncmem(dma, 0, alen, | 2761 | usb_syncmem(dma, 0, alen, | |
2759 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | 2762 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | |
2760 | for (;;) { | 2763 | for (;;) { | |
2761 | dataphyspage = EHCI_PAGE(dataphys); | 2764 | dataphyspage = EHCI_PAGE(dataphys); | |
2762 | /* The EHCI hardware can handle at most 5 pages. */ | 2765 | /* The EHCI hardware can handle at most 5 pages. */ | |
2763 | if (dataphyslastpage - dataphyspage < | 2766 | if (dataphyslastpage - dataphyspage < | |
2764 | EHCI_QTD_NBUFFERS * EHCI_PAGE_SIZE) { | 2767 | EHCI_QTD_NBUFFERS * EHCI_PAGE_SIZE) { | |
2765 | /* we can handle it in this QTD */ | 2768 | /* we can handle it in this QTD */ | |
2766 | curlen = len; | 2769 | curlen = len; | |
2767 | } else { | 2770 | } else { | |
2768 | /* must use multiple TDs, fill as much as possible. */ | 2771 | /* must use multiple TDs, fill as much as possible. */ | |
2769 | curlen = EHCI_QTD_NBUFFERS * EHCI_PAGE_SIZE - | 2772 | curlen = EHCI_QTD_NBUFFERS * EHCI_PAGE_SIZE - | |
2770 | EHCI_PAGE_OFFSET(dataphys); | 2773 | EHCI_PAGE_OFFSET(dataphys); | |
2771 | #ifdef DIAGNOSTIC | 2774 | #ifdef DIAGNOSTIC | |
2772 | if (curlen > len) { | 2775 | if (curlen > len) { | |
2773 | printf("ehci_alloc_sqtd_chain: curlen=0x%x " | 2776 | printf("ehci_alloc_sqtd_chain: curlen=0x%x " | |
2774 | "len=0x%x offs=0x%x\n", curlen, len, | 2777 | "len=0x%x offs=0x%x\n", curlen, len, | |
2775 | EHCI_PAGE_OFFSET(dataphys)); | 2778 | EHCI_PAGE_OFFSET(dataphys)); | |
2776 | printf("lastpage=0x%x page=0x%x phys=0x%x\n", | 2779 | printf("lastpage=0x%x page=0x%x phys=0x%x\n", | |
2777 | dataphyslastpage, dataphyspage, | 2780 | dataphyslastpage, dataphyspage, | |
2778 | dataphys); | 2781 | dataphys); | |
2779 | curlen = len; | 2782 | curlen = len; | |
2780 | } | 2783 | } | |
2781 | #endif | 2784 | #endif | |
2782 | /* the length must be a multiple of the max size */ | 2785 | /* the length must be a multiple of the max size */ | |
2783 | curlen -= curlen % mps; | 2786 | curlen -= curlen % mps; | |
2784 | DPRINTFN(1,("ehci_alloc_sqtd_chain: multiple QTDs, " | 2787 | DPRINTFN(1,("ehci_alloc_sqtd_chain: multiple QTDs, " | |
2785 | "curlen=%d\n", curlen)); | 2788 | "curlen=%d\n", curlen)); | |
2786 | #ifdef DIAGNOSTIC | 2789 | #ifdef DIAGNOSTIC | |
2787 | if (curlen == 0) | 2790 | if (curlen == 0) | |
2788 | panic("ehci_alloc_sqtd_chain: curlen == 0"); | 2791 | panic("ehci_alloc_sqtd_chain: curlen == 0"); | |
2789 | #endif | 2792 | #endif | |
2790 | } | 2793 | } | |
2791 | DPRINTFN(4,("ehci_alloc_sqtd_chain: dataphys=0x%08x " | 2794 | DPRINTFN(4,("ehci_alloc_sqtd_chain: dataphys=0x%08x " | |
2792 | "dataphyslastpage=0x%08x len=%d curlen=%d\n", | 2795 | "dataphyslastpage=0x%08x len=%d curlen=%d\n", | |
2793 | dataphys, dataphyslastpage, | 2796 | dataphys, dataphyslastpage, | |
2794 | len, curlen)); | 2797 | len, curlen)); | |
2795 | len -= curlen; | 2798 | len -= curlen; | |
2796 | 2799 | |||
2797 | /* | 2800 | /* | |
2798 | * Allocate another transfer if there's more data left, | 2801 | * Allocate another transfer if there's more data left, | |
2799 | * or if force last short transfer flag is set and we're | 2802 | * or if force last short transfer flag is set and we're | |
2800 | * allocating a multiple of the max packet size. | 2803 | * allocating a multiple of the max packet size. | |
2801 | */ | 2804 | */ | |
2802 | if (len != 0 || | 2805 | if (len != 0 || | |
2803 | ((curlen % mps) == 0 && !rd && curlen != 0 && | 2806 | ((curlen % mps) == 0 && !rd && curlen != 0 && | |
2804 | (flags & USBD_FORCE_SHORT_XFER))) { | 2807 | (flags & USBD_FORCE_SHORT_XFER))) { | |
2805 | next = ehci_alloc_sqtd(sc); | 2808 | next = ehci_alloc_sqtd(sc); | |
2806 | if (next == NULL) | 2809 | if (next == NULL) | |
2807 | goto nomem; | 2810 | goto nomem; | |
2808 | nextphys = htole32(next->physaddr); | 2811 | nextphys = htole32(next->physaddr); | |
2809 | } else { | 2812 | } else { | |
2810 | next = NULL; | 2813 | next = NULL; | |
2811 | nextphys = EHCI_NULL; | 2814 | nextphys = EHCI_NULL; | |
2812 | } | 2815 | } | |
2813 | 2816 | |||
2814 | for (i = 0; i * EHCI_PAGE_SIZE < | 2817 | for (i = 0; i * EHCI_PAGE_SIZE < | |
2815 | curlen + EHCI_PAGE_OFFSET(dataphys); i++) { | 2818 | curlen + EHCI_PAGE_OFFSET(dataphys); i++) { | |
2816 | ehci_physaddr_t a = dataphys + i * EHCI_PAGE_SIZE; | 2819 | ehci_physaddr_t a = dataphys + i * EHCI_PAGE_SIZE; | |
2817 | if (i != 0) /* use offset only in first buffer */ | 2820 | if (i != 0) /* use offset only in first buffer */ | |
2818 | a = EHCI_PAGE(a); | 2821 | a = EHCI_PAGE(a); | |
2819 | cur->qtd.qtd_buffer[i] = htole32(a); | 2822 | cur->qtd.qtd_buffer[i] = htole32(a); | |
2820 | cur->qtd.qtd_buffer_hi[i] = 0; | 2823 | cur->qtd.qtd_buffer_hi[i] = 0; | |
2821 | #ifdef DIAGNOSTIC | 2824 | #ifdef DIAGNOSTIC | |
2822 | if (i >= EHCI_QTD_NBUFFERS) { | 2825 | if (i >= EHCI_QTD_NBUFFERS) { | |
2823 | printf("ehci_alloc_sqtd_chain: i=%d\n", i); | 2826 | printf("ehci_alloc_sqtd_chain: i=%d\n", i); | |
2824 | goto nomem; | 2827 | goto nomem; | |
2825 | } | 2828 | } | |
2826 | #endif | 2829 | #endif | |
2827 | } | 2830 | } | |
2828 | cur->nextqtd = next; | 2831 | cur->nextqtd = next; | |
2829 | cur->qtd.qtd_next = cur->qtd.qtd_altnext = nextphys; | 2832 | cur->qtd.qtd_next = cur->qtd.qtd_altnext = nextphys; | |
2830 | cur->qtd.qtd_status = | 2833 | cur->qtd.qtd_status = | |
2831 | htole32(qtdstatus | EHCI_QTD_SET_BYTES(curlen)); | 2834 | htole32(qtdstatus | EHCI_QTD_SET_BYTES(curlen)); | |
2832 | cur->xfer = xfer; | 2835 | cur->xfer = xfer; | |
2833 | cur->len = curlen; | 2836 | cur->len = curlen; | |
2834 | 2837 | |||
2835 | DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n", | 2838 | DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n", | |
2836 | dataphys, dataphys + curlen)); | 2839 | dataphys, dataphys + curlen)); | |
2837 | /* adjust the toggle based on the number of packets in this | 2840 | /* adjust the toggle based on the number of packets in this | |
2838 | qtd */ | 2841 | qtd */ | |
2839 | if (((curlen + mps - 1) / mps) & 1) { | 2842 | if (((curlen + mps - 1) / mps) & 1) { | |
2840 | tog ^= 1; | 2843 | tog ^= 1; | |
2841 | qtdstatus ^= EHCI_QTD_TOGGLE_MASK; | 2844 | qtdstatus ^= EHCI_QTD_TOGGLE_MASK; | |
2842 | } | 2845 | } | |
2843 | if (next == NULL) | 2846 | if (next == NULL) | |
2844 | break; | 2847 | break; | |
2845 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->qtd), | 2848 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->qtd), | |
2846 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2849 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2847 | DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n")); | 2850 | DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n")); | |
2848 | if (len) | 2851 | if (len) | |
2849 | dataphys += curlen; | 2852 | dataphys += curlen; | |
2850 | cur = next; | 2853 | cur = next; | |
2851 | } | 2854 | } | |
2852 | cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC); | 2855 | cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC); | |
2853 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->qtd), | 2856 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->qtd), | |
2854 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2857 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2855 | *ep = cur; | 2858 | *ep = cur; | |
2856 | epipe->nexttoggle = tog; | 2859 | epipe->nexttoggle = tog; | |
2857 | 2860 | |||
2858 | DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n", | 2861 | DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n", | |
2859 | *sp, *ep)); | 2862 | *sp, *ep)); | |
2860 | 2863 | |||
2861 | return (USBD_NORMAL_COMPLETION); | 2864 | return (USBD_NORMAL_COMPLETION); | |
2862 | 2865 | |||
2863 | nomem: | 2866 | nomem: | |
2864 | /* XXX free chain */ | 2867 | /* XXX free chain */ | |
2865 | DPRINTFN(-1,("ehci_alloc_sqtd_chain: no memory\n")); | 2868 | DPRINTFN(-1,("ehci_alloc_sqtd_chain: no memory\n")); | |
2866 | return (USBD_NOMEM); | 2869 | return (USBD_NOMEM); | |
2867 | } | 2870 | } | |
2868 | 2871 | |||
2869 | Static void | 2872 | Static void | |
2870 | ehci_free_sqtd_chain(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd, | 2873 | ehci_free_sqtd_chain(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd, | |
2871 | ehci_soft_qtd_t *sqtdend) | 2874 | ehci_soft_qtd_t *sqtdend) | |
2872 | { | 2875 | { | |
2873 | ehci_soft_qtd_t *p; | 2876 | ehci_soft_qtd_t *p; | |
2874 | int i; | 2877 | int i; | |
2875 | 2878 | |||
2876 | DPRINTFN(10,("ehci_free_sqtd_chain: sqtd=%p sqtdend=%p\n", | 2879 | DPRINTFN(10,("ehci_free_sqtd_chain: sqtd=%p sqtdend=%p\n", | |
2877 | sqtd, sqtdend)); | 2880 | sqtd, sqtdend)); | |
2878 | 2881 | |||
2879 | for (i = 0; sqtd != sqtdend; sqtd = p, i++) { | 2882 | for (i = 0; sqtd != sqtdend; sqtd = p, i++) { | |
2880 | p = sqtd->nextqtd; | 2883 | p = sqtd->nextqtd; | |
2881 | ehci_free_sqtd(sc, sqtd); | 2884 | ehci_free_sqtd(sc, sqtd); | |
2882 | } | 2885 | } | |
2883 | } | 2886 | } | |
2884 | 2887 | |||
2885 | Static ehci_soft_itd_t * | 2888 | Static ehci_soft_itd_t * | |
2886 | ehci_alloc_itd(ehci_softc_t *sc) | 2889 | ehci_alloc_itd(ehci_softc_t *sc) | |
2887 | { | 2890 | { | |
2888 | struct ehci_soft_itd *itd, *freeitd; | 2891 | struct ehci_soft_itd *itd, *freeitd; | |
2889 | usbd_status err; | 2892 | usbd_status err; | |
2890 | int i, s, offs, frindex, previndex; | 2893 | int i, s, offs, frindex, previndex; | |
2891 | usb_dma_t dma; | 2894 | usb_dma_t dma; | |
2892 | 2895 | |||
2893 | KASSERT(mutex_owned(&sc->sc_lock)); | 2896 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2894 | 2897 | |||
2895 | /* Find an itd that wasn't freed this frame or last frame. This can | 2898 | /* Find an itd that wasn't freed this frame or last frame. This can | |
2896 | * discard itds that were freed before frindex wrapped around | 2899 | * discard itds that were freed before frindex wrapped around | |
2897 | * XXX - can this lead to thrashing? Could fix by enabling wrap-around | 2900 | * XXX - can this lead to thrashing? Could fix by enabling wrap-around | |
2898 | * interrupt and fiddling with list when that happens */ | 2901 | * interrupt and fiddling with list when that happens */ | |
2899 | frindex = (EOREAD4(sc, EHCI_FRINDEX) + 1) >> 3; | 2902 | frindex = (EOREAD4(sc, EHCI_FRINDEX) + 1) >> 3; | |
2900 | previndex = (frindex != 0) ? frindex - 1 : sc->sc_flsize; | 2903 | previndex = (frindex != 0) ? frindex - 1 : sc->sc_flsize; | |
2901 | 2904 | |||
2902 | freeitd = NULL; | 2905 | freeitd = NULL; | |
2903 | LIST_FOREACH(itd, &sc->sc_freeitds, u.free_list) { | 2906 | LIST_FOREACH(itd, &sc->sc_freeitds, u.free_list) { | |
2904 | if (itd == NULL) | 2907 | if (itd == NULL) | |
2905 | break; | 2908 | break; | |
2906 | if (itd->slot != frindex && itd->slot != previndex) { | 2909 | if (itd->slot != frindex && itd->slot != previndex) { | |
2907 | freeitd = itd; | 2910 | freeitd = itd; | |
2908 | break; | 2911 | break; | |
2909 | } | 2912 | } | |
2910 | } | 2913 | } | |
2911 | 2914 | |||
2912 | if (freeitd == NULL) { | 2915 | if (freeitd == NULL) { | |
2913 | DPRINTFN(2, ("ehci_alloc_itd allocating chunk\n")); | 2916 | DPRINTFN(2, ("ehci_alloc_itd allocating chunk\n")); | |
2914 | err = usb_allocmem(&sc->sc_bus, EHCI_ITD_SIZE * EHCI_ITD_CHUNK, | 2917 | err = usb_allocmem(&sc->sc_bus, EHCI_ITD_SIZE * EHCI_ITD_CHUNK, | |
2915 | EHCI_PAGE_SIZE, &dma); | 2918 | EHCI_PAGE_SIZE, &dma); | |
2916 | 2919 | |||
2917 | if (err) { | 2920 | if (err) { | |
2918 | DPRINTF(("ehci_alloc_itd, alloc returned %d\n", err)); | 2921 | DPRINTF(("ehci_alloc_itd, alloc returned %d\n", err)); | |
2919 | return NULL; | 2922 | return NULL; | |
2920 | } | 2923 | } | |
2921 | 2924 | |||
2922 | for (i = 0; i < EHCI_ITD_CHUNK; i++) { | 2925 | for (i = 0; i < EHCI_ITD_CHUNK; i++) { | |
2923 | offs = i * EHCI_ITD_SIZE; | 2926 | offs = i * EHCI_ITD_SIZE; | |
2924 | itd = KERNADDR(&dma, offs); | 2927 | itd = KERNADDR(&dma, offs); | |
2925 | itd->physaddr = DMAADDR(&dma, offs); | 2928 | itd->physaddr = DMAADDR(&dma, offs); | |
2926 | itd->dma = dma; | 2929 | itd->dma = dma; | |
2927 | itd->offs = offs; | 2930 | itd->offs = offs; | |
2928 | LIST_INSERT_HEAD(&sc->sc_freeitds, itd, u.free_list); | 2931 | LIST_INSERT_HEAD(&sc->sc_freeitds, itd, u.free_list); | |
2929 | } | 2932 | } | |
2930 | freeitd = LIST_FIRST(&sc->sc_freeitds); | 2933 | freeitd = LIST_FIRST(&sc->sc_freeitds); | |
2931 | } | 2934 | } | |
2932 | 2935 | |||
2933 | itd = freeitd; | 2936 | itd = freeitd; | |
2934 | LIST_REMOVE(itd, u.free_list); | 2937 | LIST_REMOVE(itd, u.free_list); | |
2935 | memset(&itd->itd, 0, sizeof(ehci_itd_t)); | 2938 | memset(&itd->itd, 0, sizeof(ehci_itd_t)); | |
2936 | usb_syncmem(&itd->dma, itd->offs + offsetof(ehci_itd_t, itd_next), | 2939 | usb_syncmem(&itd->dma, itd->offs + offsetof(ehci_itd_t, itd_next), | |
2937 | sizeof(itd->itd.itd_next), BUS_DMASYNC_PREWRITE | | 2940 | sizeof(itd->itd.itd_next), BUS_DMASYNC_PREWRITE | | |
2938 | BUS_DMASYNC_PREREAD); | 2941 | BUS_DMASYNC_PREREAD); | |
2939 | 2942 | |||
2940 | itd->u.frame_list.next = NULL; | 2943 | itd->u.frame_list.next = NULL; | |
2941 | itd->u.frame_list.prev = NULL; | 2944 | itd->u.frame_list.prev = NULL; | |
2942 | itd->xfer_next = NULL; | 2945 | itd->xfer_next = NULL; | |
2943 | itd->slot = 0; | 2946 | itd->slot = 0; | |
2944 | splx(s); | 2947 | splx(s); | |
2945 | 2948 | |||
2946 | return itd; | 2949 | return itd; | |
2947 | } | 2950 | } | |
2948 | 2951 | |||
2949 | Static void | 2952 | Static void | |
2950 | ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd) | 2953 | ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd) | |
2951 | { | 2954 | { | |
2952 | 2955 | |||
2953 | KASSERT(mutex_owned(&sc->sc_lock)); | 2956 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2954 | 2957 | |||
2955 | LIST_INSERT_HEAD(&sc->sc_freeitds, itd, u.free_list); | 2958 | LIST_INSERT_HEAD(&sc->sc_freeitds, itd, u.free_list); | |
2956 | } | 2959 | } | |
2957 | 2960 | |||
2958 | /****************/ | 2961 | /****************/ | |
2959 | 2962 | |||
2960 | /* | 2963 | /* | |
2961 | * Close a reqular pipe. | 2964 | * Close a reqular pipe. | |
2962 | * Assumes that there are no pending transactions. | 2965 | * Assumes that there are no pending transactions. | |
2963 | */ | 2966 | */ | |
2964 | Static void | 2967 | Static void | |
2965 | ehci_close_pipe(usbd_pipe_handle pipe, ehci_soft_qh_t *head) | 2968 | ehci_close_pipe(usbd_pipe_handle pipe, ehci_soft_qh_t *head) | |
2966 | { | 2969 | { | |
2967 | struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; | 2970 | struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; | |
2968 | ehci_softc_t *sc = pipe->device->bus->hci_private; | 2971 | ehci_softc_t *sc = pipe->device->bus->hci_private; | |
2969 | ehci_soft_qh_t *sqh = epipe->sqh; | 2972 | ehci_soft_qh_t *sqh = epipe->sqh; | |
2970 | 2973 | |||
2971 | KASSERT(mutex_owned(&sc->sc_lock)); | 2974 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2972 | 2975 | |||
2973 | ehci_rem_qh(sc, sqh, head); | 2976 | ehci_rem_qh(sc, sqh, head); | |
2974 | ehci_free_sqh(sc, epipe->sqh); | 2977 | ehci_free_sqh(sc, epipe->sqh); | |
2975 | } | 2978 | } | |
2976 | 2979 | |||
2977 | /* | 2980 | /* | |
2978 | * Abort a device request. | 2981 | * Abort a device request. | |
2979 | * If this routine is called at splusb() it guarantees that the request | 2982 | * If this routine is called at splusb() it guarantees that the request | |
2980 | * will be removed from the hardware scheduling and that the callback | 2983 | * will be removed from the hardware scheduling and that the callback | |
2981 | * for it will be called with USBD_CANCELLED status. | 2984 | * for it will be called with USBD_CANCELLED status. | |
2982 | * It's impossible to guarantee that the requested transfer will not | 2985 | * It's impossible to guarantee that the requested transfer will not | |
2983 | * have happened since the hardware runs concurrently. | 2986 | * have happened since the hardware runs concurrently. | |
2984 | * If the transaction has already happened we rely on the ordinary | 2987 | * If the transaction has already happened we rely on the ordinary | |
2985 | * interrupt processing to process it. | 2988 | * interrupt processing to process it. | |
2986 | * XXX This is most probably wrong. | 2989 | * XXX This is most probably wrong. | |
2987 | */ | 2990 | */ | |
2988 | Static void | 2991 | Static void | |
2989 | ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) | 2992 | ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) | |
2990 | { | 2993 | { | |
2991 | #define exfer EXFER(xfer) | 2994 | #define exfer EXFER(xfer) | |
2992 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | 2995 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | |
2993 | ehci_softc_t *sc = epipe->pipe.device->bus->hci_private; | 2996 | ehci_softc_t *sc = epipe->pipe.device->bus->hci_private; | |
2994 | ehci_soft_qh_t *sqh = epipe->sqh; | 2997 | ehci_soft_qh_t *sqh = epipe->sqh; | |
2995 | ehci_soft_qtd_t *sqtd; | 2998 | ehci_soft_qtd_t *sqtd; | |
2996 | ehci_physaddr_t cur; | 2999 | ehci_physaddr_t cur; | |
2997 | u_int32_t qhstatus; | 3000 | u_int32_t qhstatus; | |
2998 | int hit; | 3001 | int hit; | |
2999 | int wake; | 3002 | int wake; | |
3000 | 3003 | |||
3001 | DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe)); | 3004 | DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe)); | |
3002 | 3005 | |||
3003 | if (sc->sc_dying) { | 3006 | if (sc->sc_dying) { | |
3004 | /* If we're dying, just do the software part. */ | 3007 | /* If we're dying, just do the software part. */ | |
3005 | mutex_enter(&sc->sc_lock); | 3008 | mutex_enter(&sc->sc_lock); | |
3006 | xfer->status = status; /* make software ignore it */ | 3009 | xfer->status = status; /* make software ignore it */ | |
3007 | callout_stop(&xfer->timeout_handle); | 3010 | callout_stop(&xfer->timeout_handle); | |
3008 | usb_transfer_complete(xfer); | 3011 | usb_transfer_complete(xfer); | |
3009 | mutex_exit(&sc->sc_lock); | 3012 | mutex_exit(&sc->sc_lock); | |
3010 | return; | 3013 | return; | |
3011 | } | 3014 | } | |
3012 | 3015 | |||
3013 | if (xfer->device->bus->intr_context) | 3016 | if (xfer->device->bus->intr_context) | |
3014 | panic("ehci_abort_xfer: not in process context"); | 3017 | panic("ehci_abort_xfer: not in process context"); | |
3015 | 3018 | |||
3016 | mutex_enter(&sc->sc_lock); | 3019 | mutex_enter(&sc->sc_lock); | |
3017 | 3020 | |||
3018 | /* | 3021 | /* | |
3019 | * If an abort is already in progress then just wait for it to | 3022 | * If an abort is already in progress then just wait for it to | |
3020 | * complete and return. | 3023 | * complete and return. | |
3021 | */ | 3024 | */ | |
3022 | if (xfer->hcflags & UXFER_ABORTING) { | 3025 | if (xfer->hcflags & UXFER_ABORTING) { | |
3023 | DPRINTFN(2, ("ehci_abort_xfer: already aborting\n")); | 3026 | DPRINTFN(2, ("ehci_abort_xfer: already aborting\n")); | |
3024 | #ifdef DIAGNOSTIC | 3027 | #ifdef DIAGNOSTIC | |
3025 | if (status == USBD_TIMEOUT) | 3028 | if (status == USBD_TIMEOUT) | |
3026 | printf("ehci_abort_xfer: TIMEOUT while aborting\n"); | 3029 | printf("ehci_abort_xfer: TIMEOUT while aborting\n"); | |
3027 | #endif | 3030 | #endif | |
3028 | /* Override the status which might be USBD_TIMEOUT. */ | 3031 | /* Override the status which might be USBD_TIMEOUT. */ | |
3029 | xfer->status = status; | 3032 | xfer->status = status; | |
3030 | DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n")); | 3033 | DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n")); | |
3031 | xfer->hcflags |= UXFER_ABORTWAIT; | 3034 | xfer->hcflags |= UXFER_ABORTWAIT; | |
3032 | while (xfer->hcflags & UXFER_ABORTING) | 3035 | while (xfer->hcflags & UXFER_ABORTING) | |
3033 | cv_wait(&xfer->hccv, &sc->sc_lock); | 3036 | cv_wait(&xfer->hccv, &sc->sc_lock); | |
3034 | mutex_exit(&sc->sc_lock); | 3037 | mutex_exit(&sc->sc_lock); | |
3035 | return; | 3038 | return; | |
3036 | } | 3039 | } | |
3037 | xfer->hcflags |= UXFER_ABORTING; | 3040 | xfer->hcflags |= UXFER_ABORTING; | |
3038 | 3041 | |||
3039 | /* | 3042 | /* | |
3040 | * Step 1: Make interrupt routine and hardware ignore xfer. | 3043 | * Step 1: Make interrupt routine and hardware ignore xfer. | |
3041 | */ | 3044 | */ | |
3042 | xfer->status = status; /* make software ignore it */ | 3045 | xfer->status = status; /* make software ignore it */ | |
3043 | callout_stop(&xfer->timeout_handle); | 3046 | callout_stop(&xfer->timeout_handle); | |
3044 | 3047 | |||
3045 | usb_syncmem(&sqh->dma, | 3048 | usb_syncmem(&sqh->dma, | |
3046 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | 3049 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | |
3047 | sizeof(sqh->qh.qh_qtd.qtd_status), | 3050 | sizeof(sqh->qh.qh_qtd.qtd_status), | |
3048 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3051 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3049 | qhstatus = sqh->qh.qh_qtd.qtd_status; | 3052 | qhstatus = sqh->qh.qh_qtd.qtd_status; | |
3050 | sqh->qh.qh_qtd.qtd_status = qhstatus | htole32(EHCI_QTD_HALTED); | 3053 | sqh->qh.qh_qtd.qtd_status = qhstatus | htole32(EHCI_QTD_HALTED); | |
3051 | usb_syncmem(&sqh->dma, | 3054 | usb_syncmem(&sqh->dma, | |
3052 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | 3055 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | |
3053 | sizeof(sqh->qh.qh_qtd.qtd_status), | 3056 | sizeof(sqh->qh.qh_qtd.qtd_status), | |
3054 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3057 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3055 | for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) { | 3058 | for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) { | |
3056 | usb_syncmem(&sqtd->dma, | 3059 | usb_syncmem(&sqtd->dma, | |
3057 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | 3060 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | |
3058 | sizeof(sqtd->qtd.qtd_status), | 3061 | sizeof(sqtd->qtd.qtd_status), | |
3059 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3062 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3060 | sqtd->qtd.qtd_status |= htole32(EHCI_QTD_HALTED); | 3063 | sqtd->qtd.qtd_status |= htole32(EHCI_QTD_HALTED); | |
3061 | usb_syncmem(&sqtd->dma, | 3064 | usb_syncmem(&sqtd->dma, | |
3062 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | 3065 | sqtd->offs + offsetof(ehci_qtd_t, qtd_status), | |
3063 | sizeof(sqtd->qtd.qtd_status), | 3066 | sizeof(sqtd->qtd.qtd_status), | |
3064 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3067 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3065 | if (sqtd == exfer->sqtdend) | 3068 | if (sqtd == exfer->sqtdend) | |
3066 | break; | 3069 | break; | |
3067 | } | 3070 | } | |
3068 | 3071 | |||
3069 | /* | 3072 | /* | |
3070 | * Step 2: Wait until we know hardware has finished any possible | 3073 | * Step 2: Wait until we know hardware has finished any possible | |
3071 | * use of the xfer. Also make sure the soft interrupt routine | 3074 | * use of the xfer. Also make sure the soft interrupt routine | |
3072 | * has run. | 3075 | * has run. | |
3073 | */ | 3076 | */ | |
3074 | ehci_sync_hc(sc); | 3077 | ehci_sync_hc(sc); | |
3075 | sc->sc_softwake = 1; | 3078 | sc->sc_softwake = 1; | |
3076 | usb_schedsoftintr(&sc->sc_bus); | 3079 | usb_schedsoftintr(&sc->sc_bus); | |
3077 | cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); | 3080 | cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); | |
3078 | 3081 | |||
3079 | /* | 3082 | /* | |
3080 | * Step 3: Remove any vestiges of the xfer from the hardware. | 3083 | * Step 3: Remove any vestiges of the xfer from the hardware. | |
3081 | * The complication here is that the hardware may have executed | 3084 | * The complication here is that the hardware may have executed | |
3082 | * beyond the xfer we're trying to abort. So as we're scanning | 3085 | * beyond the xfer we're trying to abort. So as we're scanning | |
3083 | * the TDs of this xfer we check if the hardware points to | 3086 | * the TDs of this xfer we check if the hardware points to | |
3084 | * any of them. | 3087 | * any of them. | |
3085 | */ | 3088 | */ | |
3086 | 3089 | |||
3087 | usb_syncmem(&sqh->dma, | 3090 | usb_syncmem(&sqh->dma, | |
3088 | sqh->offs + offsetof(ehci_qh_t, qh_curqtd), | 3091 | sqh->offs + offsetof(ehci_qh_t, qh_curqtd), | |
3089 | sizeof(sqh->qh.qh_curqtd), | 3092 | sizeof(sqh->qh.qh_curqtd), | |
3090 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3093 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3091 | cur = EHCI_LINK_ADDR(le32toh(sqh->qh.qh_curqtd)); | 3094 | cur = EHCI_LINK_ADDR(le32toh(sqh->qh.qh_curqtd)); | |
3092 | hit = 0; | 3095 | hit = 0; | |
3093 | for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) { | 3096 | for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) { | |
3094 | hit |= cur == sqtd->physaddr; | 3097 | hit |= cur == sqtd->physaddr; | |
3095 | if (sqtd == exfer->sqtdend) | 3098 | if (sqtd == exfer->sqtdend) | |
3096 | break; | 3099 | break; | |
3097 | } | 3100 | } | |
3098 | sqtd = sqtd->nextqtd; | 3101 | sqtd = sqtd->nextqtd; | |
3099 | /* Zap curqtd register if hardware pointed inside the xfer. */ | 3102 | /* Zap curqtd register if hardware pointed inside the xfer. */ | |
3100 | if (hit && sqtd != NULL) { | 3103 | if (hit && sqtd != NULL) { | |
3101 | DPRINTFN(1,("ehci_abort_xfer: cur=0x%08x\n", sqtd->physaddr)); | 3104 | DPRINTFN(1,("ehci_abort_xfer: cur=0x%08x\n", sqtd->physaddr)); | |
3102 | sqh->qh.qh_curqtd = htole32(sqtd->physaddr); /* unlink qTDs */ | 3105 | sqh->qh.qh_curqtd = htole32(sqtd->physaddr); /* unlink qTDs */ | |
3103 | usb_syncmem(&sqh->dma, | 3106 | usb_syncmem(&sqh->dma, | |
3104 | sqh->offs + offsetof(ehci_qh_t, qh_curqtd), | 3107 | sqh->offs + offsetof(ehci_qh_t, qh_curqtd), | |
3105 | sizeof(sqh->qh.qh_curqtd), | 3108 | sizeof(sqh->qh.qh_curqtd), | |
3106 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3109 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3107 | sqh->qh.qh_qtd.qtd_status = qhstatus; | 3110 | sqh->qh.qh_qtd.qtd_status = qhstatus; | |
3108 | usb_syncmem(&sqh->dma, | 3111 | usb_syncmem(&sqh->dma, | |
3109 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | 3112 | sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status), | |
3110 | sizeof(sqh->qh.qh_qtd.qtd_status), | 3113 | sizeof(sqh->qh.qh_qtd.qtd_status), | |
3111 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3114 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3112 | } else { | 3115 | } else { | |
3113 | DPRINTFN(1,("ehci_abort_xfer: no hit\n")); | 3116 | DPRINTFN(1,("ehci_abort_xfer: no hit\n")); | |
3114 | } | 3117 | } | |
3115 | 3118 | |||
3116 | /* | 3119 | /* | |
3117 | * Step 4: Execute callback. | 3120 | * Step 4: Execute callback. | |
3118 | */ | 3121 | */ | |
3119 | #ifdef DIAGNOSTIC | 3122 | #ifdef DIAGNOSTIC | |
3120 | exfer->isdone = 1; | 3123 | exfer->isdone = 1; | |
3121 | #endif | 3124 | #endif | |
3122 | wake = xfer->hcflags & UXFER_ABORTWAIT; | 3125 | wake = xfer->hcflags & UXFER_ABORTWAIT; | |
3123 | xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | 3126 | xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |
3124 | usb_transfer_complete(xfer); | 3127 | usb_transfer_complete(xfer); | |
3125 | if (wake) { | 3128 | if (wake) { | |
3126 | cv_broadcast(&xfer->hccv); | 3129 | cv_broadcast(&xfer->hccv); | |
3127 | } | 3130 | } | |
3128 | 3131 | |||
3129 | mutex_exit(&sc->sc_lock); | 3132 | mutex_exit(&sc->sc_lock); | |
3130 | #undef exfer | 3133 | #undef exfer | |
3131 | } | 3134 | } | |
3132 | 3135 | |||
3133 | Static void | 3136 | Static void | |
3134 | ehci_abort_isoc_xfer(usbd_xfer_handle xfer, usbd_status status) | 3137 | ehci_abort_isoc_xfer(usbd_xfer_handle xfer, usbd_status status) | |
3135 | { | 3138 | { | |
3136 | ehci_isoc_trans_t trans_status; | 3139 | ehci_isoc_trans_t trans_status; | |
3137 | struct ehci_pipe *epipe; | 3140 | struct ehci_pipe *epipe; | |
3138 | struct ehci_xfer *exfer; | 3141 | struct ehci_xfer *exfer; | |
3139 | ehci_softc_t *sc; | 3142 | ehci_softc_t *sc; | |
3140 | struct ehci_soft_itd *itd; | 3143 | struct ehci_soft_itd *itd; | |
3141 | int i, wake; | 3144 | int i, wake; | |
3142 | 3145 | |||
3143 | epipe = (struct ehci_pipe *) xfer->pipe; | 3146 | epipe = (struct ehci_pipe *) xfer->pipe; | |
3144 | exfer = EXFER(xfer); | 3147 | exfer = EXFER(xfer); | |
3145 | sc = epipe->pipe.device->bus->hci_private; | 3148 | sc = epipe->pipe.device->bus->hci_private; | |
3146 | 3149 | |||
3147 | DPRINTF(("ehci_abort_isoc_xfer: xfer %p pipe %p\n", xfer, epipe)); | 3150 | DPRINTF(("ehci_abort_isoc_xfer: xfer %p pipe %p\n", xfer, epipe)); | |
3148 | 3151 | |||
3149 | if (sc->sc_dying) { | 3152 | if (sc->sc_dying) { | |
3150 | mutex_enter(&sc->sc_lock); | 3153 | mutex_enter(&sc->sc_lock); | |
3151 | xfer->status = status; | 3154 | xfer->status = status; | |
3152 | callout_stop(&xfer->timeout_handle); | 3155 | callout_stop(&xfer->timeout_handle); | |
3153 | usb_transfer_complete(xfer); | 3156 | usb_transfer_complete(xfer); | |
3154 | mutex_exit(&sc->sc_lock); | 3157 | mutex_exit(&sc->sc_lock); | |
3155 | return; | 3158 | return; | |
3156 | } | 3159 | } | |
3157 | 3160 | |||
3158 | mutex_enter(&sc->sc_lock); | 3161 | mutex_enter(&sc->sc_lock); | |
3159 | 3162 | |||
3160 | if (xfer->hcflags & UXFER_ABORTING) { | 3163 | if (xfer->hcflags & UXFER_ABORTING) { | |
3161 | DPRINTFN(2, ("ehci_abort_isoc_xfer: already aborting\n")); | 3164 | DPRINTFN(2, ("ehci_abort_isoc_xfer: already aborting\n")); | |
3162 | 3165 | |||
3163 | #ifdef DIAGNOSTIC | 3166 | #ifdef DIAGNOSTIC | |
3164 | if (status == USBD_TIMEOUT) | 3167 | if (status == USBD_TIMEOUT) | |
3165 | printf("ehci_abort_xfer: TIMEOUT while aborting\n"); | 3168 | printf("ehci_abort_xfer: TIMEOUT while aborting\n"); | |
3166 | #endif | 3169 | #endif | |
3167 | 3170 | |||
3168 | xfer->status = status; | 3171 | xfer->status = status; | |
3169 | DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n")); | 3172 | DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n")); | |
3170 | xfer->hcflags |= UXFER_ABORTWAIT; | 3173 | xfer->hcflags |= UXFER_ABORTWAIT; | |
3171 | while (xfer->hcflags & UXFER_ABORTING) | 3174 | while (xfer->hcflags & UXFER_ABORTING) | |
3172 | cv_wait(&xfer->hccv, &sc->sc_intr_lock); | 3175 | cv_wait(&xfer->hccv, &sc->sc_intr_lock); | |
3173 | goto done; | 3176 | goto done; | |
3174 | } | 3177 | } | |
3175 | xfer->hcflags |= UXFER_ABORTING; | 3178 | xfer->hcflags |= UXFER_ABORTING; | |
3176 | 3179 | |||
3177 | xfer->status = status; | 3180 | xfer->status = status; | |
3178 | callout_stop(&xfer->timeout_handle); | 3181 | callout_stop(&xfer->timeout_handle); | |
3179 | 3182 | |||
3180 | for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) { | 3183 | for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) { | |
3181 | usb_syncmem(&itd->dma, | 3184 | usb_syncmem(&itd->dma, | |
3182 | itd->offs + offsetof(ehci_itd_t, itd_ctl), | 3185 | itd->offs + offsetof(ehci_itd_t, itd_ctl), | |
3183 | sizeof(itd->itd.itd_ctl), | 3186 | sizeof(itd->itd.itd_ctl), | |
3184 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3187 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3185 | 3188 | |||
3186 | for (i = 0; i < 8; i++) { | 3189 | for (i = 0; i < 8; i++) { | |
3187 | trans_status = le32toh(itd->itd.itd_ctl[i]); | 3190 | trans_status = le32toh(itd->itd.itd_ctl[i]); | |
3188 | trans_status &= ~EHCI_ITD_ACTIVE; | 3191 | trans_status &= ~EHCI_ITD_ACTIVE; | |
3189 | itd->itd.itd_ctl[i] = htole32(trans_status); | 3192 | itd->itd.itd_ctl[i] = htole32(trans_status); | |
3190 | } | 3193 | } | |
3191 | 3194 | |||
3192 | usb_syncmem(&itd->dma, | 3195 | usb_syncmem(&itd->dma, | |
3193 | itd->offs + offsetof(ehci_itd_t, itd_ctl), | 3196 | itd->offs + offsetof(ehci_itd_t, itd_ctl), | |
3194 | sizeof(itd->itd.itd_ctl), | 3197 | sizeof(itd->itd.itd_ctl), | |
3195 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3198 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3196 | } | 3199 | } | |
3197 | 3200 | |||
3198 | sc->sc_softwake = 1; | 3201 | sc->sc_softwake = 1; | |
3199 | usb_schedsoftintr(&sc->sc_bus); | 3202 | usb_schedsoftintr(&sc->sc_bus); | |
3200 | cv_wait(&sc->sc_softwake_cv, &sc->sc_intr_lock); | 3203 | cv_wait(&sc->sc_softwake_cv, &sc->sc_intr_lock); | |
3201 | 3204 | |||
3202 | #ifdef DIAGNOSTIC | 3205 | #ifdef DIAGNOSTIC | |
3203 | exfer->isdone = 1; | 3206 | exfer->isdone = 1; | |
3204 | #endif | 3207 | #endif | |
3205 | wake = xfer->hcflags & UXFER_ABORTWAIT; | 3208 | wake = xfer->hcflags & UXFER_ABORTWAIT; | |
3206 | xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | 3209 | xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |
3207 | usb_transfer_complete(xfer); | 3210 | usb_transfer_complete(xfer); | |
3208 | if (wake) { | 3211 | if (wake) { | |
3209 | cv_broadcast(&xfer->hccv); | 3212 | cv_broadcast(&xfer->hccv); | |
3210 | } | 3213 | } | |
3211 | 3214 | |||
3212 | done: | 3215 | done: | |
3213 | mutex_exit(&sc->sc_lock); | 3216 | mutex_exit(&sc->sc_lock); | |
3214 | return; | 3217 | return; | |
3215 | } | 3218 | } | |
3216 | 3219 | |||
3217 | Static void | 3220 | Static void | |
3218 | ehci_timeout(void *addr) | 3221 | ehci_timeout(void *addr) | |
3219 | { | 3222 | { | |
3220 | struct ehci_xfer *exfer = addr; | 3223 | struct ehci_xfer *exfer = addr; | |
3221 | struct ehci_pipe *epipe = (struct ehci_pipe *)exfer->xfer.pipe; | 3224 | struct ehci_pipe *epipe = (struct ehci_pipe *)exfer->xfer.pipe; | |
3222 | ehci_softc_t *sc = epipe->pipe.device->bus->hci_private; | 3225 | ehci_softc_t *sc = epipe->pipe.device->bus->hci_private; | |
3223 | 3226 | |||
3224 | DPRINTF(("ehci_timeout: exfer=%p\n", exfer)); | 3227 | DPRINTF(("ehci_timeout: exfer=%p\n", exfer)); | |
3225 | #ifdef EHCI_DEBUG | 3228 | #ifdef EHCI_DEBUG | |
3226 | if (ehcidebug > 1) | 3229 | if (ehcidebug > 1) | |
3227 | usbd_dump_pipe(exfer->xfer.pipe); | 3230 | usbd_dump_pipe(exfer->xfer.pipe); | |
3228 | #endif | 3231 | #endif | |
3229 | 3232 | |||
3230 | if (sc->sc_dying) { | 3233 | if (sc->sc_dying) { | |
3231 | ehci_abort_xfer(&exfer->xfer, USBD_TIMEOUT); | 3234 | ehci_abort_xfer(&exfer->xfer, USBD_TIMEOUT); | |
3232 | return; | 3235 | return; | |
3233 | } | 3236 | } | |
3234 | 3237 | |||
3235 | /* Execute the abort in a process context. */ | 3238 | /* Execute the abort in a process context. */ | |
3236 | usb_init_task(&exfer->abort_task, ehci_timeout_task, addr); | 3239 | usb_init_task(&exfer->abort_task, ehci_timeout_task, addr); | |
3237 | usb_add_task(exfer->xfer.pipe->device, &exfer->abort_task, | 3240 | usb_add_task(exfer->xfer.pipe->device, &exfer->abort_task, | |
3238 | USB_TASKQ_HC); | 3241 | USB_TASKQ_HC); | |
3239 | } | 3242 | } | |
3240 | 3243 | |||
3241 | Static void | 3244 | Static void | |
3242 | ehci_timeout_task(void *addr) | 3245 | ehci_timeout_task(void *addr) | |
3243 | { | 3246 | { | |
3244 | usbd_xfer_handle xfer = addr; | 3247 | usbd_xfer_handle xfer = addr; | |
3245 | 3248 | |||
3246 | DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer)); | 3249 | DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer)); | |
3247 | 3250 | |||
3248 | ehci_abort_xfer(xfer, USBD_TIMEOUT); | 3251 | ehci_abort_xfer(xfer, USBD_TIMEOUT); | |
3249 | } | 3252 | } | |
3250 | 3253 | |||
3251 | /************************/ | 3254 | /************************/ | |
3252 | 3255 | |||
3253 | Static usbd_status | 3256 | Static usbd_status | |
3254 | ehci_device_ctrl_transfer(usbd_xfer_handle xfer) | 3257 | ehci_device_ctrl_transfer(usbd_xfer_handle xfer) | |
3255 | { | 3258 | { | |
3256 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 3259 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
3257 | usbd_status err; | 3260 | usbd_status err; | |
3258 | 3261 | |||
3259 | /* Insert last in queue. */ | 3262 | /* Insert last in queue. */ | |
3260 | mutex_enter(&sc->sc_lock); | 3263 | mutex_enter(&sc->sc_lock); | |
3261 | err = usb_insert_transfer(xfer); | 3264 | err = usb_insert_transfer(xfer); | |
3262 | mutex_exit(&sc->sc_lock); | 3265 | mutex_exit(&sc->sc_lock); | |
3263 | if (err) | 3266 | if (err) | |
3264 | return (err); | 3267 | return (err); | |
3265 | 3268 | |||
3266 | /* Pipe isn't running, start first */ | 3269 | /* Pipe isn't running, start first */ | |
3267 | return (ehci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 3270 | return (ehci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
3268 | } | 3271 | } | |
3269 | 3272 | |||
3270 | Static usbd_status | 3273 | Static usbd_status | |
3271 | ehci_device_ctrl_start(usbd_xfer_handle xfer) | 3274 | ehci_device_ctrl_start(usbd_xfer_handle xfer) | |
3272 | { | 3275 | { | |
3273 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 3276 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
3274 | usbd_status err; | 3277 | usbd_status err; | |
3275 | 3278 | |||
3276 | if (sc->sc_dying) | 3279 | if (sc->sc_dying) | |
3277 | return (USBD_IOERROR); | 3280 | return (USBD_IOERROR); | |
3278 | 3281 | |||
3279 | #ifdef DIAGNOSTIC | 3282 | #ifdef DIAGNOSTIC | |
3280 | if (!(xfer->rqflags & URQ_REQUEST)) { | 3283 | if (!(xfer->rqflags & URQ_REQUEST)) { | |
3281 | /* XXX panic */ | 3284 | /* XXX panic */ | |
3282 | printf("ehci_device_ctrl_transfer: not a request\n"); | 3285 | printf("ehci_device_ctrl_transfer: not a request\n"); | |
3283 | return (USBD_INVAL); | 3286 | return (USBD_INVAL); | |
3284 | } | 3287 | } | |
3285 | #endif | 3288 | #endif | |
3286 | 3289 | |||
3287 | err = ehci_device_request(xfer); | 3290 | err = ehci_device_request(xfer); | |
3288 | if (err) { | 3291 | if (err) { | |
3289 | return (err); | 3292 | return (err); | |
3290 | } | 3293 | } | |
3291 | 3294 | |||
3292 | if (sc->sc_bus.use_polling) | 3295 | if (sc->sc_bus.use_polling) | |
3293 | ehci_waitintr(sc, xfer); | 3296 | ehci_waitintr(sc, xfer); | |
3294 | 3297 | |||
3295 | return (USBD_IN_PROGRESS); | 3298 | return (USBD_IN_PROGRESS); | |
3296 | } | 3299 | } | |
3297 | 3300 | |||
3298 | Static void | 3301 | Static void | |
3299 | ehci_device_ctrl_done(usbd_xfer_handle xfer) | 3302 | ehci_device_ctrl_done(usbd_xfer_handle xfer) | |
3300 | { | 3303 | { | |
3301 | struct ehci_xfer *ex = EXFER(xfer); | 3304 | struct ehci_xfer *ex = EXFER(xfer); | |
3302 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 3305 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
3303 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | 3306 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | |
3304 | usb_device_request_t *req = &xfer->request; | 3307 | usb_device_request_t *req = &xfer->request; | |
3305 | int len = UGETW(req->wLength); | 3308 | int len = UGETW(req->wLength); | |
3306 | int rd = req->bmRequestType & UT_READ; | 3309 | int rd = req->bmRequestType & UT_READ; | |
3307 | 3310 | |||
3308 | DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer)); | 3311 | DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer)); | |
3309 | 3312 | |||
3310 | KASSERT(mutex_owned(&sc->sc_lock)); | 3313 | KASSERT(mutex_owned(&sc->sc_lock)); | |
3311 | 3314 | |||
3312 | #ifdef DIAGNOSTIC | 3315 | #ifdef DIAGNOSTIC | |
3313 | if (!(xfer->rqflags & URQ_REQUEST)) { | 3316 | if (!(xfer->rqflags & URQ_REQUEST)) { | |
3314 | panic("ehci_ctrl_done: not a request"); | 3317 | panic("ehci_ctrl_done: not a request"); | |
3315 | } | 3318 | } | |
3316 | #endif | 3319 | #endif | |
3317 | 3320 | |||
3318 | if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { | 3321 | if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { | |
3319 | ehci_del_intr_list(sc, ex); /* remove from active list */ | 3322 | ehci_del_intr_list(sc, ex); /* remove from active list */ | |
3320 | ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); | 3323 | ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); | |
3321 | usb_syncmem(&epipe->u.ctl.reqdma, 0, sizeof *req, | 3324 | usb_syncmem(&epipe->u.ctl.reqdma, 0, sizeof *req, | |
3322 | BUS_DMASYNC_POSTWRITE); | 3325 | BUS_DMASYNC_POSTWRITE); | |
3323 | if (len) | 3326 | if (len) | |
3324 | usb_syncmem(&xfer->dmabuf, 0, len, | 3327 | usb_syncmem(&xfer->dmabuf, 0, len, | |
3325 | rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | 3328 | rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | |
3326 | } | 3329 | } | |
3327 | 3330 | |||
3328 | DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen)); | 3331 | DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen)); | |
3329 | } | 3332 | } | |
3330 | 3333 | |||
3331 | /* Abort a device control request. */ | 3334 | /* Abort a device control request. */ | |
3332 | Static void | 3335 | Static void | |
3333 | ehci_device_ctrl_abort(usbd_xfer_handle xfer) | 3336 | ehci_device_ctrl_abort(usbd_xfer_handle xfer) | |
3334 | { | 3337 | { | |
3335 | DPRINTF(("ehci_device_ctrl_abort: xfer=%p\n", xfer)); | 3338 | DPRINTF(("ehci_device_ctrl_abort: xfer=%p\n", xfer)); | |
3336 | ehci_abort_xfer(xfer, USBD_CANCELLED); | 3339 | ehci_abort_xfer(xfer, USBD_CANCELLED); | |
3337 | } | 3340 | } | |
3338 | 3341 | |||
3339 | /* Close a device control pipe. */ | 3342 | /* Close a device control pipe. */ | |
3340 | Static void | 3343 | Static void | |
3341 | ehci_device_ctrl_close(usbd_pipe_handle pipe) | 3344 | ehci_device_ctrl_close(usbd_pipe_handle pipe) | |
3342 | { | 3345 | { | |
3343 | ehci_softc_t *sc = pipe->device->bus->hci_private; | 3346 | ehci_softc_t *sc = pipe->device->bus->hci_private; | |
3344 | /*struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;*/ | 3347 | /*struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;*/ | |
3345 | 3348 | |||
3346 | DPRINTF(("ehci_device_ctrl_close: pipe=%p\n", pipe)); | 3349 | DPRINTF(("ehci_device_ctrl_close: pipe=%p\n", pipe)); | |
3347 | 3350 | |||
3348 | mutex_enter(&sc->sc_lock); | 3351 | mutex_enter(&sc->sc_lock); | |
3349 | ehci_close_pipe(pipe, sc->sc_async_head); | 3352 | ehci_close_pipe(pipe, sc->sc_async_head); | |
3350 | mutex_exit(&sc->sc_lock); | 3353 | mutex_exit(&sc->sc_lock); | |
3351 | } | 3354 | } | |
3352 | 3355 | |||
3353 | Static usbd_status | 3356 | Static usbd_status | |
3354 | ehci_device_request(usbd_xfer_handle xfer) | 3357 | ehci_device_request(usbd_xfer_handle xfer) | |
3355 | { | 3358 | { | |
3356 | #define exfer EXFER(xfer) | 3359 | #define exfer EXFER(xfer) | |
3357 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | 3360 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | |
3358 | usb_device_request_t *req = &xfer->request; | 3361 | usb_device_request_t *req = &xfer->request; | |
3359 | usbd_device_handle dev = epipe->pipe.device; | 3362 | usbd_device_handle dev = epipe->pipe.device; | |
3360 | ehci_softc_t *sc = dev->bus->hci_private; | 3363 | ehci_softc_t *sc = dev->bus->hci_private; | |
3361 | int addr = dev->address; | 3364 | int addr = dev->address; | |
3362 | ehci_soft_qtd_t *setup, *stat, *next; | 3365 | ehci_soft_qtd_t *setup, *stat, *next; | |
3363 | ehci_soft_qh_t *sqh; | 3366 | ehci_soft_qh_t *sqh; | |
3364 | int isread; | 3367 | int isread; | |
3365 | int len; | 3368 | int len; | |
3366 | usbd_status err; | 3369 | usbd_status err; | |
3367 | 3370 | |||
3368 | isread = req->bmRequestType & UT_READ; | 3371 | isread = req->bmRequestType & UT_READ; | |
3369 | len = UGETW(req->wLength); | 3372 | len = UGETW(req->wLength); | |
3370 | 3373 | |||
3371 | DPRINTFN(3,("ehci_device_request: type=0x%02x, request=0x%02x, " | 3374 | DPRINTFN(3,("ehci_device_request: type=0x%02x, request=0x%02x, " | |
3372 | "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n", | 3375 | "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n", | |
3373 | req->bmRequestType, req->bRequest, UGETW(req->wValue), | 3376 | req->bmRequestType, req->bRequest, UGETW(req->wValue), | |
3374 | UGETW(req->wIndex), len, addr, | 3377 | UGETW(req->wIndex), len, addr, | |
3375 | epipe->pipe.endpoint->edesc->bEndpointAddress)); | 3378 | epipe->pipe.endpoint->edesc->bEndpointAddress)); | |
3376 | 3379 | |||
3377 | setup = ehci_alloc_sqtd(sc); | 3380 | setup = ehci_alloc_sqtd(sc); | |
3378 | if (setup == NULL) { | 3381 | if (setup == NULL) { | |
3379 | err = USBD_NOMEM; | 3382 | err = USBD_NOMEM; | |
3380 | goto bad1; | 3383 | goto bad1; | |
3381 | } | 3384 | } | |
3382 | stat = ehci_alloc_sqtd(sc); | 3385 | stat = ehci_alloc_sqtd(sc); | |
3383 | if (stat == NULL) { | 3386 | if (stat == NULL) { | |
3384 | err = USBD_NOMEM; | 3387 | err = USBD_NOMEM; | |
3385 | goto bad2; | 3388 | goto bad2; | |
3386 | } | 3389 | } | |
3387 | 3390 | |||
3388 | mutex_enter(&sc->sc_lock); | 3391 | mutex_enter(&sc->sc_lock); | |
3389 | 3392 | |||
3390 | sqh = epipe->sqh; | 3393 | sqh = epipe->sqh; | |
3391 | epipe->u.ctl.length = len; | 3394 | epipe->u.ctl.length = len; | |
3392 | 3395 | |||
3393 | /* Update device address and length since they may have changed | 3396 | /* Update device address and length since they may have changed | |
3394 | during the setup of the control pipe in usbd_new_device(). */ | 3397 | during the setup of the control pipe in usbd_new_device(). */ | |
3395 | /* XXX This only needs to be done once, but it's too early in open. */ | 3398 | /* XXX This only needs to be done once, but it's too early in open. */ | |
3396 | /* XXXX Should not touch ED here! */ | 3399 | /* XXXX Should not touch ED here! */ | |
3397 | sqh->qh.qh_endp = | 3400 | sqh->qh.qh_endp = | |
3398 | (sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QH_MPLMASK))) | | 3401 | (sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QH_MPLMASK))) | | |
3399 | htole32( | 3402 | htole32( | |
3400 | EHCI_QH_SET_ADDR(addr) | | 3403 | EHCI_QH_SET_ADDR(addr) | | |
3401 | EHCI_QH_SET_MPL(UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize)) | 3404 | EHCI_QH_SET_MPL(UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize)) | |
3402 | ); | 3405 | ); | |
3403 | 3406 | |||
3404 | /* Set up data transaction */ | 3407 | /* Set up data transaction */ | |
3405 | if (len != 0) { | 3408 | if (len != 0) { | |
3406 | ehci_soft_qtd_t *end; | 3409 | ehci_soft_qtd_t *end; | |
3407 | 3410 | |||
3408 | /* Start toggle at 1. */ | 3411 | /* Start toggle at 1. */ | |
3409 | epipe->nexttoggle = 1; | 3412 | epipe->nexttoggle = 1; | |
3410 | err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, | 3413 | err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, | |
3411 | &next, &end); | 3414 | &next, &end); | |
3412 | if (err) | 3415 | if (err) | |
3413 | goto bad3; | 3416 | goto bad3; | |
3414 | end->qtd.qtd_status &= htole32(~EHCI_QTD_IOC); | 3417 | end->qtd.qtd_status &= htole32(~EHCI_QTD_IOC); | |
3415 | end->nextqtd = stat; | 3418 | end->nextqtd = stat; | |
3416 | end->qtd.qtd_next = | 3419 | end->qtd.qtd_next = | |
3417 | end->qtd.qtd_altnext = htole32(stat->physaddr); | 3420 | end->qtd.qtd_altnext = htole32(stat->physaddr); | |
3418 | usb_syncmem(&end->dma, end->offs, sizeof(end->qtd), | 3421 | usb_syncmem(&end->dma, end->offs, sizeof(end->qtd), | |
3419 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3422 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3420 | } else { | 3423 | } else { | |
3421 | next = stat; | 3424 | next = stat; | |
3422 | } | 3425 | } | |
3423 | 3426 | |||
3424 | memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req); | 3427 | memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req); | |
3425 | usb_syncmem(&epipe->u.ctl.reqdma, 0, sizeof *req, BUS_DMASYNC_PREWRITE); | 3428 | usb_syncmem(&epipe->u.ctl.reqdma, 0, sizeof *req, BUS_DMASYNC_PREWRITE); | |
3426 | 3429 | |||
3427 | /* Clear toggle */ | 3430 | /* Clear toggle */ | |
3428 | setup->qtd.qtd_status = htole32( | 3431 | setup->qtd.qtd_status = htole32( | |
3429 | EHCI_QTD_ACTIVE | | 3432 | EHCI_QTD_ACTIVE | | |
3430 | EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) | | 3433 | EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) | | |
3431 | EHCI_QTD_SET_CERR(3) | | 3434 | EHCI_QTD_SET_CERR(3) | | |
3432 | EHCI_QTD_SET_TOGGLE(0) | | 3435 | EHCI_QTD_SET_TOGGLE(0) | | |
3433 | EHCI_QTD_SET_BYTES(sizeof *req) | 3436 | EHCI_QTD_SET_BYTES(sizeof *req) | |
3434 | ); | 3437 | ); | |
3435 | setup->qtd.qtd_buffer[0] = htole32(DMAADDR(&epipe->u.ctl.reqdma, 0)); | 3438 | setup->qtd.qtd_buffer[0] = htole32(DMAADDR(&epipe->u.ctl.reqdma, 0)); | |
3436 | setup->qtd.qtd_buffer_hi[0] = 0; | 3439 | setup->qtd.qtd_buffer_hi[0] = 0; | |
3437 | setup->nextqtd = next; | 3440 | setup->nextqtd = next; | |
3438 | setup->qtd.qtd_next = setup->qtd.qtd_altnext = htole32(next->physaddr); | 3441 | setup->qtd.qtd_next = setup->qtd.qtd_altnext = htole32(next->physaddr); | |
3439 | setup->xfer = xfer; | 3442 | setup->xfer = xfer; | |
3440 | setup->len = sizeof *req; | 3443 | setup->len = sizeof *req; | |
3441 | usb_syncmem(&setup->dma, setup->offs, sizeof(setup->qtd), | 3444 | usb_syncmem(&setup->dma, setup->offs, sizeof(setup->qtd), | |
3442 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3445 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3443 | 3446 | |||
3444 | stat->qtd.qtd_status = htole32( | 3447 | stat->qtd.qtd_status = htole32( | |
3445 | EHCI_QTD_ACTIVE | | 3448 | EHCI_QTD_ACTIVE | | |
3446 | EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) | | 3449 | EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) | | |
3447 | EHCI_QTD_SET_CERR(3) | | 3450 | EHCI_QTD_SET_CERR(3) | | |
3448 | EHCI_QTD_SET_TOGGLE(1) | | 3451 | EHCI_QTD_SET_TOGGLE(1) | | |
3449 | EHCI_QTD_IOC | 3452 | EHCI_QTD_IOC | |
3450 | ); | 3453 | ); | |
3451 | stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */ | 3454 | stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */ | |
3452 | stat->qtd.qtd_buffer_hi[0] = 0; /* XXX not needed? */ | 3455 | stat->qtd.qtd_buffer_hi[0] = 0; /* XXX not needed? */ | |
3453 | stat->nextqtd = NULL; | 3456 | stat->nextqtd = NULL; | |
3454 | stat->qtd.qtd_next = stat->qtd.qtd_altnext = EHCI_NULL; | 3457 | stat->qtd.qtd_next = stat->qtd.qtd_altnext = EHCI_NULL; | |
3455 | stat->xfer = xfer; | 3458 | stat->xfer = xfer; | |
3456 | stat->len = 0; | 3459 | stat->len = 0; | |
3457 | usb_syncmem(&stat->dma, stat->offs, sizeof(stat->qtd), | 3460 | usb_syncmem(&stat->dma, stat->offs, sizeof(stat->qtd), | |
3458 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3461 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3459 | 3462 | |||
3460 | #ifdef EHCI_DEBUG | 3463 | #ifdef EHCI_DEBUG | |
3461 | if (ehcidebug > 5) { | 3464 | if (ehcidebug > 5) { | |
3462 | DPRINTF(("ehci_device_request:\n")); | 3465 | DPRINTF(("ehci_device_request:\n")); | |
3463 | ehci_dump_sqh(sqh); | 3466 | ehci_dump_sqh(sqh); | |
3464 | ehci_dump_sqtds(setup); | 3467 | ehci_dump_sqtds(setup); | |
3465 | } | 3468 | } | |
3466 | #endif | 3469 | #endif | |
3467 | 3470 | |||
3468 | exfer->sqtdstart = setup; | 3471 | exfer->sqtdstart = setup; | |
3469 | exfer->sqtdend = stat; | 3472 | exfer->sqtdend = stat; | |
3470 | #ifdef DIAGNOSTIC | 3473 | #ifdef DIAGNOSTIC | |
3471 | if (!exfer->isdone) { | 3474 | if (!exfer->isdone) { | |
3472 | printf("ehci_device_request: not done, exfer=%p\n", exfer); | 3475 | printf("ehci_device_request: not done, exfer=%p\n", exfer); | |
3473 | } | 3476 | } | |
3474 | exfer->isdone = 0; | 3477 | exfer->isdone = 0; | |
3475 | #endif | 3478 | #endif | |
3476 | 3479 | |||
3477 | /* Insert qTD in QH list. */ | 3480 | /* Insert qTD in QH list. */ | |
3478 | ehci_set_qh_qtd(sqh, setup); /* also does usb_syncmem(sqh) */ | 3481 | ehci_set_qh_qtd(sqh, setup); /* also does usb_syncmem(sqh) */ | |
3479 | if (xfer->timeout && !sc->sc_bus.use_polling) { | 3482 | if (xfer->timeout && !sc->sc_bus.use_polling) { | |
3480 | callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)), | 3483 | callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)), | |
3481 | (ehci_timeout), (xfer)); | 3484 | (ehci_timeout), (xfer)); | |
3482 | } | 3485 | } | |
3483 | ehci_add_intr_list(sc, exfer); | 3486 | ehci_add_intr_list(sc, exfer); | |
3484 | xfer->status = USBD_IN_PROGRESS; | 3487 | xfer->status = USBD_IN_PROGRESS; | |
3485 | mutex_exit(&sc->sc_lock); | 3488 | mutex_exit(&sc->sc_lock); | |
3486 | 3489 | |||
3487 | #ifdef EHCI_DEBUG | 3490 | #ifdef EHCI_DEBUG | |
3488 | if (ehcidebug > 10) { | 3491 | if (ehcidebug > 10) { | |
3489 | DPRINTF(("ehci_device_request: status=%x\n", | 3492 | DPRINTF(("ehci_device_request: status=%x\n", | |
3490 | EOREAD4(sc, EHCI_USBSTS))); | 3493 | EOREAD4(sc, EHCI_USBSTS))); | |
3491 | delay(10000); | 3494 | delay(10000); | |
3492 | ehci_dump_regs(sc); | 3495 | ehci_dump_regs(sc); | |
3493 | ehci_dump_sqh(sc->sc_async_head); | 3496 | ehci_dump_sqh(sc->sc_async_head); | |
3494 | ehci_dump_sqh(sqh); | 3497 | ehci_dump_sqh(sqh); | |
3495 | ehci_dump_sqtds(setup); | 3498 | ehci_dump_sqtds(setup); | |
3496 | } | 3499 | } | |
3497 | #endif | 3500 | #endif | |
3498 | 3501 | |||
3499 | return (USBD_NORMAL_COMPLETION); | 3502 | return (USBD_NORMAL_COMPLETION); | |
3500 | 3503 | |||
3501 | bad3: | 3504 | bad3: | |
3502 | mutex_exit(&sc->sc_lock); | 3505 | mutex_exit(&sc->sc_lock); | |
3503 | ehci_free_sqtd(sc, stat); | 3506 | ehci_free_sqtd(sc, stat); | |
3504 | bad2: | 3507 | bad2: | |
3505 | ehci_free_sqtd(sc, setup); | 3508 | ehci_free_sqtd(sc, setup); | |
3506 | bad1: | 3509 | bad1: | |
3507 | DPRINTFN(-1,("ehci_device_request: no memory\n")); | 3510 | DPRINTFN(-1,("ehci_device_request: no memory\n")); | |
3508 | mutex_enter(&sc->sc_lock); | 3511 | mutex_enter(&sc->sc_lock); | |
3509 | xfer->status = err; | 3512 | xfer->status = err; | |
3510 | usb_transfer_complete(xfer); | 3513 | usb_transfer_complete(xfer); | |
3511 | mutex_exit(&sc->sc_lock); | 3514 | mutex_exit(&sc->sc_lock); | |
3512 | return (err); | 3515 | return (err); | |
3513 | #undef exfer | 3516 | #undef exfer | |
3514 | } | 3517 | } | |
3515 | 3518 | |||
3516 | /* | 3519 | /* | |
3517 | * Some EHCI chips from VIA seem to trigger interrupts before writing back the | 3520 | * Some EHCI chips from VIA seem to trigger interrupts before writing back the | |
3518 | * qTD status, or miss signalling occasionally under heavy load. If the host | 3521 | * qTD status, or miss signalling occasionally under heavy load. If the host | |
3519 | * machine is too fast, we we can miss transaction completion - when we scan | 3522 | * machine is too fast, we we can miss transaction completion - when we scan | |
3520 | * the active list the transaction still seems to be active. This generally | 3523 | * the active list the transaction still seems to be active. This generally | |
3521 | * exhibits itself as a umass stall that never recovers. | 3524 | * exhibits itself as a umass stall that never recovers. | |
3522 | * | 3525 | * | |
3523 | * We work around this behaviour by setting up this callback after any softintr | 3526 | * We work around this behaviour by setting up this callback after any softintr | |
3524 | * that completes with transactions still pending, giving us another chance to | 3527 | * that completes with transactions still pending, giving us another chance to | |
3525 | * check for completion after the writeback has taken place. | 3528 | * check for completion after the writeback has taken place. | |
3526 | */ | 3529 | */ | |
3527 | Static void | 3530 | Static void | |
3528 | ehci_intrlist_timeout(void *arg) | 3531 | ehci_intrlist_timeout(void *arg) | |
3529 | { | 3532 | { | |
3530 | ehci_softc_t *sc = arg; | 3533 | ehci_softc_t *sc = arg; | |
3531 | 3534 | |||
3532 | DPRINTF(("ehci_intrlist_timeout\n")); | 3535 | DPRINTF(("ehci_intrlist_timeout\n")); | |
3533 | mutex_spin_enter(&sc->sc_intr_lock); | 3536 | mutex_spin_enter(&sc->sc_intr_lock); | |
3534 | usb_schedsoftintr(&sc->sc_bus); | 3537 | usb_schedsoftintr(&sc->sc_bus); | |
3535 | mutex_spin_exit(&sc->sc_intr_lock); | 3538 | mutex_spin_exit(&sc->sc_intr_lock); | |
3536 | } | 3539 | } | |
3537 | 3540 | |||
3538 | /************************/ | 3541 | /************************/ | |
3539 | 3542 | |||
3540 | Static usbd_status | 3543 | Static usbd_status | |
3541 | ehci_device_bulk_transfer(usbd_xfer_handle xfer) | 3544 | ehci_device_bulk_transfer(usbd_xfer_handle xfer) | |
3542 | { | 3545 | { | |
3543 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 3546 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
3544 | usbd_status err; | 3547 | usbd_status err; | |
3545 | 3548 | |||
3546 | /* Insert last in queue. */ | 3549 | /* Insert last in queue. */ | |
3547 | mutex_enter(&sc->sc_lock); | 3550 | mutex_enter(&sc->sc_lock); | |
3548 | err = usb_insert_transfer(xfer); | 3551 | err = usb_insert_transfer(xfer); | |
3549 | mutex_exit(&sc->sc_lock); | 3552 | mutex_exit(&sc->sc_lock); | |
3550 | if (err) | 3553 | if (err) | |
3551 | return (err); | 3554 | return (err); | |
3552 | 3555 | |||
3553 | /* Pipe isn't running, start first */ | 3556 | /* Pipe isn't running, start first */ | |
3554 | return (ehci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 3557 | return (ehci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
3555 | } | 3558 | } | |
3556 | 3559 | |||
3557 | Static usbd_status | 3560 | Static usbd_status | |
3558 | ehci_device_bulk_start(usbd_xfer_handle xfer) | 3561 | ehci_device_bulk_start(usbd_xfer_handle xfer) | |
3559 | { | 3562 | { | |
3560 | #define exfer EXFER(xfer) | 3563 | #define exfer EXFER(xfer) | |
3561 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | 3564 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | |
3562 | usbd_device_handle dev = epipe->pipe.device; | 3565 | usbd_device_handle dev = epipe->pipe.device; | |
3563 | ehci_softc_t *sc = dev->bus->hci_private; | 3566 | ehci_softc_t *sc = dev->bus->hci_private; | |
3564 | ehci_soft_qtd_t *data, *dataend; | 3567 | ehci_soft_qtd_t *data, *dataend; | |
3565 | ehci_soft_qh_t *sqh; | 3568 | ehci_soft_qh_t *sqh; | |
3566 | usbd_status err; | 3569 | usbd_status err; | |
3567 | int len, isread, endpt; | 3570 | int len, isread, endpt; | |
3568 | 3571 | |||
3569 | DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%d flags=%d\n", | 3572 | DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%d flags=%d\n", | |
3570 | xfer, xfer->length, xfer->flags)); | 3573 | xfer, xfer->length, xfer->flags)); | |
3571 | 3574 | |||
3572 | if (sc->sc_dying) | 3575 | if (sc->sc_dying) | |
3573 | return (USBD_IOERROR); | 3576 | return (USBD_IOERROR); | |
3574 | 3577 | |||
3575 | #ifdef DIAGNOSTIC | 3578 | #ifdef DIAGNOSTIC | |
3576 | if (xfer->rqflags & URQ_REQUEST) | 3579 | if (xfer->rqflags & URQ_REQUEST) | |
3577 | panic("ehci_device_bulk_start: a request"); | 3580 | panic("ehci_device_bulk_start: a request"); | |
3578 | #endif | 3581 | #endif | |
3579 | 3582 | |||
3580 | len = xfer->length; | 3583 | len = xfer->length; | |
3581 | endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; | 3584 | endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; | |
3582 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | 3585 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | |
3583 | sqh = epipe->sqh; | 3586 | sqh = epipe->sqh; | |
3584 | 3587 | |||
3585 | epipe->u.bulk.length = len; | 3588 | epipe->u.bulk.length = len; | |
3586 | 3589 | |||
3587 | err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data, | 3590 | err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data, | |
3588 | &dataend); | 3591 | &dataend); | |
3589 | if (err) { | 3592 | if (err) { | |
3590 | DPRINTFN(-1,("ehci_device_bulk_transfer: no memory\n")); | 3593 | DPRINTFN(-1,("ehci_device_bulk_transfer: no memory\n")); | |
3591 | xfer->status = err; | 3594 | xfer->status = err; | |
3592 | usb_transfer_complete(xfer); | 3595 | usb_transfer_complete(xfer); | |
3593 | return (err); | 3596 | return (err); | |
3594 | } | 3597 | } | |
3595 | 3598 | |||
3596 | #ifdef EHCI_DEBUG | 3599 | #ifdef EHCI_DEBUG | |
3597 | if (ehcidebug > 5) { | 3600 | if (ehcidebug > 5) { | |
3598 | DPRINTF(("ehci_device_bulk_start: data(1)\n")); | 3601 | DPRINTF(("ehci_device_bulk_start: data(1)\n")); | |
3599 | ehci_dump_sqh(sqh); | 3602 | ehci_dump_sqh(sqh); | |
3600 | ehci_dump_sqtds(data); | 3603 | ehci_dump_sqtds(data); | |
3601 | } | 3604 | } | |
3602 | #endif | 3605 | #endif | |
3603 | 3606 | |||
3604 | /* Set up interrupt info. */ | 3607 | /* Set up interrupt info. */ | |
3605 | exfer->sqtdstart = data; | 3608 | exfer->sqtdstart = data; | |
3606 | exfer->sqtdend = dataend; | 3609 | exfer->sqtdend = dataend; | |
3607 | #ifdef DIAGNOSTIC | 3610 | #ifdef DIAGNOSTIC | |
3608 | if (!exfer->isdone) { | 3611 | if (!exfer->isdone) { | |
3609 | printf("ehci_device_bulk_start: not done, ex=%p\n", exfer); | 3612 | printf("ehci_device_bulk_start: not done, ex=%p\n", exfer); | |
3610 | } | 3613 | } | |
3611 | exfer->isdone = 0; | 3614 | exfer->isdone = 0; | |
3612 | #endif | 3615 | #endif | |
3613 | 3616 | |||
3614 | mutex_enter(&sc->sc_lock); | 3617 | mutex_enter(&sc->sc_lock); | |
3615 | ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ | 3618 | ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ | |
3616 | if (xfer->timeout && !sc->sc_bus.use_polling) { | 3619 | if (xfer->timeout && !sc->sc_bus.use_polling) { | |
3617 | callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)), | 3620 | callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)), | |
3618 | (ehci_timeout), (xfer)); | 3621 | (ehci_timeout), (xfer)); | |
3619 | } | 3622 | } | |
3620 | ehci_add_intr_list(sc, exfer); | 3623 | ehci_add_intr_list(sc, exfer); | |
3621 | xfer->status = USBD_IN_PROGRESS; | 3624 | xfer->status = USBD_IN_PROGRESS; | |
3622 | mutex_exit(&sc->sc_lock); | 3625 | mutex_exit(&sc->sc_lock); | |
3623 | 3626 | |||
3624 | #ifdef EHCI_DEBUG | 3627 | #ifdef EHCI_DEBUG | |
3625 | if (ehcidebug > 10) { | 3628 | if (ehcidebug > 10) { | |
3626 | DPRINTF(("ehci_device_bulk_start: data(2)\n")); | 3629 | DPRINTF(("ehci_device_bulk_start: data(2)\n")); | |
3627 | delay(10000); | 3630 | delay(10000); | |
3628 | DPRINTF(("ehci_device_bulk_start: data(3)\n")); | 3631 | DPRINTF(("ehci_device_bulk_start: data(3)\n")); | |
3629 | ehci_dump_regs(sc); | 3632 | ehci_dump_regs(sc); | |
3630 | #if 0 | 3633 | #if 0 | |
3631 | printf("async_head:\n"); | 3634 | printf("async_head:\n"); | |
3632 | ehci_dump_sqh(sc->sc_async_head); | 3635 | ehci_dump_sqh(sc->sc_async_head); | |
3633 | #endif | 3636 | #endif | |
3634 | printf("sqh:\n"); | 3637 | printf("sqh:\n"); | |
3635 | ehci_dump_sqh(sqh); | 3638 | ehci_dump_sqh(sqh); | |
3636 | ehci_dump_sqtds(data); | 3639 | ehci_dump_sqtds(data); | |
3637 | } | 3640 | } | |
3638 | #endif | 3641 | #endif | |
3639 | 3642 | |||
3640 | if (sc->sc_bus.use_polling) | 3643 | if (sc->sc_bus.use_polling) | |
3641 | ehci_waitintr(sc, xfer); | 3644 | ehci_waitintr(sc, xfer); | |
3642 | 3645 | |||
3643 | return (USBD_IN_PROGRESS); | 3646 | return (USBD_IN_PROGRESS); | |
3644 | #undef exfer | 3647 | #undef exfer | |
3645 | } | 3648 | } | |
3646 | 3649 | |||
3647 | Static void | 3650 | Static void | |
3648 | ehci_device_bulk_abort(usbd_xfer_handle xfer) | 3651 | ehci_device_bulk_abort(usbd_xfer_handle xfer) | |
3649 | { | 3652 | { | |
3650 | DPRINTF(("ehci_device_bulk_abort: xfer=%p\n", xfer)); | 3653 | DPRINTF(("ehci_device_bulk_abort: xfer=%p\n", xfer)); | |
3651 | ehci_abort_xfer(xfer, USBD_CANCELLED); | 3654 | ehci_abort_xfer(xfer, USBD_CANCELLED); | |
3652 | } | 3655 | } | |
3653 | 3656 | |||
3654 | /* | 3657 | /* | |
3655 | * Close a device bulk pipe. | 3658 | * Close a device bulk pipe. | |
3656 | */ | 3659 | */ | |
3657 | Static void | 3660 | Static void | |
3658 | ehci_device_bulk_close(usbd_pipe_handle pipe) | 3661 | ehci_device_bulk_close(usbd_pipe_handle pipe) | |
3659 | { | 3662 | { | |
3660 | ehci_softc_t *sc = pipe->device->bus->hci_private; | 3663 | ehci_softc_t *sc = pipe->device->bus->hci_private; | |
3661 | struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; | 3664 | struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; | |
3662 | 3665 | |||
3663 | DPRINTF(("ehci_device_bulk_close: pipe=%p\n", pipe)); | 3666 | DPRINTF(("ehci_device_bulk_close: pipe=%p\n", pipe)); | |
3664 | mutex_enter(&sc->sc_lock); | 3667 | mutex_enter(&sc->sc_lock); | |
3665 | pipe->endpoint->datatoggle = epipe->nexttoggle; | 3668 | pipe->endpoint->datatoggle = epipe->nexttoggle; | |
3666 | ehci_close_pipe(pipe, sc->sc_async_head); | 3669 | ehci_close_pipe(pipe, sc->sc_async_head); | |
3667 | mutex_exit(&sc->sc_lock); | 3670 | mutex_exit(&sc->sc_lock); | |
3668 | } | 3671 | } | |
3669 | 3672 | |||
3670 | Static void | 3673 | Static void | |
3671 | ehci_device_bulk_done(usbd_xfer_handle xfer) | 3674 | ehci_device_bulk_done(usbd_xfer_handle xfer) | |
3672 | { | 3675 | { | |
3673 | struct ehci_xfer *ex = EXFER(xfer); | 3676 | struct ehci_xfer *ex = EXFER(xfer); | |
3674 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 3677 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
3675 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | 3678 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | |
3676 | int endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; | 3679 | int endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; | |
3677 | int rd = UE_GET_DIR(endpt) == UE_DIR_IN; | 3680 | int rd = UE_GET_DIR(endpt) == UE_DIR_IN; | |
3678 | 3681 | |||
3679 | DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n", | 3682 | DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n", | |
3680 | xfer, xfer->actlen)); | 3683 | xfer, xfer->actlen)); | |
3681 | 3684 | |||
3682 | KASSERT(mutex_owned(&sc->sc_lock)); | 3685 | KASSERT(mutex_owned(&sc->sc_lock)); | |
3683 | 3686 | |||
3684 | if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { | 3687 | if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { | |
3685 | ehci_del_intr_list(sc, ex); /* remove from active list */ | 3688 | ehci_del_intr_list(sc, ex); /* remove from active list */ | |
3686 | ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); | 3689 | ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); | |
3687 | usb_syncmem(&xfer->dmabuf, 0, xfer->length, | 3690 | usb_syncmem(&xfer->dmabuf, 0, xfer->length, | |
3688 | rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | 3691 | rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | |
3689 | } | 3692 | } | |
3690 | 3693 | |||
3691 | DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen)); | 3694 | DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen)); | |
3692 | } | 3695 | } | |
3693 | 3696 | |||
3694 | /************************/ | 3697 | /************************/ | |
3695 | 3698 | |||
3696 | Static usbd_status | 3699 | Static usbd_status | |
3697 | ehci_device_setintr(ehci_softc_t *sc, ehci_soft_qh_t *sqh, int ival) | 3700 | ehci_device_setintr(ehci_softc_t *sc, ehci_soft_qh_t *sqh, int ival) | |
3698 | { | 3701 | { | |
3699 | struct ehci_soft_islot *isp; | 3702 | struct ehci_soft_islot *isp; | |
3700 | int islot, lev; | 3703 | int islot, lev; | |
3701 | 3704 | |||
3702 | /* Find a poll rate that is large enough. */ | 3705 | /* Find a poll rate that is large enough. */ | |
3703 | for (lev = EHCI_IPOLLRATES - 1; lev > 0; lev--) | 3706 | for (lev = EHCI_IPOLLRATES - 1; lev > 0; lev--) | |
3704 | if (EHCI_ILEV_IVAL(lev) <= ival) | 3707 | if (EHCI_ILEV_IVAL(lev) <= ival) | |
3705 | break; | 3708 | break; | |
3706 | 3709 | |||
3707 | /* Pick an interrupt slot at the right level. */ | 3710 | /* Pick an interrupt slot at the right level. */ | |
3708 | /* XXX could do better than picking at random */ | 3711 | /* XXX could do better than picking at random */ | |
3709 | sc->sc_rand = (sc->sc_rand + 191) % sc->sc_flsize; | 3712 | sc->sc_rand = (sc->sc_rand + 191) % sc->sc_flsize; | |
3710 | islot = EHCI_IQHIDX(lev, sc->sc_rand); | 3713 | islot = EHCI_IQHIDX(lev, sc->sc_rand); | |
3711 | 3714 | |||
3712 | sqh->islot = islot; | 3715 | sqh->islot = islot; | |
3713 | isp = &sc->sc_islots[islot]; | 3716 | isp = &sc->sc_islots[islot]; | |
3714 | ehci_add_qh(sqh, isp->sqh); | 3717 | ehci_add_qh(sc, sqh, isp->sqh); | |
3715 | 3718 | |||
3716 | return (USBD_NORMAL_COMPLETION); | 3719 | return (USBD_NORMAL_COMPLETION); | |
3717 | } | 3720 | } | |
3718 | 3721 | |||
3719 | Static usbd_status | 3722 | Static usbd_status | |
3720 | ehci_device_intr_transfer(usbd_xfer_handle xfer) | 3723 | ehci_device_intr_transfer(usbd_xfer_handle xfer) | |
3721 | { | 3724 | { | |
3722 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 3725 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
3723 | usbd_status err; | 3726 | usbd_status err; | |
3724 | 3727 | |||
3725 | /* Insert last in queue. */ | 3728 | /* Insert last in queue. */ | |
3726 | mutex_enter(&sc->sc_lock); | 3729 | mutex_enter(&sc->sc_lock); | |
3727 | err = usb_insert_transfer(xfer); | 3730 | err = usb_insert_transfer(xfer); | |
3728 | mutex_exit(&sc->sc_lock); | 3731 | mutex_exit(&sc->sc_lock); | |
3729 | if (err) | 3732 | if (err) | |
3730 | return (err); | 3733 | return (err); | |
3731 | 3734 | |||
3732 | /* | 3735 | /* | |
3733 | * Pipe isn't running (otherwise err would be USBD_INPROG), | 3736 | * Pipe isn't running (otherwise err would be USBD_INPROG), | |
3734 | * so start it first. | 3737 | * so start it first. | |
3735 | */ | 3738 | */ | |
3736 | return (ehci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 3739 | return (ehci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
3737 | } | 3740 | } | |
3738 | 3741 | |||
3739 | Static usbd_status | 3742 | Static usbd_status | |
3740 | ehci_device_intr_start(usbd_xfer_handle xfer) | 3743 | ehci_device_intr_start(usbd_xfer_handle xfer) | |
3741 | { | 3744 | { | |
3742 | #define exfer EXFER(xfer) | 3745 | #define exfer EXFER(xfer) | |
3743 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | 3746 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | |
3744 | usbd_device_handle dev = xfer->pipe->device; | 3747 | usbd_device_handle dev = xfer->pipe->device; | |
3745 | ehci_softc_t *sc = dev->bus->hci_private; | 3748 | ehci_softc_t *sc = dev->bus->hci_private; | |
3746 | ehci_soft_qtd_t *data, *dataend; | 3749 | ehci_soft_qtd_t *data, *dataend; | |
3747 | ehci_soft_qh_t *sqh; | 3750 | ehci_soft_qh_t *sqh; | |
3748 | usbd_status err; | 3751 | usbd_status err; | |
3749 | int len, isread, endpt; | 3752 | int len, isread, endpt; | |
3750 | 3753 | |||
3751 | DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n", | 3754 | DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n", | |
3752 | xfer, xfer->length, xfer->flags)); | 3755 | xfer, xfer->length, xfer->flags)); | |
3753 | 3756 | |||
3754 | if (sc->sc_dying) | 3757 | if (sc->sc_dying) | |
3755 | return (USBD_IOERROR); | 3758 | return (USBD_IOERROR); | |
3756 | 3759 | |||
3757 | #ifdef DIAGNOSTIC | 3760 | #ifdef DIAGNOSTIC | |
3758 | if (xfer->rqflags & URQ_REQUEST) | 3761 | if (xfer->rqflags & URQ_REQUEST) | |
3759 | panic("ehci_device_intr_start: a request"); | 3762 | panic("ehci_device_intr_start: a request"); | |
3760 | #endif | 3763 | #endif | |
3761 | 3764 | |||
3762 | len = xfer->length; | 3765 | len = xfer->length; | |
3763 | endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; | 3766 | endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; | |
3764 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | 3767 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | |
3765 | sqh = epipe->sqh; | 3768 | sqh = epipe->sqh; | |
3766 | 3769 | |||
3767 | epipe->u.intr.length = len; | 3770 | epipe->u.intr.length = len; | |
3768 | 3771 | |||
3769 | err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data, | 3772 | err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data, | |
3770 | &dataend); | 3773 | &dataend); | |
3771 | if (err) { | 3774 | if (err) { | |
3772 | DPRINTFN(-1, ("ehci_device_intr_start: no memory\n")); | 3775 | DPRINTFN(-1, ("ehci_device_intr_start: no memory\n")); | |
3773 | xfer->status = err; | 3776 | xfer->status = err; | |
3774 | usb_transfer_complete(xfer); | 3777 | usb_transfer_complete(xfer); | |
3775 | return (err); | 3778 | return (err); | |
3776 | } | 3779 | } | |
3777 | 3780 | |||
3778 | #ifdef EHCI_DEBUG | 3781 | #ifdef EHCI_DEBUG | |
3779 | if (ehcidebug > 5) { | 3782 | if (ehcidebug > 5) { | |
3780 | DPRINTF(("ehci_device_intr_start: data(1)\n")); | 3783 | DPRINTF(("ehci_device_intr_start: data(1)\n")); | |
3781 | ehci_dump_sqh(sqh); | 3784 | ehci_dump_sqh(sqh); | |
3782 | ehci_dump_sqtds(data); | 3785 | ehci_dump_sqtds(data); | |
3783 | } | 3786 | } | |
3784 | #endif | 3787 | #endif | |
3785 | 3788 | |||
3786 | /* Set up interrupt info. */ | 3789 | /* Set up interrupt info. */ | |
3787 | exfer->sqtdstart = data; | 3790 | exfer->sqtdstart = data; | |
3788 | exfer->sqtdend = dataend; | 3791 | exfer->sqtdend = dataend; | |
3789 | #ifdef DIAGNOSTIC | 3792 | #ifdef DIAGNOSTIC | |
3790 | if (!exfer->isdone) { | 3793 | if (!exfer->isdone) { | |
3791 | printf("ehci_device_intr_start: not done, ex=%p\n", exfer); | 3794 | printf("ehci_device_intr_start: not done, ex=%p\n", exfer); | |
3792 | } | 3795 | } | |
3793 | exfer->isdone = 0; | 3796 | exfer->isdone = 0; | |
3794 | #endif | 3797 | #endif | |
3795 | 3798 | |||
3796 | mutex_enter(&sc->sc_lock); | 3799 | mutex_enter(&sc->sc_lock); | |
3797 | ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ | 3800 | ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ | |
3798 | if (xfer->timeout && !sc->sc_bus.use_polling) { | 3801 | if (xfer->timeout && !sc->sc_bus.use_polling) { | |
3799 | callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)), | 3802 | callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)), | |
3800 | (ehci_timeout), (xfer)); | 3803 | (ehci_timeout), (xfer)); | |
3801 | } | 3804 | } | |
3802 | ehci_add_intr_list(sc, exfer); | 3805 | ehci_add_intr_list(sc, exfer); | |
3803 | xfer->status = USBD_IN_PROGRESS; | 3806 | xfer->status = USBD_IN_PROGRESS; | |
3804 | mutex_exit(&sc->sc_lock); | 3807 | mutex_exit(&sc->sc_lock); | |
3805 | 3808 | |||
3806 | #ifdef EHCI_DEBUG | 3809 | #ifdef EHCI_DEBUG | |
3807 | if (ehcidebug > 10) { | 3810 | if (ehcidebug > 10) { | |
3808 | DPRINTF(("ehci_device_intr_start: data(2)\n")); | 3811 | DPRINTF(("ehci_device_intr_start: data(2)\n")); | |
3809 | delay(10000); | 3812 | delay(10000); | |
3810 | DPRINTF(("ehci_device_intr_start: data(3)\n")); | 3813 | DPRINTF(("ehci_device_intr_start: data(3)\n")); | |
3811 | ehci_dump_regs(sc); | 3814 | ehci_dump_regs(sc); | |
3812 | printf("sqh:\n"); | 3815 | printf("sqh:\n"); | |
3813 | ehci_dump_sqh(sqh); | 3816 | ehci_dump_sqh(sqh); | |
3814 | ehci_dump_sqtds(data); | 3817 | ehci_dump_sqtds(data); | |
3815 | } | 3818 | } | |
3816 | #endif | 3819 | #endif | |
3817 | 3820 | |||
3818 | if (sc->sc_bus.use_polling) | 3821 | if (sc->sc_bus.use_polling) | |
3819 | ehci_waitintr(sc, xfer); | 3822 | ehci_waitintr(sc, xfer); | |
3820 | 3823 | |||
3821 | return (USBD_IN_PROGRESS); | 3824 | return (USBD_IN_PROGRESS); | |
3822 | #undef exfer | 3825 | #undef exfer | |
3823 | } | 3826 | } | |
3824 | 3827 | |||
3825 | Static void | 3828 | Static void | |
3826 | ehci_device_intr_abort(usbd_xfer_handle xfer) | 3829 | ehci_device_intr_abort(usbd_xfer_handle xfer) | |
3827 | { | 3830 | { | |
3828 | DPRINTFN(1, ("ehci_device_intr_abort: xfer=%p\n", xfer)); | 3831 | DPRINTFN(1, ("ehci_device_intr_abort: xfer=%p\n", xfer)); | |
3829 | if (xfer->pipe->intrxfer == xfer) { | 3832 | if (xfer->pipe->intrxfer == xfer) { | |
3830 | DPRINTFN(1, ("echi_device_intr_abort: remove\n")); | 3833 | DPRINTFN(1, ("echi_device_intr_abort: remove\n")); | |
3831 | xfer->pipe->intrxfer = NULL; | 3834 | xfer->pipe->intrxfer = NULL; | |
3832 | } | 3835 | } | |
3833 | /* | 3836 | /* | |
3834 | * XXX - abort_xfer uses ehci_sync_hc, which syncs via the advance | 3837 | * XXX - abort_xfer uses ehci_sync_hc, which syncs via the advance | |
3835 | * async doorbell. That's dependent on the async list, wheras | 3838 | * async doorbell. That's dependent on the async list, wheras | |
3836 | * intr xfers are periodic, should not use this? | 3839 | * intr xfers are periodic, should not use this? | |
3837 | */ | 3840 | */ | |
3838 | ehci_abort_xfer(xfer, USBD_CANCELLED); | 3841 | ehci_abort_xfer(xfer, USBD_CANCELLED); | |
3839 | } | 3842 | } | |
3840 | 3843 | |||
3841 | Static void | 3844 | Static void | |
3842 | ehci_device_intr_close(usbd_pipe_handle pipe) | 3845 | ehci_device_intr_close(usbd_pipe_handle pipe) | |
3843 | { | 3846 | { | |
3844 | ehci_softc_t *sc = pipe->device->bus->hci_private; | 3847 | ehci_softc_t *sc = pipe->device->bus->hci_private; | |
3845 | struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; | 3848 | struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; | |
3846 | struct ehci_soft_islot *isp; | 3849 | struct ehci_soft_islot *isp; | |
3847 | 3850 | |||
3848 | isp = &sc->sc_islots[epipe->sqh->islot]; | 3851 | isp = &sc->sc_islots[epipe->sqh->islot]; | |
3849 | ehci_close_pipe(pipe, isp->sqh); | 3852 | ehci_close_pipe(pipe, isp->sqh); | |
3850 | } | 3853 | } | |
3851 | 3854 | |||
3852 | Static void | 3855 | Static void | |
3853 | ehci_device_intr_done(usbd_xfer_handle xfer) | 3856 | ehci_device_intr_done(usbd_xfer_handle xfer) | |
3854 | { | 3857 | { | |
3855 | #define exfer EXFER(xfer) | 3858 | #define exfer EXFER(xfer) | |
3856 | struct ehci_xfer *ex = EXFER(xfer); | 3859 | struct ehci_xfer *ex = EXFER(xfer); | |
3857 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 3860 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
3858 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | 3861 | struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; | |
3859 | ehci_soft_qtd_t *data, *dataend; | 3862 | ehci_soft_qtd_t *data, *dataend; | |
3860 | ehci_soft_qh_t *sqh; | 3863 | ehci_soft_qh_t *sqh; | |
3861 | usbd_status err; | 3864 | usbd_status err; | |
3862 | int len, isread, endpt; | 3865 | int len, isread, endpt; | |
3863 | 3866 | |||
3864 | DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n", | 3867 | DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n", | |
3865 | xfer, xfer->actlen)); | 3868 | xfer, xfer->actlen)); | |
3866 | 3869 | |||
3867 | KASSERT(mutex_owned(&sc->sc_lock)); | 3870 | KASSERT(mutex_owned(&sc->sc_lock)); | |
3868 | 3871 | |||
3869 | if (xfer->pipe->repeat) { | 3872 | if (xfer->pipe->repeat) { | |
3870 | ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); | 3873 | ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); | |
3871 | 3874 | |||
3872 | len = epipe->u.intr.length; | 3875 | len = epipe->u.intr.length; | |
3873 | xfer->length = len; | 3876 | xfer->length = len; | |
3874 | endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; | 3877 | endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; | |
3875 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | 3878 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | |
3876 | usb_syncmem(&xfer->dmabuf, 0, len, | 3879 | usb_syncmem(&xfer->dmabuf, 0, len, | |
3877 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | 3880 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | |
3878 | sqh = epipe->sqh; | 3881 | sqh = epipe->sqh; | |
3879 | 3882 | |||
3880 | err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, | 3883 | err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, | |
3881 | &data, &dataend); | 3884 | &data, &dataend); | |
3882 | if (err) { | 3885 | if (err) { | |
3883 | DPRINTFN(-1, ("ehci_device_intr_done: no memory\n")); | 3886 | DPRINTFN(-1, ("ehci_device_intr_done: no memory\n")); | |
3884 | xfer->status = err; | 3887 | xfer->status = err; | |
3885 | return; | 3888 | return; | |
3886 | } | 3889 | } | |
3887 | 3890 | |||
3888 | /* Set up interrupt info. */ | 3891 | /* Set up interrupt info. */ | |
3889 | exfer->sqtdstart = data; | 3892 | exfer->sqtdstart = data; | |
3890 | exfer->sqtdend = dataend; | 3893 | exfer->sqtdend = dataend; | |
3891 | #ifdef DIAGNOSTIC | 3894 | #ifdef DIAGNOSTIC | |
3892 | if (!exfer->isdone) { | 3895 | if (!exfer->isdone) { | |
3893 | printf("ehci_device_intr_done: not done, ex=%p\n", | 3896 | printf("ehci_device_intr_done: not done, ex=%p\n", | |
3894 | exfer); | 3897 | exfer); | |
3895 | } | 3898 | } | |
3896 | exfer->isdone = 0; | 3899 | exfer->isdone = 0; | |
3897 | #endif | 3900 | #endif | |
3898 | 3901 | |||
3899 | ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ | 3902 | ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ | |
3900 | if (xfer->timeout && !sc->sc_bus.use_polling) { | 3903 | if (xfer->timeout && !sc->sc_bus.use_polling) { | |
3901 | callout_reset(&(xfer->timeout_handle), | 3904 | callout_reset(&(xfer->timeout_handle), | |
3902 | (mstohz(xfer->timeout)), (ehci_timeout), (xfer)); | 3905 | (mstohz(xfer->timeout)), (ehci_timeout), (xfer)); | |
3903 | } | 3906 | } | |
3904 | 3907 | |||
3905 | xfer->status = USBD_IN_PROGRESS; | 3908 | xfer->status = USBD_IN_PROGRESS; | |
3906 | } else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { | 3909 | } else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { | |
3907 | ehci_del_intr_list(sc, ex); /* remove from active list */ | 3910 | ehci_del_intr_list(sc, ex); /* remove from active list */ | |
3908 | ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); | 3911 | ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); | |
3909 | endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; | 3912 | endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; | |
3910 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | 3913 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | |
3911 | usb_syncmem(&xfer->dmabuf, 0, xfer->length, | 3914 | usb_syncmem(&xfer->dmabuf, 0, xfer->length, | |
3912 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | 3915 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | |
3913 | } | 3916 | } | |
3914 | #undef exfer | 3917 | #undef exfer | |
3915 | } | 3918 | } | |
3916 | 3919 | |||
3917 | /************************/ | 3920 | /************************/ | |
3918 | 3921 | |||
3919 | Static usbd_status | 3922 | Static usbd_status | |
3920 | ehci_device_isoc_transfer(usbd_xfer_handle xfer) | 3923 | ehci_device_isoc_transfer(usbd_xfer_handle xfer) | |
3921 | { | 3924 | { | |
3922 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 3925 | ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
3923 | usbd_status err; | 3926 | usbd_status err; | |
3924 | 3927 | |||
3925 | mutex_enter(&sc->sc_lock); | 3928 | mutex_enter(&sc->sc_lock); | |
3926 | err = usb_insert_transfer(xfer); | 3929 | err = usb_insert_transfer(xfer); | |
3927 | mutex_exit(&sc->sc_lock); | 3930 | mutex_exit(&sc->sc_lock); | |
3928 | if (err && err != USBD_IN_PROGRESS) | 3931 | if (err && err != USBD_IN_PROGRESS) | |
3929 | return err; | 3932 | return err; | |
3930 | 3933 | |||
3931 | return ehci_device_isoc_start(xfer); | 3934 | return ehci_device_isoc_start(xfer); | |
3932 | } | 3935 | } | |
3933 | 3936 | |||
3934 | Static usbd_status | 3937 | Static usbd_status | |
3935 | ehci_device_isoc_start(usbd_xfer_handle xfer) | 3938 | ehci_device_isoc_start(usbd_xfer_handle xfer) | |
3936 | { | 3939 | { | |
3937 | struct ehci_pipe *epipe; | 3940 | struct ehci_pipe *epipe; | |
3938 | usbd_device_handle dev; | 3941 | usbd_device_handle dev; | |
3939 | ehci_softc_t *sc; | 3942 | ehci_softc_t *sc; | |
3940 | struct ehci_xfer *exfer; | 3943 | struct ehci_xfer *exfer; | |
3941 | ehci_soft_itd_t *itd, *prev, *start, *stop; | 3944 | ehci_soft_itd_t *itd, *prev, *start, *stop; | |
3942 | usb_dma_t *dma_buf; | 3945 | usb_dma_t *dma_buf; | |
3943 | int i, j, k, frames, uframes, ufrperframe; | 3946 | int i, j, k, frames, uframes, ufrperframe; | |
3944 | int trans_count, offs, total_length; | 3947 | int trans_count, offs, total_length; | |
3945 | int frindex; | 3948 | int frindex; | |
3946 | 3949 | |||
3947 | start = NULL; | 3950 | start = NULL; | |
3948 | prev = NULL; | 3951 | prev = NULL; | |
3949 | itd = NULL; | 3952 | itd = NULL; | |
3950 | trans_count = 0; | 3953 | trans_count = 0; | |
3951 | total_length = 0; | 3954 | total_length = 0; | |
3952 | exfer = (struct ehci_xfer *) xfer; | 3955 | exfer = (struct ehci_xfer *) xfer; | |
3953 | sc = xfer->pipe->device->bus->hci_private; | 3956 | sc = xfer->pipe->device->bus->hci_private; | |
3954 | dev = xfer->pipe->device; | 3957 | dev = xfer->pipe->device; | |
3955 | epipe = (struct ehci_pipe *)xfer->pipe; | 3958 | epipe = (struct ehci_pipe *)xfer->pipe; | |
3956 | 3959 | |||
3957 | /* | 3960 | /* | |
3958 | * To allow continuous transfers, above we start all transfers | 3961 | * To allow continuous transfers, above we start all transfers | |
3959 | * immediately. However, we're still going to get usbd_start_next call | 3962 | * immediately. However, we're still going to get usbd_start_next call | |
3960 | * this when another xfer completes. So, check if this is already | 3963 | * this when another xfer completes. So, check if this is already | |
3961 | * in progress or not | 3964 | * in progress or not | |
3962 | */ | 3965 | */ | |
3963 | 3966 | |||
3964 | if (exfer->itdstart != NULL) | 3967 | if (exfer->itdstart != NULL) | |
3965 | return USBD_IN_PROGRESS; | 3968 | return USBD_IN_PROGRESS; | |
3966 | 3969 | |||
3967 | DPRINTFN(2, ("ehci_device_isoc_start: xfer %p len %d flags %d\n", | 3970 | DPRINTFN(2, ("ehci_device_isoc_start: xfer %p len %d flags %d\n", | |
3968 | xfer, xfer->length, xfer->flags)); | 3971 | xfer, xfer->length, xfer->flags)); | |
3969 | 3972 | |||
3970 | if (sc->sc_dying) | 3973 | if (sc->sc_dying) | |
3971 | return USBD_IOERROR; | 3974 | return USBD_IOERROR; | |
3972 | 3975 | |||
3973 | /* | 3976 | /* | |
3974 | * To avoid complication, don't allow a request right now that'll span | 3977 | * To avoid complication, don't allow a request right now that'll span | |
3975 | * the entire frame table. To within 4 frames, to allow some leeway | 3978 | * the entire frame table. To within 4 frames, to allow some leeway | |
3976 | * on either side of where the hc currently is. | 3979 | * on either side of where the hc currently is. | |
3977 | */ | 3980 | */ | |
3978 | if ((1 << (epipe->pipe.endpoint->edesc->bInterval)) * | 3981 | if ((1 << (epipe->pipe.endpoint->edesc->bInterval)) * | |
3979 | xfer->nframes >= (sc->sc_flsize - 4) * 8) { | 3982 | xfer->nframes >= (sc->sc_flsize - 4) * 8) { | |
3980 | printf("ehci: isoc descriptor requested that spans the entire frametable, too many frames\n"); | 3983 | printf("ehci: isoc descriptor requested that spans the entire frametable, too many frames\n"); | |
3981 | return USBD_INVAL; | 3984 | return USBD_INVAL; | |
3982 | } | 3985 | } | |
3983 | 3986 | |||
3984 | #ifdef DIAGNOSTIC | 3987 | #ifdef DIAGNOSTIC | |
3985 | if (xfer->rqflags & URQ_REQUEST) | 3988 | if (xfer->rqflags & URQ_REQUEST) | |
3986 | panic("ehci_device_isoc_start: request\n"); | 3989 | panic("ehci_device_isoc_start: request\n"); | |
3987 | 3990 | |||
3988 | if (!exfer->isdone) | 3991 | if (!exfer->isdone) | |
3989 | printf("ehci_device_isoc_start: not done, ex = %p\n", exfer); | 3992 | printf("ehci_device_isoc_start: not done, ex = %p\n", exfer); | |
3990 | exfer->isdone = 0; | 3993 | exfer->isdone = 0; | |
3991 | #endif | 3994 | #endif | |
3992 | 3995 | |||
3993 | /* | 3996 | /* | |
3994 | * Step 1: Allocate and initialize itds, how many do we need? | 3997 | * Step 1: Allocate and initialize itds, how many do we need? | |
3995 | * One per transfer if interval >= 8 microframes, fewer if we use | 3998 | * One per transfer if interval >= 8 microframes, fewer if we use | |
3996 | * multiple microframes per frame. | 3999 | * multiple microframes per frame. | |
3997 | */ | 4000 | */ | |
3998 | 4001 | |||
3999 | i = epipe->pipe.endpoint->edesc->bInterval; | 4002 | i = epipe->pipe.endpoint->edesc->bInterval; | |
4000 | if (i > 16 || i == 0) { | 4003 | if (i > 16 || i == 0) { | |
4001 | /* Spec page 271 says intervals > 16 are invalid */ | 4004 | /* Spec page 271 says intervals > 16 are invalid */ | |
4002 | DPRINTF(("ehci_device_isoc_start: bInvertal %d invalid\n", i)); | 4005 | DPRINTF(("ehci_device_isoc_start: bInvertal %d invalid\n", i)); | |
4003 | return USBD_INVAL; | 4006 | return USBD_INVAL; | |
4004 | } | 4007 | } | |
4005 | 4008 | |||
4006 | ufrperframe = max(1, USB_UFRAMES_PER_FRAME / (1 << (i - 1))); | 4009 | ufrperframe = max(1, USB_UFRAMES_PER_FRAME / (1 << (i - 1))); | |
4007 | frames = (xfer->nframes + (ufrperframe - 1)) / ufrperframe; | 4010 | frames = (xfer->nframes + (ufrperframe - 1)) / ufrperframe; | |
4008 | uframes = USB_UFRAMES_PER_FRAME / ufrperframe; | 4011 | uframes = USB_UFRAMES_PER_FRAME / ufrperframe; | |
4009 | 4012 | |||
4010 | if (frames == 0) { | 4013 | if (frames == 0) { | |
4011 | DPRINTF(("ehci_device_isoc_start: frames == 0\n")); | 4014 | DPRINTF(("ehci_device_isoc_start: frames == 0\n")); | |
4012 | return USBD_INVAL; | 4015 | return USBD_INVAL; | |
4013 | } | 4016 | } | |
4014 | 4017 | |||
4015 | dma_buf = &xfer->dmabuf; | 4018 | dma_buf = &xfer->dmabuf; | |
4016 | offs = 0; | 4019 | offs = 0; | |
4017 | 4020 | |||
4018 | for (i = 0; i < frames; i++) { | 4021 | for (i = 0; i < frames; i++) { | |
4019 | int froffs = offs; | 4022 | int froffs = offs; | |
4020 | itd = ehci_alloc_itd(sc); | 4023 | itd = ehci_alloc_itd(sc); | |
4021 | 4024 | |||
4022 | if (prev != NULL) { | 4025 | if (prev != NULL) { | |
4023 | prev->itd.itd_next = | 4026 | prev->itd.itd_next = | |
4024 | htole32(itd->physaddr | EHCI_LINK_ITD); | 4027 | htole32(itd->physaddr | EHCI_LINK_ITD); | |
4025 | usb_syncmem(&itd->dma, | 4028 | usb_syncmem(&itd->dma, | |
4026 | itd->offs + offsetof(ehci_itd_t, itd_next), | 4029 | itd->offs + offsetof(ehci_itd_t, itd_next), | |
4027 | sizeof(itd->itd.itd_next), BUS_DMASYNC_POSTWRITE); | 4030 | sizeof(itd->itd.itd_next), BUS_DMASYNC_POSTWRITE); | |
4028 | 4031 | |||
4029 | prev->xfer_next = itd; | 4032 | prev->xfer_next = itd; | |
4030 | } else { | 4033 | } else { | |
4031 | start = itd; | 4034 | start = itd; | |
4032 | } | 4035 | } | |
4033 | 4036 | |||
4034 | /* | 4037 | /* | |
4035 | * Step 1.5, initialize uframes | 4038 | * Step 1.5, initialize uframes | |
4036 | */ | 4039 | */ | |
4037 | for (j = 0; j < EHCI_ITD_NUFRAMES; j += uframes) { | 4040 | for (j = 0; j < EHCI_ITD_NUFRAMES; j += uframes) { | |
4038 | /* Calculate which page in the list this starts in */ | 4041 | /* Calculate which page in the list this starts in */ | |
4039 | int addr = DMAADDR(dma_buf, froffs); | 4042 | int addr = DMAADDR(dma_buf, froffs); | |
4040 | addr = EHCI_PAGE_OFFSET(addr); | 4043 | addr = EHCI_PAGE_OFFSET(addr); | |
4041 | addr += (offs - froffs); | 4044 | addr += (offs - froffs); | |
4042 | addr = EHCI_PAGE(addr); | 4045 | addr = EHCI_PAGE(addr); | |
4043 | addr /= EHCI_PAGE_SIZE; | 4046 | addr /= EHCI_PAGE_SIZE; | |
4044 | 4047 | |||
4045 | /* This gets the initial offset into the first page, | 4048 | /* This gets the initial offset into the first page, | |
4046 | * looks how far further along the current uframe | 4049 | * looks how far further along the current uframe | |
4047 | * offset is. Works out how many pages that is. | 4050 | * offset is. Works out how many pages that is. | |
4048 | */ | 4051 | */ | |
4049 | 4052 | |||
4050 | itd->itd.itd_ctl[j] = htole32 ( EHCI_ITD_ACTIVE | | 4053 | itd->itd.itd_ctl[j] = htole32 ( EHCI_ITD_ACTIVE | | |
4051 | EHCI_ITD_SET_LEN(xfer->frlengths[trans_count]) | | 4054 | EHCI_ITD_SET_LEN(xfer->frlengths[trans_count]) | | |
4052 | EHCI_ITD_SET_PG(addr) | | 4055 | EHCI_ITD_SET_PG(addr) | | |
4053 | EHCI_ITD_SET_OFFS(EHCI_PAGE_OFFSET(DMAADDR(dma_buf,offs)))); | 4056 | EHCI_ITD_SET_OFFS(EHCI_PAGE_OFFSET(DMAADDR(dma_buf,offs)))); | |
4054 | 4057 | |||
4055 | total_length += xfer->frlengths[trans_count]; | 4058 | total_length += xfer->frlengths[trans_count]; | |
4056 | offs += xfer->frlengths[trans_count]; | 4059 | offs += xfer->frlengths[trans_count]; | |
4057 | trans_count++; | 4060 | trans_count++; | |
4058 | 4061 | |||
4059 | if (trans_count >= xfer->nframes) { /*Set IOC*/ | 4062 | if (trans_count >= xfer->nframes) { /*Set IOC*/ | |
4060 | itd->itd.itd_ctl[j] |= htole32(EHCI_ITD_IOC); | 4063 | itd->itd.itd_ctl[j] |= htole32(EHCI_ITD_IOC); | |
4061 | break; | 4064 | break; | |
4062 | } | 4065 | } | |
4063 | } | 4066 | } | |
4064 | 4067 | |||
4065 | /* Step 1.75, set buffer pointers. To simplify matters, all | 4068 | /* Step 1.75, set buffer pointers. To simplify matters, all | |
4066 | * pointers are filled out for the next 7 hardware pages in | 4069 | * pointers are filled out for the next 7 hardware pages in | |
4067 | * the dma block, so no need to worry what pages to cover | 4070 | * the dma block, so no need to worry what pages to cover | |
4068 | * and what to not. | 4071 | * and what to not. | |
4069 | */ | 4072 | */ | |
4070 | 4073 | |||
4071 | for (j = 0; j < EHCI_ITD_NBUFFERS; j++) { | 4074 | for (j = 0; j < EHCI_ITD_NBUFFERS; j++) { | |
4072 | /* | 4075 | /* | |
4073 | * Don't try to lookup a page that's past the end | 4076 | * Don't try to lookup a page that's past the end | |
4074 | * of buffer | 4077 | * of buffer | |
4075 | */ | 4078 | */ | |
4076 | int page_offs = EHCI_PAGE(froffs + (EHCI_PAGE_SIZE * j)); | 4079 | int page_offs = EHCI_PAGE(froffs + (EHCI_PAGE_SIZE * j)); | |
4077 | if (page_offs >= dma_buf->block->size) | 4080 | if (page_offs >= dma_buf->block->size) | |
4078 | break; | 4081 | break; | |
4079 | 4082 | |||
4080 | unsigned long long page = DMAADDR(dma_buf, page_offs); | 4083 | unsigned long long page = DMAADDR(dma_buf, page_offs); | |
4081 | page = EHCI_PAGE(page); | 4084 | page = EHCI_PAGE(page); | |
4082 | itd->itd.itd_bufr[j] = | 4085 | itd->itd.itd_bufr[j] = | |
4083 | htole32(EHCI_ITD_SET_BPTR(page)); | 4086 | htole32(EHCI_ITD_SET_BPTR(page)); | |
4084 | itd->itd.itd_bufr_hi[j] = | 4087 | itd->itd.itd_bufr_hi[j] = | |
4085 | htole32(page >> 32); | 4088 | htole32(page >> 32); | |
4086 | } | 4089 | } | |
4087 | 4090 | |||
4088 | /* | 4091 | /* | |
4089 | * Other special values | 4092 | * Other special values | |
4090 | */ | 4093 | */ | |
4091 | 4094 | |||
4092 | k = epipe->pipe.endpoint->edesc->bEndpointAddress; | 4095 | k = epipe->pipe.endpoint->edesc->bEndpointAddress; | |
4093 | itd->itd.itd_bufr[0] |= htole32(EHCI_ITD_SET_EP(UE_GET_ADDR(k)) | | 4096 | itd->itd.itd_bufr[0] |= htole32(EHCI_ITD_SET_EP(UE_GET_ADDR(k)) | | |
4094 | EHCI_ITD_SET_DADDR(epipe->pipe.device->address)); | 4097 | EHCI_ITD_SET_DADDR(epipe->pipe.device->address)); | |
4095 | 4098 | |||
4096 | k = (UE_GET_DIR(epipe->pipe.endpoint->edesc->bEndpointAddress)) | 4099 | k = (UE_GET_DIR(epipe->pipe.endpoint->edesc->bEndpointAddress)) | |
4097 | ? 1 : 0; | 4100 | ? 1 : 0; | |
4098 | j = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize); | 4101 | j = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize); | |
4099 | itd->itd.itd_bufr[1] |= htole32(EHCI_ITD_SET_DIR(k) | | 4102 | itd->itd.itd_bufr[1] |= htole32(EHCI_ITD_SET_DIR(k) | | |
4100 | EHCI_ITD_SET_MAXPKT(UE_GET_SIZE(j))); | 4103 | EHCI_ITD_SET_MAXPKT(UE_GET_SIZE(j))); | |
4101 | 4104 | |||
4102 | /* FIXME: handle invalid trans */ | 4105 | /* FIXME: handle invalid trans */ | |
4103 | itd->itd.itd_bufr[2] |= | 4106 | itd->itd.itd_bufr[2] |= | |
4104 | htole32(EHCI_ITD_SET_MULTI(UE_GET_TRANS(j)+1)); | 4107 | htole32(EHCI_ITD_SET_MULTI(UE_GET_TRANS(j)+1)); | |
4105 | 4108 | |||
4106 | usb_syncmem(&itd->dma, | 4109 | usb_syncmem(&itd->dma, | |
4107 | itd->offs + offsetof(ehci_itd_t, itd_next), | 4110 | itd->offs + offsetof(ehci_itd_t, itd_next), | |
4108 | sizeof(ehci_itd_t), | 4111 | sizeof(ehci_itd_t), | |
4109 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 4112 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
4110 | 4113 | |||
4111 | prev = itd; | 4114 | prev = itd; | |
4112 | } /* End of frame */ | 4115 | } /* End of frame */ | |
4113 | 4116 | |||
4114 | stop = itd; | 4117 | stop = itd; | |
4115 | stop->xfer_next = NULL; | 4118 | stop->xfer_next = NULL; | |
4116 | exfer->isoc_len = total_length; | 4119 | exfer->isoc_len = total_length; | |
4117 | 4120 | |||
4118 | usb_syncmem(&exfer->xfer.dmabuf, 0, total_length, | 4121 | usb_syncmem(&exfer->xfer.dmabuf, 0, total_length, | |
4119 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 4122 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
4120 | 4123 | |||
4121 | /* | 4124 | /* | |
4122 | * Part 2: Transfer descriptors have now been set up, now they must | 4125 | * Part 2: Transfer descriptors have now been set up, now they must | |
4123 | * be scheduled into the period frame list. Erk. Not wanting to | 4126 | * be scheduled into the period frame list. Erk. Not wanting to | |
4124 | * complicate matters, transfer is denied if the transfer spans | 4127 | * complicate matters, transfer is denied if the transfer spans | |
4125 | * more than the period frame list. | 4128 | * more than the period frame list. | |
4126 | */ | 4129 | */ | |
4127 | 4130 | |||
4128 | mutex_enter(&sc->sc_lock); | 4131 | mutex_enter(&sc->sc_lock); | |
4129 | 4132 | |||
4130 | /* Start inserting frames */ | 4133 | /* Start inserting frames */ | |
4131 | if (epipe->u.isoc.cur_xfers > 0) { | 4134 | if (epipe->u.isoc.cur_xfers > 0) { | |
4132 | frindex = epipe->u.isoc.next_frame; | 4135 | frindex = epipe->u.isoc.next_frame; | |
4133 | } else { | 4136 | } else { | |
4134 | frindex = EOREAD4(sc, EHCI_FRINDEX); | 4137 | frindex = EOREAD4(sc, EHCI_FRINDEX); | |
4135 | frindex = frindex >> 3; /* Erase microframe index */ | 4138 | frindex = frindex >> 3; /* Erase microframe index */ | |
4136 | frindex += 2; | 4139 | frindex += 2; | |
4137 | } | 4140 | } | |
4138 | 4141 | |||
4139 | if (frindex >= sc->sc_flsize) | 4142 | if (frindex >= sc->sc_flsize) | |
4140 | frindex &= (sc->sc_flsize - 1); | 4143 | frindex &= (sc->sc_flsize - 1); | |
4141 | 4144 | |||
4142 | /* What's the frame interval? */ | 4145 | /* What's the frame interval? */ | |
4143 | i = (1 << (epipe->pipe.endpoint->edesc->bInterval - 1)); | 4146 | i = (1 << (epipe->pipe.endpoint->edesc->bInterval - 1)); | |
4144 | if (i / USB_UFRAMES_PER_FRAME == 0) | 4147 | if (i / USB_UFRAMES_PER_FRAME == 0) | |
4145 | i = 1; | 4148 | i = 1; | |
4146 | else | 4149 | else | |
4147 | i /= USB_UFRAMES_PER_FRAME; | 4150 | i /= USB_UFRAMES_PER_FRAME; | |
4148 | 4151 | |||
4149 | itd = start; | 4152 | itd = start; | |
4150 | for (j = 0; j < frames; j++) { | 4153 | for (j = 0; j < frames; j++) { | |
4151 | if (itd == NULL) | 4154 | if (itd == NULL) | |
4152 | panic("ehci: unexpectedly ran out of isoc itds, isoc_start\n"); | 4155 | panic("ehci: unexpectedly ran out of isoc itds, isoc_start\n"); | |
4153 | 4156 | |||
4154 | itd->itd.itd_next = sc->sc_flist[frindex]; | 4157 | itd->itd.itd_next = sc->sc_flist[frindex]; | |
4155 | if (itd->itd.itd_next == 0) | 4158 | if (itd->itd.itd_next == 0) | |
4156 | /* FIXME: frindex table gets initialized to NULL | 4159 | /* FIXME: frindex table gets initialized to NULL | |
4157 | * or EHCI_NULL? */ | 4160 | * or EHCI_NULL? */ | |
4158 | itd->itd.itd_next = EHCI_NULL; | 4161 | itd->itd.itd_next = EHCI_NULL; | |
4159 | 4162 | |||
4160 | usb_syncmem(&itd->dma, | 4163 | usb_syncmem(&itd->dma, | |
4161 | itd->offs + offsetof(ehci_itd_t, itd_next), | 4164 | itd->offs + offsetof(ehci_itd_t, itd_next), | |
4162 | sizeof(itd->itd.itd_next), | 4165 | sizeof(itd->itd.itd_next), | |
4163 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 4166 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
4164 | 4167 | |||
4165 | sc->sc_flist[frindex] = htole32(EHCI_LINK_ITD | itd->physaddr); | 4168 | sc->sc_flist[frindex] = htole32(EHCI_LINK_ITD | itd->physaddr); | |
4166 | 4169 | |||
4167 | usb_syncmem(&sc->sc_fldma, | 4170 | usb_syncmem(&sc->sc_fldma, | |
4168 | sizeof(ehci_link_t) * frindex, | 4171 | sizeof(ehci_link_t) * frindex, | |
4169 | sizeof(ehci_link_t), | 4172 | sizeof(ehci_link_t), | |
4170 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 4173 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
4171 | 4174 | |||
4172 | itd->u.frame_list.next = sc->sc_softitds[frindex]; | 4175 | itd->u.frame_list.next = sc->sc_softitds[frindex]; | |
4173 | sc->sc_softitds[frindex] = itd; | 4176 | sc->sc_softitds[frindex] = itd; | |
4174 | if (itd->u.frame_list.next != NULL) | 4177 | if (itd->u.frame_list.next != NULL) | |
4175 | itd->u.frame_list.next->u.frame_list.prev = itd; | 4178 | itd->u.frame_list.next->u.frame_list.prev = itd; | |
4176 | itd->slot = frindex; | 4179 | itd->slot = frindex; | |
4177 | itd->u.frame_list.prev = NULL; | 4180 | itd->u.frame_list.prev = NULL; | |
4178 | 4181 | |||
4179 | frindex += i; | 4182 | frindex += i; | |
4180 | if (frindex >= sc->sc_flsize) | 4183 | if (frindex >= sc->sc_flsize) | |
4181 | frindex -= sc->sc_flsize; | 4184 | frindex -= sc->sc_flsize; | |
4182 | 4185 | |||
4183 | itd = itd->xfer_next; | 4186 | itd = itd->xfer_next; | |
4184 | } | 4187 | } | |
4185 | 4188 | |||
4186 | epipe->u.isoc.cur_xfers++; | 4189 | epipe->u.isoc.cur_xfers++; | |
4187 | epipe->u.isoc.next_frame = frindex; | 4190 | epipe->u.isoc.next_frame = frindex; | |
4188 | 4191 | |||
4189 | exfer->itdstart = start; | 4192 | exfer->itdstart = start; | |
4190 | exfer->itdend = stop; | 4193 | exfer->itdend = stop; | |
4191 | exfer->sqtdstart = NULL; | 4194 | exfer->sqtdstart = NULL; | |
4192 | exfer->sqtdstart = NULL; | 4195 | exfer->sqtdstart = NULL; | |
4193 | 4196 | |||
4194 | ehci_add_intr_list(sc, exfer); | 4197 | ehci_add_intr_list(sc, exfer); | |
4195 | xfer->status = USBD_IN_PROGRESS; | 4198 | xfer->status = USBD_IN_PROGRESS; | |
4196 | xfer->done = 0; | 4199 | xfer->done = 0; | |
4197 | mutex_exit(&sc->sc_lock); | 4200 | mutex_exit(&sc->sc_lock); | |
4198 | 4201 | |||
4199 | if (sc->sc_bus.use_polling) { | 4202 | if (sc->sc_bus.use_polling) { | |
4200 | printf("Starting ehci isoc xfer with polling. Bad idea?\n"); | 4203 | printf("Starting ehci isoc xfer with polling. Bad idea?\n"); | |
4201 | ehci_waitintr(sc, xfer); | 4204 | ehci_waitintr(sc, xfer); | |
4202 | } | 4205 | } | |
4203 | 4206 | |||
4204 | return USBD_IN_PROGRESS; | 4207 | return USBD_IN_PROGRESS; | |
4205 | } | 4208 | } | |
4206 | 4209 | |||
4207 | Static void | 4210 | Static void | |
4208 | ehci_device_isoc_abort(usbd_xfer_handle xfer) | 4211 | ehci_device_isoc_abort(usbd_xfer_handle xfer) | |
4209 | { | 4212 | { | |
4210 | DPRINTFN(1, ("ehci_device_isoc_abort: xfer = %p\n", xfer)); | 4213 | DPRINTFN(1, ("ehci_device_isoc_abort: xfer = %p\n", xfer)); | |
4211 | ehci_abort_isoc_xfer(xfer, USBD_CANCELLED); | 4214 | ehci_abort_isoc_xfer(xfer, USBD_CANCELLED); | |
4212 | } | 4215 | } | |
4213 | 4216 | |||
4214 | Static void | 4217 | Static void | |
4215 | ehci_device_isoc_close(usbd_pipe_handle pipe) | 4218 | ehci_device_isoc_close(usbd_pipe_handle pipe) | |
4216 | { | 4219 | { | |
4217 | DPRINTFN(1, ("ehci_device_isoc_close: nothing in the pipe to free?\n")); | 4220 | DPRINTFN(1, ("ehci_device_isoc_close: nothing in the pipe to free?\n")); | |
4218 | } | 4221 | } | |
4219 | 4222 | |||
4220 | Static void | 4223 | Static void | |
4221 | ehci_device_isoc_done(usbd_xfer_handle xfer) | 4224 | ehci_device_isoc_done(usbd_xfer_handle xfer) | |
4222 | { | 4225 | { | |
4223 | struct ehci_xfer *exfer; | 4226 | struct ehci_xfer *exfer; | |
4224 | ehci_softc_t *sc; | 4227 | ehci_softc_t *sc; | |
4225 | struct ehci_pipe *epipe; | 4228 | struct ehci_pipe *epipe; | |
4226 | 4229 | |||
4227 | exfer = EXFER(xfer); | 4230 | exfer = EXFER(xfer); | |
4228 | sc = xfer->pipe->device->bus->hci_private; | 4231 | sc = xfer->pipe->device->bus->hci_private; | |
4229 | epipe = (struct ehci_pipe *) xfer->pipe; | 4232 | epipe = (struct ehci_pipe *) xfer->pipe; | |
4230 | 4233 | |||
4231 | KASSERT(mutex_owned(&sc->sc_lock)); | 4234 | KASSERT(mutex_owned(&sc->sc_lock)); | |
4232 | 4235 | |||
4233 | epipe->u.isoc.cur_xfers--; | 4236 | epipe->u.isoc.cur_xfers--; | |
4234 | if (xfer->status != USBD_NOMEM && ehci_active_intr_list(exfer)) { | 4237 | if (xfer->status != USBD_NOMEM && ehci_active_intr_list(exfer)) { | |
4235 | ehci_del_intr_list(sc, exfer); | 4238 | ehci_del_intr_list(sc, exfer); | |
4236 | ehci_rem_free_itd_chain(sc, exfer); | 4239 | ehci_rem_free_itd_chain(sc, exfer); | |
4237 | } | 4240 | } | |
4238 | 4241 | |||
4239 | usb_syncmem(&xfer->dmabuf, 0, xfer->length, BUS_DMASYNC_POSTWRITE | | 4242 | usb_syncmem(&xfer->dmabuf, 0, xfer->length, BUS_DMASYNC_POSTWRITE | | |
4240 | BUS_DMASYNC_POSTREAD); | 4243 | BUS_DMASYNC_POSTREAD); | |
4241 | 4244 | |||
4242 | } | 4245 | } |
--- src/sys/dev/usb/ohci.c 2011/12/07 05:41:53 1.218.6.5
+++ src/sys/dev/usb/ohci.c 2011/12/08 02:51:07 1.218.6.6
@@ -1,3273 +1,3276 @@ | @@ -1,3273 +1,3276 @@ | |||
1 | /* $NetBSD: ohci.c,v 1.218.6.5 2011/12/07 05:41:53 macallan Exp $ */ | 1 | /* $NetBSD: ohci.c,v 1.218.6.6 2011/12/08 02:51:07 mrg Exp $ */ | |
2 | /* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */ | 2 | /* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 1998, 2004, 2005, 2011 The NetBSD Foundation, Inc. | 5 | * Copyright (c) 1998, 2004, 2005, 2011 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, Jared D. McNeill (jmcneill@invisible.ca) | 10 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) | |
11 | * and Matthew R. Green. | 11 | * and Matthew R. Green. | |
12 | * This code is derived from software contributed to The NetBSD Foundation | 12 | * This code is derived from software contributed to The NetBSD Foundation | |
13 | * by Charles M. Hannum. | 13 | * by Charles M. Hannum. | |
14 | * | 14 | * | |
15 | * Redistribution and use in source and binary forms, with or without | 15 | * Redistribution and use in source and binary forms, with or without | |
16 | * modification, are permitted provided that the following conditions | 16 | * modification, are permitted provided that the following conditions | |
17 | * are met: | 17 | * are met: | |
18 | * 1. Redistributions of source code must retain the above copyright | 18 | * 1. Redistributions of source code must retain the above copyright | |
19 | * notice, this list of conditions and the following disclaimer. | 19 | * notice, this list of conditions and the following disclaimer. | |
20 | * 2. Redistributions in binary form must reproduce the above copyright | 20 | * 2. Redistributions in binary form must reproduce the above copyright | |
21 | * notice, this list of conditions and the following disclaimer in the | 21 | * notice, this list of conditions and the following disclaimer in the | |
22 | * documentation and/or other materials provided with the distribution. | 22 | * documentation and/or other materials provided with the distribution. | |
23 | * | 23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 24 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
25 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 25 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
26 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 26 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
27 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 27 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
28 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 28 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
34 | * POSSIBILITY OF SUCH DAMAGE. | 34 | * POSSIBILITY OF SUCH DAMAGE. | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | /* | 37 | /* | |
38 | * USB Open Host Controller driver. | 38 | * USB Open Host Controller driver. | |
39 | * | 39 | * | |
40 | * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html | 40 | * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html | |
41 | * USB spec: http://www.usb.org/developers/docs/ | 41 | * USB spec: http://www.usb.org/developers/docs/ | |
42 | */ | 42 | */ | |
43 | 43 | |||
44 | #include <sys/cdefs.h> | 44 | #include <sys/cdefs.h> | |
45 | __KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.218.6.5 2011/12/07 05:41:53 macallan Exp $"); | 45 | __KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.218.6.6 2011/12/08 02:51:07 mrg Exp $"); | |
46 | 46 | |||
47 | #include "opt_usb.h" | 47 | #include "opt_usb.h" | |
48 | 48 | |||
49 | #include <sys/param.h> | 49 | #include <sys/param.h> | |
50 | #include <sys/systm.h> | 50 | #include <sys/systm.h> | |
51 | #include <sys/kmem.h> | 51 | #include <sys/kmem.h> | |
52 | #include <sys/kernel.h> | 52 | #include <sys/kernel.h> | |
53 | #include <sys/device.h> | 53 | #include <sys/device.h> | |
54 | #include <sys/select.h> | 54 | #include <sys/select.h> | |
55 | #include <sys/proc.h> | 55 | #include <sys/proc.h> | |
56 | #include <sys/queue.h> | 56 | #include <sys/queue.h> | |
57 | 57 | |||
58 | #include <sys/bus.h> | 58 | #include <sys/bus.h> | |
59 | #include <machine/endian.h> | 59 | #include <machine/endian.h> | |
60 | 60 | |||
61 | #include <dev/usb/usb.h> | 61 | #include <dev/usb/usb.h> | |
62 | #include <dev/usb/usbdi.h> | 62 | #include <dev/usb/usbdi.h> | |
63 | #include <dev/usb/usbdivar.h> | 63 | #include <dev/usb/usbdivar.h> | |
64 | #include <dev/usb/usb_mem.h> | 64 | #include <dev/usb/usb_mem.h> | |
65 | #include <dev/usb/usb_quirks.h> | 65 | #include <dev/usb/usb_quirks.h> | |
66 | 66 | |||
67 | #include <dev/usb/ohcireg.h> | 67 | #include <dev/usb/ohcireg.h> | |
68 | #include <dev/usb/ohcivar.h> | 68 | #include <dev/usb/ohcivar.h> | |
69 | #include <dev/usb/usbroothub_subr.h> | 69 | #include <dev/usb/usbroothub_subr.h> | |
70 | 70 | |||
71 | 71 | |||
72 | 72 | |||
73 | #ifdef OHCI_DEBUG | 73 | #ifdef OHCI_DEBUG | |
74 | #define DPRINTF(x) if (ohcidebug) printf x | 74 | #define DPRINTF(x) if (ohcidebug) printf x | |
75 | #define DPRINTFN(n,x) if (ohcidebug>(n)) printf x | 75 | #define DPRINTFN(n,x) if (ohcidebug>(n)) printf x | |
76 | int ohcidebug = 0; | 76 | int ohcidebug = 0; | |
77 | #else | 77 | #else | |
78 | #define DPRINTF(x) | 78 | #define DPRINTF(x) | |
79 | #define DPRINTFN(n,x) | 79 | #define DPRINTFN(n,x) | |
80 | #endif | 80 | #endif | |
81 | 81 | |||
82 | #if BYTE_ORDER == BIG_ENDIAN | 82 | #if BYTE_ORDER == BIG_ENDIAN | |
83 | #define SWAP_ENDIAN OHCI_LITTLE_ENDIAN | 83 | #define SWAP_ENDIAN OHCI_LITTLE_ENDIAN | |
84 | #else | 84 | #else | |
85 | #define SWAP_ENDIAN OHCI_BIG_ENDIAN | 85 | #define SWAP_ENDIAN OHCI_BIG_ENDIAN | |
86 | #endif | 86 | #endif | |
87 | 87 | |||
88 | #define O16TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap16(val) : val) | 88 | #define O16TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap16(val) : val) | |
89 | #define O32TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap32(val) : val) | 89 | #define O32TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap32(val) : val) | |
90 | #define HTOO16(val) O16TOH(val) | 90 | #define HTOO16(val) O16TOH(val) | |
91 | #define HTOO32(val) O32TOH(val) | 91 | #define HTOO32(val) O32TOH(val) | |
92 | 92 | |||
93 | struct ohci_pipe; | 93 | struct ohci_pipe; | |
94 | 94 | |||
95 | Static ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *); | 95 | Static ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *); | |
96 | Static void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *); | 96 | Static void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *); | |
97 | 97 | |||
98 | Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *); | 98 | Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *); | |
99 | Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *); | 99 | Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *); | |
100 | 100 | |||
101 | Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *); | 101 | Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *); | |
102 | Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *); | 102 | Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *); | |
103 | 103 | |||
104 | #if 0 | 104 | #if 0 | |
105 | Static void ohci_free_std_chain(ohci_softc_t *, ohci_soft_td_t *, | 105 | Static void ohci_free_std_chain(ohci_softc_t *, ohci_soft_td_t *, | |
106 | ohci_soft_td_t *); | 106 | ohci_soft_td_t *); | |
107 | #endif | 107 | #endif | |
108 | Static usbd_status ohci_alloc_std_chain(struct ohci_pipe *, | 108 | Static usbd_status ohci_alloc_std_chain(struct ohci_pipe *, | |
109 | ohci_softc_t *, int, int, usbd_xfer_handle, | 109 | ohci_softc_t *, int, int, usbd_xfer_handle, | |
110 | ohci_soft_td_t *, ohci_soft_td_t **); | 110 | ohci_soft_td_t *, ohci_soft_td_t **); | |
111 | 111 | |||
112 | Static usbd_status ohci_open(usbd_pipe_handle); | 112 | Static usbd_status ohci_open(usbd_pipe_handle); | |
113 | Static void ohci_poll(struct usbd_bus *); | 113 | Static void ohci_poll(struct usbd_bus *); | |
114 | Static void ohci_softintr(void *); | 114 | Static void ohci_softintr(void *); | |
115 | Static void ohci_waitintr(ohci_softc_t *, usbd_xfer_handle); | 115 | Static void ohci_waitintr(ohci_softc_t *, usbd_xfer_handle); | |
116 | Static void ohci_rhsc(ohci_softc_t *, usbd_xfer_handle); | 116 | Static void ohci_rhsc(ohci_softc_t *, usbd_xfer_handle); | |
117 | Static void ohci_rhsc_softint(void *arg); | 117 | Static void ohci_rhsc_softint(void *arg); | |
118 | 118 | |||
119 | Static usbd_status ohci_device_request(usbd_xfer_handle xfer); | 119 | Static usbd_status ohci_device_request(usbd_xfer_handle xfer); | |
120 | Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *, | 120 | Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *, | |
121 | ohci_soft_ed_t *); | 121 | ohci_soft_ed_t *); | |
122 | 122 | |||
123 | Static void ohci_rem_ed(ohci_soft_ed_t *, ohci_soft_ed_t *); | 123 | Static void ohci_rem_ed(ohci_softc_t *, ohci_soft_ed_t *, | |
124 | ohci_soft_ed_t *); | |||
124 | Static void ohci_hash_add_td(ohci_softc_t *, ohci_soft_td_t *); | 125 | Static void ohci_hash_add_td(ohci_softc_t *, ohci_soft_td_t *); | |
125 | Static void ohci_hash_rem_td(ohci_softc_t *, ohci_soft_td_t *); | 126 | Static void ohci_hash_rem_td(ohci_softc_t *, ohci_soft_td_t *); | |
126 | Static ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, ohci_physaddr_t); | 127 | Static ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, ohci_physaddr_t); | |
127 | Static void ohci_hash_add_itd(ohci_softc_t *, ohci_soft_itd_t *); | 128 | Static void ohci_hash_add_itd(ohci_softc_t *, ohci_soft_itd_t *); | |
128 | Static void ohci_hash_rem_itd(ohci_softc_t *, ohci_soft_itd_t *); | 129 | Static void ohci_hash_rem_itd(ohci_softc_t *, ohci_soft_itd_t *); | |
129 | Static ohci_soft_itd_t *ohci_hash_find_itd(ohci_softc_t *, ohci_physaddr_t); | 130 | Static ohci_soft_itd_t *ohci_hash_find_itd(ohci_softc_t *, ohci_physaddr_t); | |
130 | 131 | |||
131 | Static usbd_status ohci_setup_isoc(usbd_pipe_handle pipe); | 132 | Static usbd_status ohci_setup_isoc(usbd_pipe_handle pipe); | |
132 | Static void ohci_device_isoc_enter(usbd_xfer_handle); | 133 | Static void ohci_device_isoc_enter(usbd_xfer_handle); | |
133 | 134 | |||
134 | Static usbd_status ohci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); | 135 | Static usbd_status ohci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); | |
135 | Static void ohci_freem(struct usbd_bus *, usb_dma_t *); | 136 | Static void ohci_freem(struct usbd_bus *, usb_dma_t *); | |
136 | 137 | |||
137 | Static usbd_xfer_handle ohci_allocx(struct usbd_bus *); | 138 | Static usbd_xfer_handle ohci_allocx(struct usbd_bus *); | |
138 | Static void ohci_freex(struct usbd_bus *, usbd_xfer_handle); | 139 | Static void ohci_freex(struct usbd_bus *, usbd_xfer_handle); | |
139 | Static void ohci_get_locks(struct usbd_bus *, kmutex_t **, | 140 | Static void ohci_get_locks(struct usbd_bus *, kmutex_t **, | |
140 | kmutex_t **); | 141 | kmutex_t **); | |
141 | 142 | |||
142 | Static usbd_status ohci_root_ctrl_transfer(usbd_xfer_handle); | 143 | Static usbd_status ohci_root_ctrl_transfer(usbd_xfer_handle); | |
143 | Static usbd_status ohci_root_ctrl_start(usbd_xfer_handle); | 144 | Static usbd_status ohci_root_ctrl_start(usbd_xfer_handle); | |
144 | Static void ohci_root_ctrl_abort(usbd_xfer_handle); | 145 | Static void ohci_root_ctrl_abort(usbd_xfer_handle); | |
145 | Static void ohci_root_ctrl_close(usbd_pipe_handle); | 146 | Static void ohci_root_ctrl_close(usbd_pipe_handle); | |
146 | Static void ohci_root_ctrl_done(usbd_xfer_handle); | 147 | Static void ohci_root_ctrl_done(usbd_xfer_handle); | |
147 | 148 | |||
148 | Static usbd_status ohci_root_intr_transfer(usbd_xfer_handle); | 149 | Static usbd_status ohci_root_intr_transfer(usbd_xfer_handle); | |
149 | Static usbd_status ohci_root_intr_start(usbd_xfer_handle); | 150 | Static usbd_status ohci_root_intr_start(usbd_xfer_handle); | |
150 | Static void ohci_root_intr_abort(usbd_xfer_handle); | 151 | Static void ohci_root_intr_abort(usbd_xfer_handle); | |
151 | Static void ohci_root_intr_close(usbd_pipe_handle); | 152 | Static void ohci_root_intr_close(usbd_pipe_handle); | |
152 | Static void ohci_root_intr_done(usbd_xfer_handle); | 153 | Static void ohci_root_intr_done(usbd_xfer_handle); | |
153 | 154 | |||
154 | Static usbd_status ohci_device_ctrl_transfer(usbd_xfer_handle); | 155 | Static usbd_status ohci_device_ctrl_transfer(usbd_xfer_handle); | |
155 | Static usbd_status ohci_device_ctrl_start(usbd_xfer_handle); | 156 | Static usbd_status ohci_device_ctrl_start(usbd_xfer_handle); | |
156 | Static void ohci_device_ctrl_abort(usbd_xfer_handle); | 157 | Static void ohci_device_ctrl_abort(usbd_xfer_handle); | |
157 | Static void ohci_device_ctrl_close(usbd_pipe_handle); | 158 | Static void ohci_device_ctrl_close(usbd_pipe_handle); | |
158 | Static void ohci_device_ctrl_done(usbd_xfer_handle); | 159 | Static void ohci_device_ctrl_done(usbd_xfer_handle); | |
159 | 160 | |||
160 | Static usbd_status ohci_device_bulk_transfer(usbd_xfer_handle); | 161 | Static usbd_status ohci_device_bulk_transfer(usbd_xfer_handle); | |
161 | Static usbd_status ohci_device_bulk_start(usbd_xfer_handle); | 162 | Static usbd_status ohci_device_bulk_start(usbd_xfer_handle); | |
162 | Static void ohci_device_bulk_abort(usbd_xfer_handle); | 163 | Static void ohci_device_bulk_abort(usbd_xfer_handle); | |
163 | Static void ohci_device_bulk_close(usbd_pipe_handle); | 164 | Static void ohci_device_bulk_close(usbd_pipe_handle); | |
164 | Static void ohci_device_bulk_done(usbd_xfer_handle); | 165 | Static void ohci_device_bulk_done(usbd_xfer_handle); | |
165 | 166 | |||
166 | Static usbd_status ohci_device_intr_transfer(usbd_xfer_handle); | 167 | Static usbd_status ohci_device_intr_transfer(usbd_xfer_handle); | |
167 | Static usbd_status ohci_device_intr_start(usbd_xfer_handle); | 168 | Static usbd_status ohci_device_intr_start(usbd_xfer_handle); | |
168 | Static void ohci_device_intr_abort(usbd_xfer_handle); | 169 | Static void ohci_device_intr_abort(usbd_xfer_handle); | |
169 | Static void ohci_device_intr_close(usbd_pipe_handle); | 170 | Static void ohci_device_intr_close(usbd_pipe_handle); | |
170 | Static void ohci_device_intr_done(usbd_xfer_handle); | 171 | Static void ohci_device_intr_done(usbd_xfer_handle); | |
171 | 172 | |||
172 | Static usbd_status ohci_device_isoc_transfer(usbd_xfer_handle); | 173 | Static usbd_status ohci_device_isoc_transfer(usbd_xfer_handle); | |
173 | Static usbd_status ohci_device_isoc_start(usbd_xfer_handle); | 174 | Static usbd_status ohci_device_isoc_start(usbd_xfer_handle); | |
174 | Static void ohci_device_isoc_abort(usbd_xfer_handle); | 175 | Static void ohci_device_isoc_abort(usbd_xfer_handle); | |
175 | Static void ohci_device_isoc_close(usbd_pipe_handle); | 176 | Static void ohci_device_isoc_close(usbd_pipe_handle); | |
176 | Static void ohci_device_isoc_done(usbd_xfer_handle); | 177 | Static void ohci_device_isoc_done(usbd_xfer_handle); | |
177 | 178 | |||
178 | Static usbd_status ohci_device_setintr(ohci_softc_t *sc, | 179 | Static usbd_status ohci_device_setintr(ohci_softc_t *sc, | |
179 | struct ohci_pipe *pipe, int ival); | 180 | struct ohci_pipe *pipe, int ival); | |
180 | 181 | |||
181 | Static void ohci_timeout(void *); | 182 | Static void ohci_timeout(void *); | |
182 | Static void ohci_timeout_task(void *); | 183 | Static void ohci_timeout_task(void *); | |
183 | Static void ohci_rhsc_enable(void *); | 184 | Static void ohci_rhsc_enable(void *); | |
184 | 185 | |||
185 | Static void ohci_close_pipe(usbd_pipe_handle, ohci_soft_ed_t *); | 186 | Static void ohci_close_pipe(usbd_pipe_handle, ohci_soft_ed_t *); | |
186 | Static void ohci_abort_xfer(usbd_xfer_handle, usbd_status); | 187 | Static void ohci_abort_xfer(usbd_xfer_handle, usbd_status); | |
187 | 188 | |||
188 | Static void ohci_device_clear_toggle(usbd_pipe_handle pipe); | 189 | Static void ohci_device_clear_toggle(usbd_pipe_handle pipe); | |
189 | Static void ohci_noop(usbd_pipe_handle pipe); | 190 | Static void ohci_noop(usbd_pipe_handle pipe); | |
190 | 191 | |||
191 | #ifdef OHCI_DEBUG | 192 | #ifdef OHCI_DEBUG | |
192 | Static void ohci_dumpregs(ohci_softc_t *); | 193 | Static void ohci_dumpregs(ohci_softc_t *); | |
193 | Static void ohci_dump_tds(ohci_softc_t *, ohci_soft_td_t *); | 194 | Static void ohci_dump_tds(ohci_softc_t *, ohci_soft_td_t *); | |
194 | Static void ohci_dump_td(ohci_softc_t *, ohci_soft_td_t *); | 195 | Static void ohci_dump_td(ohci_softc_t *, ohci_soft_td_t *); | |
195 | Static void ohci_dump_ed(ohci_softc_t *, ohci_soft_ed_t *); | 196 | Static void ohci_dump_ed(ohci_softc_t *, ohci_soft_ed_t *); | |
196 | Static void ohci_dump_itd(ohci_softc_t *, ohci_soft_itd_t *); | 197 | Static void ohci_dump_itd(ohci_softc_t *, ohci_soft_itd_t *); | |
197 | Static void ohci_dump_itds(ohci_softc_t *, ohci_soft_itd_t *); | 198 | Static void ohci_dump_itds(ohci_softc_t *, ohci_soft_itd_t *); | |
198 | #endif | 199 | #endif | |
199 | 200 | |||
200 | #define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ | 201 | #define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ | |
201 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) | 202 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) | |
202 | #define OWRITE1(sc, r, x) \ | 203 | #define OWRITE1(sc, r, x) \ | |
203 | do { OBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | 204 | do { OBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | |
204 | #define OWRITE2(sc, r, x) \ | 205 | #define OWRITE2(sc, r, x) \ | |
205 | do { OBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | 206 | do { OBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | |
206 | #define OWRITE4(sc, r, x) \ | 207 | #define OWRITE4(sc, r, x) \ | |
207 | do { OBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | 208 | do { OBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | |
208 | static __inline uint8_t | 209 | static __inline uint8_t | |
209 | OREAD1(ohci_softc_t *sc, bus_size_t r) | 210 | OREAD1(ohci_softc_t *sc, bus_size_t r) | |
210 | { | 211 | { | |
211 | 212 | |||
212 | OBARR(sc); | 213 | OBARR(sc); | |
213 | return bus_space_read_1(sc->iot, sc->ioh, r); | 214 | return bus_space_read_1(sc->iot, sc->ioh, r); | |
214 | } | 215 | } | |
215 | 216 | |||
216 | static __inline uint16_t | 217 | static __inline uint16_t | |
217 | OREAD2(ohci_softc_t *sc, bus_size_t r) | 218 | OREAD2(ohci_softc_t *sc, bus_size_t r) | |
218 | { | 219 | { | |
219 | 220 | |||
220 | OBARR(sc); | 221 | OBARR(sc); | |
221 | return bus_space_read_2(sc->iot, sc->ioh, r); | 222 | return bus_space_read_2(sc->iot, sc->ioh, r); | |
222 | } | 223 | } | |
223 | 224 | |||
224 | static __inline uint32_t | 225 | static __inline uint32_t | |
225 | OREAD4(ohci_softc_t *sc, bus_size_t r) | 226 | OREAD4(ohci_softc_t *sc, bus_size_t r) | |
226 | { | 227 | { | |
227 | 228 | |||
228 | OBARR(sc); | 229 | OBARR(sc); | |
229 | return bus_space_read_4(sc->iot, sc->ioh, r); | 230 | return bus_space_read_4(sc->iot, sc->ioh, r); | |
230 | } | 231 | } | |
231 | 232 | |||
232 | /* Reverse the bits in a value 0 .. 31 */ | 233 | /* Reverse the bits in a value 0 .. 31 */ | |
233 | Static u_int8_t revbits[OHCI_NO_INTRS] = | 234 | Static u_int8_t revbits[OHCI_NO_INTRS] = | |
234 | { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, | 235 | { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, | |
235 | 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, | 236 | 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, | |
236 | 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, | 237 | 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, | |
237 | 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; | 238 | 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; | |
238 | 239 | |||
239 | struct ohci_pipe { | 240 | struct ohci_pipe { | |
240 | struct usbd_pipe pipe; | 241 | struct usbd_pipe pipe; | |
241 | ohci_soft_ed_t *sed; | 242 | ohci_soft_ed_t *sed; | |
242 | union { | 243 | union { | |
243 | ohci_soft_td_t *td; | 244 | ohci_soft_td_t *td; | |
244 | ohci_soft_itd_t *itd; | 245 | ohci_soft_itd_t *itd; | |
245 | } tail; | 246 | } tail; | |
246 | /* Info needed for different pipe kinds. */ | 247 | /* Info needed for different pipe kinds. */ | |
247 | union { | 248 | union { | |
248 | /* Control pipe */ | 249 | /* Control pipe */ | |
249 | struct { | 250 | struct { | |
250 | usb_dma_t reqdma; | 251 | usb_dma_t reqdma; | |
251 | u_int length; | 252 | u_int length; | |
252 | ohci_soft_td_t *setup, *data, *stat; | 253 | ohci_soft_td_t *setup, *data, *stat; | |
253 | } ctl; | 254 | } ctl; | |
254 | /* Interrupt pipe */ | 255 | /* Interrupt pipe */ | |
255 | struct { | 256 | struct { | |
256 | int nslots; | 257 | int nslots; | |
257 | int pos; | 258 | int pos; | |
258 | } intr; | 259 | } intr; | |
259 | /* Bulk pipe */ | 260 | /* Bulk pipe */ | |
260 | struct { | 261 | struct { | |
261 | u_int length; | 262 | u_int length; | |
262 | int isread; | 263 | int isread; | |
263 | } bulk; | 264 | } bulk; | |
264 | /* Iso pipe */ | 265 | /* Iso pipe */ | |
265 | struct iso { | 266 | struct iso { | |
266 | int next, inuse; | 267 | int next, inuse; | |
267 | } iso; | 268 | } iso; | |
268 | } u; | 269 | } u; | |
269 | }; | 270 | }; | |
270 | 271 | |||
271 | #define OHCI_INTR_ENDPT 1 | 272 | #define OHCI_INTR_ENDPT 1 | |
272 | 273 | |||
273 | Static const struct usbd_bus_methods ohci_bus_methods = { | 274 | Static const struct usbd_bus_methods ohci_bus_methods = { | |
274 | ohci_open, | 275 | .open_pipe = ohci_open, | |
275 | ohci_softintr, | 276 | .soft_intr = ohci_softintr, | |
276 | ohci_poll, | 277 | .do_poll = ohci_poll, | |
277 | ohci_allocm, | 278 | .allocm = ohci_allocm, | |
278 | ohci_freem, | 279 | .freem = ohci_freem, | |
279 | ohci_allocx, | 280 | .allocx = ohci_allocx, | |
280 | ohci_freex, | 281 | .freex = ohci_freex, | |
281 | ohci_get_locks, | 282 | .get_locks = ohci_get_locks, | |
282 | }; | 283 | }; | |
283 | 284 | |||
284 | Static const struct usbd_pipe_methods ohci_root_ctrl_methods = { | 285 | Static const struct usbd_pipe_methods ohci_root_ctrl_methods = { | |
285 | ohci_root_ctrl_transfer, | 286 | .transfer = ohci_root_ctrl_transfer, | |
286 | ohci_root_ctrl_start, | 287 | .start = ohci_root_ctrl_start, | |
287 | ohci_root_ctrl_abort, | 288 | .abort = ohci_root_ctrl_abort, | |
288 | ohci_root_ctrl_close, | 289 | .close = ohci_root_ctrl_close, | |
289 | ohci_noop, | 290 | .cleartoggle = ohci_noop, | |
290 | ohci_root_ctrl_done, | 291 | .done = ohci_root_ctrl_done, | |
291 | }; | 292 | }; | |
292 | 293 | |||
293 | Static const struct usbd_pipe_methods ohci_root_intr_methods = { | 294 | Static const struct usbd_pipe_methods ohci_root_intr_methods = { | |
294 | ohci_root_intr_transfer, | 295 | .transfer = ohci_root_intr_transfer, | |
295 | ohci_root_intr_start, | 296 | .start = ohci_root_intr_start, | |
296 | ohci_root_intr_abort, | 297 | .abort = ohci_root_intr_abort, | |
297 | ohci_root_intr_close, | 298 | .close = ohci_root_intr_close, | |
298 | ohci_noop, | 299 | .cleartoggle = ohci_noop, | |
299 | ohci_root_intr_done, | 300 | .done = ohci_root_intr_done, | |
300 | }; | 301 | }; | |
301 | 302 | |||
302 | Static const struct usbd_pipe_methods ohci_device_ctrl_methods = { | 303 | Static const struct usbd_pipe_methods ohci_device_ctrl_methods = { | |
303 | ohci_device_ctrl_transfer, | 304 | .transfer = ohci_device_ctrl_transfer, | |
304 | ohci_device_ctrl_start, | 305 | .start = ohci_device_ctrl_start, | |
305 | ohci_device_ctrl_abort, | 306 | .abort = ohci_device_ctrl_abort, | |
306 | ohci_device_ctrl_close, | 307 | .close = ohci_device_ctrl_close, | |
307 | ohci_noop, | 308 | .cleartoggle = ohci_noop, | |
308 | ohci_device_ctrl_done, | 309 | .done = ohci_device_ctrl_done, | |
309 | }; | 310 | }; | |
310 | 311 | |||
311 | Static const struct usbd_pipe_methods ohci_device_intr_methods = { | 312 | Static const struct usbd_pipe_methods ohci_device_intr_methods = { | |
312 | ohci_device_intr_transfer, | 313 | .transfer = ohci_device_intr_transfer, | |
313 | ohci_device_intr_start, | 314 | .start = ohci_device_intr_start, | |
314 | ohci_device_intr_abort, | 315 | .abort = ohci_device_intr_abort, | |
315 | ohci_device_intr_close, | 316 | .close = ohci_device_intr_close, | |
316 | ohci_device_clear_toggle, | 317 | .cleartoggle = ohci_device_clear_toggle, | |
317 | ohci_device_intr_done, | 318 | .done = ohci_device_intr_done, | |
318 | }; | 319 | }; | |
319 | 320 | |||
320 | Static const struct usbd_pipe_methods ohci_device_bulk_methods = { | 321 | Static const struct usbd_pipe_methods ohci_device_bulk_methods = { | |
321 | ohci_device_bulk_transfer, | 322 | .transfer = ohci_device_bulk_transfer, | |
322 | ohci_device_bulk_start, | 323 | .start = ohci_device_bulk_start, | |
323 | ohci_device_bulk_abort, | 324 | .abort = ohci_device_bulk_abort, | |
324 | ohci_device_bulk_close, | 325 | .close = ohci_device_bulk_close, | |
325 | ohci_device_clear_toggle, | 326 | .cleartoggle = ohci_device_clear_toggle, | |
326 | ohci_device_bulk_done, | 327 | .done = ohci_device_bulk_done, | |
327 | }; | 328 | }; | |
328 | 329 | |||
329 | Static const struct usbd_pipe_methods ohci_device_isoc_methods = { | 330 | Static const struct usbd_pipe_methods ohci_device_isoc_methods = { | |
330 | ohci_device_isoc_transfer, | 331 | .transfer = ohci_device_isoc_transfer, | |
331 | ohci_device_isoc_start, | 332 | .start = ohci_device_isoc_start, | |
332 | ohci_device_isoc_abort, | 333 | .abort = ohci_device_isoc_abort, | |
333 | ohci_device_isoc_close, | 334 | .close = ohci_device_isoc_close, | |
334 | ohci_noop, | 335 | .cleartoggle = ohci_noop, | |
335 | ohci_device_isoc_done, | 336 | .done = ohci_device_isoc_done, | |
336 | }; | 337 | }; | |
337 | 338 | |||
338 | int | 339 | int | |
339 | ohci_activate(device_t self, enum devact act) | 340 | ohci_activate(device_t self, enum devact act) | |
340 | { | 341 | { | |
341 | struct ohci_softc *sc = device_private(self); | 342 | struct ohci_softc *sc = device_private(self); | |
342 | 343 | |||
343 | switch (act) { | 344 | switch (act) { | |
344 | case DVACT_DEACTIVATE: | 345 | case DVACT_DEACTIVATE: | |
345 | sc->sc_dying = 1; | 346 | sc->sc_dying = 1; | |
346 | return 0; | 347 | return 0; | |
347 | default: | 348 | default: | |
348 | return EOPNOTSUPP; | 349 | return EOPNOTSUPP; | |
349 | } | 350 | } | |
350 | } | 351 | } | |
351 | 352 | |||
352 | void | 353 | void | |
353 | ohci_childdet(device_t self, device_t child) | 354 | ohci_childdet(device_t self, device_t child) | |
354 | { | 355 | { | |
355 | struct ohci_softc *sc = device_private(self); | 356 | struct ohci_softc *sc = device_private(self); | |
356 | 357 | |||
357 | KASSERT(sc->sc_child == child); | 358 | KASSERT(sc->sc_child == child); | |
358 | sc->sc_child = NULL; | 359 | sc->sc_child = NULL; | |
359 | } | 360 | } | |
360 | 361 | |||
361 | int | 362 | int | |
362 | ohci_detach(struct ohci_softc *sc, int flags) | 363 | ohci_detach(struct ohci_softc *sc, int flags) | |
363 | { | 364 | { | |
364 | int rv = 0; | 365 | int rv = 0; | |
365 | usbd_xfer_handle xfer; | 366 | usbd_xfer_handle xfer; | |
366 | 367 | |||
367 | if (sc->sc_child != NULL) | 368 | if (sc->sc_child != NULL) | |
368 | rv = config_detach(sc->sc_child, flags); | 369 | rv = config_detach(sc->sc_child, flags); | |
369 | 370 | |||
370 | if (rv != 0) | 371 | if (rv != 0) | |
371 | return (rv); | 372 | return (rv); | |
372 | 373 | |||
373 | callout_stop(&sc->sc_tmo_rhsc); | 374 | callout_stop(&sc->sc_tmo_rhsc); | |
374 | 375 | |||
375 | usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ | 376 | usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ | |
376 | callout_destroy(&sc->sc_tmo_rhsc); | 377 | callout_destroy(&sc->sc_tmo_rhsc); | |
377 | 378 | |||
378 | softint_disestablish(sc->sc_rhsc_si); | 379 | softint_disestablish(sc->sc_rhsc_si); | |
379 | 380 | |||
380 | cv_destroy(&sc->sc_softwake_cv); | 381 | cv_destroy(&sc->sc_softwake_cv); | |
381 | 382 | |||
382 | mutex_destroy(&sc->sc_lock); | 383 | mutex_destroy(&sc->sc_lock); | |
383 | mutex_destroy(&sc->sc_intr_lock); | 384 | mutex_destroy(&sc->sc_intr_lock); | |
384 | 385 | |||
385 | if (sc->sc_hcca != NULL) | 386 | if (sc->sc_hcca != NULL) | |
386 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | 387 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | |
387 | while((xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers)) != NULL) { | 388 | while((xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers)) != NULL) { | |
388 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | 389 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | |
389 | kmem_free(xfer, sizeof(struct ohci_xfer)); | 390 | kmem_free(xfer, sizeof(struct ohci_xfer)); | |
390 | } | 391 | } | |
391 | 392 | |||
392 | return (rv); | 393 | return (rv); | |
393 | } | 394 | } | |
394 | 395 | |||
395 | ohci_soft_ed_t * | 396 | ohci_soft_ed_t * | |
396 | ohci_alloc_sed(ohci_softc_t *sc) | 397 | ohci_alloc_sed(ohci_softc_t *sc) | |
397 | { | 398 | { | |
398 | ohci_soft_ed_t *sed; | 399 | ohci_soft_ed_t *sed; | |
399 | usbd_status err; | 400 | usbd_status err; | |
400 | int i, offs; | 401 | int i, offs; | |
401 | usb_dma_t dma; | 402 | usb_dma_t dma; | |
402 | 403 | |||
403 | if (sc->sc_freeeds == NULL) { | 404 | if (sc->sc_freeeds == NULL) { | |
404 | DPRINTFN(2, ("ohci_alloc_sed: allocating chunk\n")); | 405 | DPRINTFN(2, ("ohci_alloc_sed: allocating chunk\n")); | |
405 | err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK, | 406 | err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK, | |
406 | OHCI_ED_ALIGN, &dma); | 407 | OHCI_ED_ALIGN, &dma); | |
407 | if (err) | 408 | if (err) | |
408 | return (0); | 409 | return (0); | |
409 | for(i = 0; i < OHCI_SED_CHUNK; i++) { | 410 | for(i = 0; i < OHCI_SED_CHUNK; i++) { | |
410 | offs = i * OHCI_SED_SIZE; | 411 | offs = i * OHCI_SED_SIZE; | |
411 | sed = KERNADDR(&dma, offs); | 412 | sed = KERNADDR(&dma, offs); | |
412 | sed->physaddr = DMAADDR(&dma, offs); | 413 | sed->physaddr = DMAADDR(&dma, offs); | |
413 | sed->dma = dma; | 414 | sed->dma = dma; | |
414 | sed->offs = offs; | 415 | sed->offs = offs; | |
415 | sed->next = sc->sc_freeeds; | 416 | sed->next = sc->sc_freeeds; | |
416 | sc->sc_freeeds = sed; | 417 | sc->sc_freeeds = sed; | |
417 | } | 418 | } | |
418 | } | 419 | } | |
419 | sed = sc->sc_freeeds; | 420 | sed = sc->sc_freeeds; | |
420 | sc->sc_freeeds = sed->next; | 421 | sc->sc_freeeds = sed->next; | |
421 | memset(&sed->ed, 0, sizeof(ohci_ed_t)); | 422 | memset(&sed->ed, 0, sizeof(ohci_ed_t)); | |
422 | sed->next = 0; | 423 | sed->next = 0; | |
423 | return (sed); | 424 | return (sed); | |
424 | } | 425 | } | |
425 | 426 | |||
426 | void | 427 | void | |
427 | ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed) | 428 | ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed) | |
428 | { | 429 | { | |
429 | sed->next = sc->sc_freeeds; | 430 | sed->next = sc->sc_freeeds; | |
430 | sc->sc_freeeds = sed; | 431 | sc->sc_freeeds = sed; | |
431 | } | 432 | } | |
432 | 433 | |||
433 | ohci_soft_td_t * | 434 | ohci_soft_td_t * | |
434 | ohci_alloc_std(ohci_softc_t *sc) | 435 | ohci_alloc_std(ohci_softc_t *sc) | |
435 | { | 436 | { | |
436 | ohci_soft_td_t *std; | 437 | ohci_soft_td_t *std; | |
437 | usbd_status err; | 438 | usbd_status err; | |
438 | int i, offs; | 439 | int i, offs; | |
439 | usb_dma_t dma; | 440 | usb_dma_t dma; | |
440 | 441 | |||
441 | if (sc->sc_freetds == NULL) { | 442 | if (sc->sc_freetds == NULL) { | |
442 | DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n")); | 443 | DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n")); | |
443 | err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK, | 444 | err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK, | |
444 | OHCI_TD_ALIGN, &dma); | 445 | OHCI_TD_ALIGN, &dma); | |
445 | if (err) | 446 | if (err) | |
446 | return (NULL); | 447 | return (NULL); | |
447 | for(i = 0; i < OHCI_STD_CHUNK; i++) { | 448 | for(i = 0; i < OHCI_STD_CHUNK; i++) { | |
448 | offs = i * OHCI_STD_SIZE; | 449 | offs = i * OHCI_STD_SIZE; | |
449 | std = KERNADDR(&dma, offs); | 450 | std = KERNADDR(&dma, offs); | |
450 | std->physaddr = DMAADDR(&dma, offs); | 451 | std->physaddr = DMAADDR(&dma, offs); | |
451 | std->dma = dma; | 452 | std->dma = dma; | |
452 | std->offs = offs; | 453 | std->offs = offs; | |
453 | std->nexttd = sc->sc_freetds; | 454 | std->nexttd = sc->sc_freetds; | |
454 | sc->sc_freetds = std; | 455 | sc->sc_freetds = std; | |
455 | } | 456 | } | |
456 | } | 457 | } | |
457 | 458 | |||
458 | std = sc->sc_freetds; | 459 | std = sc->sc_freetds; | |
459 | sc->sc_freetds = std->nexttd; | 460 | sc->sc_freetds = std->nexttd; | |
460 | memset(&std->td, 0, sizeof(ohci_td_t)); | 461 | memset(&std->td, 0, sizeof(ohci_td_t)); | |
461 | std->nexttd = NULL; | 462 | std->nexttd = NULL; | |
462 | std->xfer = NULL; | 463 | std->xfer = NULL; | |
463 | ohci_hash_add_td(sc, std); | 464 | ohci_hash_add_td(sc, std); | |
464 | 465 | |||
465 | return (std); | 466 | return (std); | |
466 | } | 467 | } | |
467 | 468 | |||
468 | void | 469 | void | |
469 | ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std) | 470 | ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std) | |
470 | { | 471 | { | |
471 | 472 | |||
472 | ohci_hash_rem_td(sc, std); | 473 | ohci_hash_rem_td(sc, std); | |
473 | std->nexttd = sc->sc_freetds; | 474 | std->nexttd = sc->sc_freetds; | |
474 | sc->sc_freetds = std; | 475 | sc->sc_freetds = std; | |
475 | } | 476 | } | |
476 | 477 | |||
477 | usbd_status | 478 | usbd_status | |
478 | ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc, | 479 | ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc, | |
479 | int alen, int rd, usbd_xfer_handle xfer, | 480 | int alen, int rd, usbd_xfer_handle xfer, | |
480 | ohci_soft_td_t *sp, ohci_soft_td_t **ep) | 481 | ohci_soft_td_t *sp, ohci_soft_td_t **ep) | |
481 | { | 482 | { | |
482 | ohci_soft_td_t *next, *cur; | 483 | ohci_soft_td_t *next, *cur; | |
483 | ohci_physaddr_t dataphys, dataphysend; | 484 | ohci_physaddr_t dataphys, dataphysend; | |
484 | u_int32_t tdflags; | 485 | u_int32_t tdflags; | |
485 | int len, curlen; | 486 | int len, curlen; | |
486 | usb_dma_t *dma = &xfer->dmabuf; | 487 | usb_dma_t *dma = &xfer->dmabuf; | |
487 | u_int16_t flags = xfer->flags; | 488 | u_int16_t flags = xfer->flags; | |
488 | 489 | |||
489 | DPRINTFN(alen < 4096,("ohci_alloc_std_chain: start len=%d\n", alen)); | 490 | DPRINTFN(alen < 4096,("ohci_alloc_std_chain: start len=%d\n", alen)); | |
490 | 491 | |||
491 | KASSERT(mutex_owned(&sc->sc_lock)); | 492 | KASSERT(mutex_owned(&sc->sc_lock)); | |
492 | 493 | |||
493 | len = alen; | 494 | len = alen; | |
494 | cur = sp; | 495 | cur = sp; | |
495 | dataphys = DMAADDR(dma, 0); | 496 | dataphys = DMAADDR(dma, 0); | |
496 | dataphysend = OHCI_PAGE(dataphys + len - 1); | 497 | dataphysend = OHCI_PAGE(dataphys + len - 1); | |
497 | usb_syncmem(dma, 0, len, | 498 | usb_syncmem(dma, 0, len, | |
498 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | 499 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | |
499 | tdflags = HTOO32( | 500 | tdflags = HTOO32( | |
500 | (rd ? OHCI_TD_IN : OHCI_TD_OUT) | | 501 | (rd ? OHCI_TD_IN : OHCI_TD_OUT) | | |
501 | (flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0) | | 502 | (flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0) | | |
502 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); | 503 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); | |
503 | 504 | |||
504 | for (;;) { | 505 | for (;;) { | |
505 | next = ohci_alloc_std(sc); | 506 | next = ohci_alloc_std(sc); | |
506 | if (next == NULL) | 507 | if (next == NULL) | |
507 | goto nomem; | 508 | goto nomem; | |
508 | 509 | |||
509 | /* The OHCI hardware can handle at most one page crossing. */ | 510 | /* The OHCI hardware can handle at most one page crossing. */ | |
510 | if (OHCI_PAGE(dataphys) == dataphysend || | 511 | if (OHCI_PAGE(dataphys) == dataphysend || | |
511 | OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) { | 512 | OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) { | |
512 | /* we can handle it in this TD */ | 513 | /* we can handle it in this TD */ | |
513 | curlen = len; | 514 | curlen = len; | |
514 | } else { | 515 | } else { | |
515 | /* must use multiple TDs, fill as much as possible. */ | 516 | /* must use multiple TDs, fill as much as possible. */ | |
516 | curlen = 2 * OHCI_PAGE_SIZE - | 517 | curlen = 2 * OHCI_PAGE_SIZE - | |
517 | (dataphys & (OHCI_PAGE_SIZE-1)); | 518 | (dataphys & (OHCI_PAGE_SIZE-1)); | |
518 | /* the length must be a multiple of the max size */ | 519 | /* the length must be a multiple of the max size */ | |
519 | curlen -= curlen % UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize); | 520 | curlen -= curlen % UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize); | |
520 | #ifdef DIAGNOSTIC | 521 | #ifdef DIAGNOSTIC | |
521 | if (curlen == 0) | 522 | if (curlen == 0) | |
522 | panic("ohci_alloc_std: curlen == 0"); | 523 | panic("ohci_alloc_std: curlen == 0"); | |
523 | #endif | 524 | #endif | |
524 | } | 525 | } | |
525 | DPRINTFN(4,("ohci_alloc_std_chain: dataphys=0x%08x " | 526 | DPRINTFN(4,("ohci_alloc_std_chain: dataphys=0x%08x " | |
526 | "dataphysend=0x%08x len=%d curlen=%d\n", | 527 | "dataphysend=0x%08x len=%d curlen=%d\n", | |
527 | dataphys, dataphysend, | 528 | dataphys, dataphysend, | |
528 | len, curlen)); | 529 | len, curlen)); | |
529 | len -= curlen; | 530 | len -= curlen; | |
530 | 531 | |||
531 | cur->td.td_flags = tdflags; | 532 | cur->td.td_flags = tdflags; | |
532 | cur->td.td_cbp = HTOO32(dataphys); | 533 | cur->td.td_cbp = HTOO32(dataphys); | |
533 | cur->nexttd = next; | 534 | cur->nexttd = next; | |
534 | cur->td.td_nexttd = HTOO32(next->physaddr); | 535 | cur->td.td_nexttd = HTOO32(next->physaddr); | |
535 | cur->td.td_be = HTOO32(dataphys + curlen - 1); | 536 | cur->td.td_be = HTOO32(dataphys + curlen - 1); | |
536 | cur->len = curlen; | 537 | cur->len = curlen; | |
537 | cur->flags = OHCI_ADD_LEN; | 538 | cur->flags = OHCI_ADD_LEN; | |
538 | cur->xfer = xfer; | 539 | cur->xfer = xfer; | |
539 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), | 540 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), | |
540 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 541 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
541 | DPRINTFN(10,("ohci_alloc_std_chain: cbp=0x%08x be=0x%08x\n", | 542 | DPRINTFN(10,("ohci_alloc_std_chain: cbp=0x%08x be=0x%08x\n", | |
542 | dataphys, dataphys + curlen - 1)); | 543 | dataphys, dataphys + curlen - 1)); | |
543 | if (len == 0) | 544 | if (len == 0) | |
544 | break; | 545 | break; | |
545 | DPRINTFN(10,("ohci_alloc_std_chain: extend chain\n")); | 546 | DPRINTFN(10,("ohci_alloc_std_chain: extend chain\n")); | |
546 | dataphys += curlen; | 547 | dataphys += curlen; | |
547 | cur = next; | 548 | cur = next; | |
548 | } | 549 | } | |
549 | if (!rd && (flags & USBD_FORCE_SHORT_XFER) && | 550 | if (!rd && (flags & USBD_FORCE_SHORT_XFER) && | |
550 | alen % UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize) == 0) { | 551 | alen % UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize) == 0) { | |
551 | /* Force a 0 length transfer at the end. */ | 552 | /* Force a 0 length transfer at the end. */ | |
552 | 553 | |||
553 | cur = next; | 554 | cur = next; | |
554 | next = ohci_alloc_std(sc); | 555 | next = ohci_alloc_std(sc); | |
555 | if (next == NULL) | 556 | if (next == NULL) | |
556 | goto nomem; | 557 | goto nomem; | |
557 | 558 | |||
558 | cur->td.td_flags = tdflags; | 559 | cur->td.td_flags = tdflags; | |
559 | cur->td.td_cbp = 0; /* indicate 0 length packet */ | 560 | cur->td.td_cbp = 0; /* indicate 0 length packet */ | |
560 | cur->nexttd = next; | 561 | cur->nexttd = next; | |
561 | cur->td.td_nexttd = HTOO32(next->physaddr); | 562 | cur->td.td_nexttd = HTOO32(next->physaddr); | |
562 | cur->td.td_be = ~0; | 563 | cur->td.td_be = ~0; | |
563 | cur->len = 0; | 564 | cur->len = 0; | |
564 | cur->flags = 0; | 565 | cur->flags = 0; | |
565 | cur->xfer = xfer; | 566 | cur->xfer = xfer; | |
566 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), | 567 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), | |
567 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 568 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
568 | DPRINTFN(2,("ohci_alloc_std_chain: add 0 xfer\n")); | 569 | DPRINTFN(2,("ohci_alloc_std_chain: add 0 xfer\n")); | |
569 | } | 570 | } | |
570 | *ep = cur; | 571 | *ep = cur; | |
571 | 572 | |||
572 | return (USBD_NORMAL_COMPLETION); | 573 | return (USBD_NORMAL_COMPLETION); | |
573 | 574 | |||
574 | nomem: | 575 | nomem: | |
575 | /* XXX free chain */ | 576 | /* XXX free chain */ | |
576 | return (USBD_NOMEM); | 577 | return (USBD_NOMEM); | |
577 | } | 578 | } | |
578 | 579 | |||
579 | #if 0 | 580 | #if 0 | |
580 | Static void | 581 | Static void | |
581 | ohci_free_std_chain(ohci_softc_t *sc, ohci_soft_td_t *std, | 582 | ohci_free_std_chain(ohci_softc_t *sc, ohci_soft_td_t *std, | |
582 | ohci_soft_td_t *stdend) | 583 | ohci_soft_td_t *stdend) | |
583 | { | 584 | { | |
584 | ohci_soft_td_t *p; | 585 | ohci_soft_td_t *p; | |
585 | 586 | |||
586 | for (; std != stdend; std = p) { | 587 | for (; std != stdend; std = p) { | |
587 | p = std->nexttd; | 588 | p = std->nexttd; | |
588 | ohci_free_std(sc, std); | 589 | ohci_free_std(sc, std); | |
589 | } | 590 | } | |
590 | } | 591 | } | |
591 | #endif | 592 | #endif | |
592 | 593 | |||
593 | ohci_soft_itd_t * | 594 | ohci_soft_itd_t * | |
594 | ohci_alloc_sitd(ohci_softc_t *sc) | 595 | ohci_alloc_sitd(ohci_softc_t *sc) | |
595 | { | 596 | { | |
596 | ohci_soft_itd_t *sitd; | 597 | ohci_soft_itd_t *sitd; | |
597 | usbd_status err; | 598 | usbd_status err; | |
598 | int i, offs; | 599 | int i, offs; | |
599 | usb_dma_t dma; | 600 | usb_dma_t dma; | |
600 | 601 | |||
601 | if (sc->sc_freeitds == NULL) { | 602 | if (sc->sc_freeitds == NULL) { | |
602 | DPRINTFN(2, ("ohci_alloc_sitd: allocating chunk\n")); | 603 | DPRINTFN(2, ("ohci_alloc_sitd: allocating chunk\n")); | |
603 | err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK, | 604 | err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK, | |
604 | OHCI_ITD_ALIGN, &dma); | 605 | OHCI_ITD_ALIGN, &dma); | |
605 | if (err) | 606 | if (err) | |
606 | return (NULL); | 607 | return (NULL); | |
607 | for(i = 0; i < OHCI_SITD_CHUNK; i++) { | 608 | for(i = 0; i < OHCI_SITD_CHUNK; i++) { | |
608 | offs = i * OHCI_SITD_SIZE; | 609 | offs = i * OHCI_SITD_SIZE; | |
609 | sitd = KERNADDR(&dma, offs); | 610 | sitd = KERNADDR(&dma, offs); | |
610 | sitd->physaddr = DMAADDR(&dma, offs); | 611 | sitd->physaddr = DMAADDR(&dma, offs); | |
611 | sitd->dma = dma; | 612 | sitd->dma = dma; | |
612 | sitd->offs = offs; | 613 | sitd->offs = offs; | |
613 | sitd->nextitd = sc->sc_freeitds; | 614 | sitd->nextitd = sc->sc_freeitds; | |
614 | sc->sc_freeitds = sitd; | 615 | sc->sc_freeitds = sitd; | |
615 | } | 616 | } | |
616 | } | 617 | } | |
617 | 618 | |||
618 | sitd = sc->sc_freeitds; | 619 | sitd = sc->sc_freeitds; | |
619 | sc->sc_freeitds = sitd->nextitd; | 620 | sc->sc_freeitds = sitd->nextitd; | |
620 | memset(&sitd->itd, 0, sizeof(ohci_itd_t)); | 621 | memset(&sitd->itd, 0, sizeof(ohci_itd_t)); | |
621 | sitd->nextitd = NULL; | 622 | sitd->nextitd = NULL; | |
622 | sitd->xfer = NULL; | 623 | sitd->xfer = NULL; | |
623 | ohci_hash_add_itd(sc, sitd); | 624 | ohci_hash_add_itd(sc, sitd); | |
624 | 625 | |||
625 | #ifdef DIAGNOSTIC | 626 | #ifdef DIAGNOSTIC | |
626 | sitd->isdone = 0; | 627 | sitd->isdone = 0; | |
627 | #endif | 628 | #endif | |
628 | 629 | |||
629 | return (sitd); | 630 | return (sitd); | |
630 | } | 631 | } | |
631 | 632 | |||
632 | void | 633 | void | |
633 | ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | 634 | ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | |
634 | { | 635 | { | |
635 | 636 | |||
636 | DPRINTFN(10,("ohci_free_sitd: sitd=%p\n", sitd)); | 637 | DPRINTFN(10,("ohci_free_sitd: sitd=%p\n", sitd)); | |
637 | 638 | |||
638 | #ifdef DIAGNOSTIC | 639 | #ifdef DIAGNOSTIC | |
639 | if (!sitd->isdone) { | 640 | if (!sitd->isdone) { | |
640 | panic("ohci_free_sitd: sitd=%p not done", sitd); | 641 | panic("ohci_free_sitd: sitd=%p not done", sitd); | |
641 | return; | 642 | return; | |
642 | } | 643 | } | |
643 | /* Warn double free */ | 644 | /* Warn double free */ | |
644 | sitd->isdone = 0; | 645 | sitd->isdone = 0; | |
645 | #endif | 646 | #endif | |
646 | 647 | |||
647 | ohci_hash_rem_itd(sc, sitd); | 648 | ohci_hash_rem_itd(sc, sitd); | |
648 | sitd->nextitd = sc->sc_freeitds; | 649 | sitd->nextitd = sc->sc_freeitds; | |
649 | sc->sc_freeitds = sitd; | 650 | sc->sc_freeitds = sitd; | |
650 | } | 651 | } | |
651 | 652 | |||
652 | usbd_status | 653 | usbd_status | |
653 | ohci_init(ohci_softc_t *sc) | 654 | ohci_init(ohci_softc_t *sc) | |
654 | { | 655 | { | |
655 | ohci_soft_ed_t *sed, *psed; | 656 | ohci_soft_ed_t *sed, *psed; | |
656 | usbd_status err; | 657 | usbd_status err; | |
657 | int i; | 658 | int i; | |
658 | u_int32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca, descb; | 659 | u_int32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca, descb; | |
659 | 660 | |||
660 | DPRINTF(("ohci_init: start\n")); | 661 | DPRINTF(("ohci_init: start\n")); | |
661 | aprint_normal_dev(sc->sc_dev, ""); | 662 | aprint_normal_dev(sc->sc_dev, ""); | |
662 | 663 | |||
663 | sc->sc_hcca = NULL; | 664 | sc->sc_hcca = NULL; | |
664 | callout_init(&sc->sc_tmo_rhsc, CALLOUT_MPSAFE); | 665 | callout_init(&sc->sc_tmo_rhsc, CALLOUT_MPSAFE); | |
665 | 666 | |||
666 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | 667 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | |
667 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | 668 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | |
668 | cv_init(&sc->sc_softwake_cv, "ohciab"); | 669 | cv_init(&sc->sc_softwake_cv, "ohciab"); | |
669 | 670 | |||
670 | sc->sc_rhsc_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | 671 | sc->sc_rhsc_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | |
671 | ohci_rhsc_softint, sc); | 672 | ohci_rhsc_softint, sc); | |
672 | 673 | |||
673 | for (i = 0; i < OHCI_HASH_SIZE; i++) | 674 | for (i = 0; i < OHCI_HASH_SIZE; i++) | |
674 | LIST_INIT(&sc->sc_hash_tds[i]); | 675 | LIST_INIT(&sc->sc_hash_tds[i]); | |
675 | for (i = 0; i < OHCI_HASH_SIZE; i++) | 676 | for (i = 0; i < OHCI_HASH_SIZE; i++) | |
676 | LIST_INIT(&sc->sc_hash_itds[i]); | 677 | LIST_INIT(&sc->sc_hash_itds[i]); | |
677 | 678 | |||
678 | SIMPLEQ_INIT(&sc->sc_free_xfers); | 679 | SIMPLEQ_INIT(&sc->sc_free_xfers); | |
679 | 680 | |||
680 | rev = OREAD4(sc, OHCI_REVISION); | 681 | rev = OREAD4(sc, OHCI_REVISION); | |
681 | aprint_normal("OHCI version %d.%d%s\n", | 682 | aprint_normal("OHCI version %d.%d%s\n", | |
682 | OHCI_REV_HI(rev), OHCI_REV_LO(rev), | 683 | OHCI_REV_HI(rev), OHCI_REV_LO(rev), | |
683 | OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); | 684 | OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); | |
684 | 685 | |||
685 | if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { | 686 | if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { | |
686 | aprint_error_dev(sc->sc_dev, "unsupported OHCI revision\n"); | 687 | aprint_error_dev(sc->sc_dev, "unsupported OHCI revision\n"); | |
687 | sc->sc_bus.usbrev = USBREV_UNKNOWN; | 688 | sc->sc_bus.usbrev = USBREV_UNKNOWN; | |
688 | return (USBD_INVAL); | 689 | return (USBD_INVAL); | |
689 | } | 690 | } | |
690 | sc->sc_bus.usbrev = USBREV_1_0; | 691 | sc->sc_bus.usbrev = USBREV_1_0; | |
691 | 692 | |||
692 | usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag, | 693 | usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag, | |
693 | USB_MEM_RESERVE); | 694 | USB_MEM_RESERVE); | |
694 | 695 | |||
695 | /* XXX determine alignment by R/W */ | 696 | /* XXX determine alignment by R/W */ | |
696 | /* Allocate the HCCA area. */ | 697 | /* Allocate the HCCA area. */ | |
697 | err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, | 698 | err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, | |
698 | OHCI_HCCA_ALIGN, &sc->sc_hccadma); | 699 | OHCI_HCCA_ALIGN, &sc->sc_hccadma); | |
699 | if (err) { | 700 | if (err) { | |
700 | sc->sc_hcca = NULL; | 701 | sc->sc_hcca = NULL; | |
701 | return err; | 702 | return err; | |
702 | } | 703 | } | |
703 | sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0); | 704 | sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0); | |
704 | memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE); | 705 | memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE); | |
705 | 706 | |||
706 | sc->sc_eintrs = OHCI_NORMAL_INTRS; | 707 | sc->sc_eintrs = OHCI_NORMAL_INTRS; | |
707 | 708 | |||
708 | /* Allocate dummy ED that starts the control list. */ | 709 | /* Allocate dummy ED that starts the control list. */ | |
709 | sc->sc_ctrl_head = ohci_alloc_sed(sc); | 710 | sc->sc_ctrl_head = ohci_alloc_sed(sc); | |
710 | if (sc->sc_ctrl_head == NULL) { | 711 | if (sc->sc_ctrl_head == NULL) { | |
711 | err = USBD_NOMEM; | 712 | err = USBD_NOMEM; | |
712 | goto bad1; | 713 | goto bad1; | |
713 | } | 714 | } | |
714 | sc->sc_ctrl_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | 715 | sc->sc_ctrl_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | |
715 | 716 | |||
716 | /* Allocate dummy ED that starts the bulk list. */ | 717 | /* Allocate dummy ED that starts the bulk list. */ | |
717 | sc->sc_bulk_head = ohci_alloc_sed(sc); | 718 | sc->sc_bulk_head = ohci_alloc_sed(sc); | |
718 | if (sc->sc_bulk_head == NULL) { | 719 | if (sc->sc_bulk_head == NULL) { | |
719 | err = USBD_NOMEM; | 720 | err = USBD_NOMEM; | |
720 | goto bad2; | 721 | goto bad2; | |
721 | } | 722 | } | |
722 | sc->sc_bulk_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | 723 | sc->sc_bulk_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | |
723 | usb_syncmem(&sc->sc_bulk_head->dma, sc->sc_bulk_head->offs, | 724 | usb_syncmem(&sc->sc_bulk_head->dma, sc->sc_bulk_head->offs, | |
724 | sizeof(sc->sc_bulk_head->ed), | 725 | sizeof(sc->sc_bulk_head->ed), | |
725 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 726 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
726 | 727 | |||
727 | /* Allocate dummy ED that starts the isochronous list. */ | 728 | /* Allocate dummy ED that starts the isochronous list. */ | |
728 | sc->sc_isoc_head = ohci_alloc_sed(sc); | 729 | sc->sc_isoc_head = ohci_alloc_sed(sc); | |
729 | if (sc->sc_isoc_head == NULL) { | 730 | if (sc->sc_isoc_head == NULL) { | |
730 | err = USBD_NOMEM; | 731 | err = USBD_NOMEM; | |
731 | goto bad3; | 732 | goto bad3; | |
732 | } | 733 | } | |
733 | sc->sc_isoc_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | 734 | sc->sc_isoc_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | |
734 | usb_syncmem(&sc->sc_isoc_head->dma, sc->sc_isoc_head->offs, | 735 | usb_syncmem(&sc->sc_isoc_head->dma, sc->sc_isoc_head->offs, | |
735 | sizeof(sc->sc_isoc_head->ed), | 736 | sizeof(sc->sc_isoc_head->ed), | |
736 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 737 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
737 | 738 | |||
738 | /* Allocate all the dummy EDs that make up the interrupt tree. */ | 739 | /* Allocate all the dummy EDs that make up the interrupt tree. */ | |
739 | for (i = 0; i < OHCI_NO_EDS; i++) { | 740 | for (i = 0; i < OHCI_NO_EDS; i++) { | |
740 | sed = ohci_alloc_sed(sc); | 741 | sed = ohci_alloc_sed(sc); | |
741 | if (sed == NULL) { | 742 | if (sed == NULL) { | |
742 | while (--i >= 0) | 743 | while (--i >= 0) | |
743 | ohci_free_sed(sc, sc->sc_eds[i]); | 744 | ohci_free_sed(sc, sc->sc_eds[i]); | |
744 | err = USBD_NOMEM; | 745 | err = USBD_NOMEM; | |
745 | goto bad4; | 746 | goto bad4; | |
746 | } | 747 | } | |
747 | /* All ED fields are set to 0. */ | 748 | /* All ED fields are set to 0. */ | |
748 | sc->sc_eds[i] = sed; | 749 | sc->sc_eds[i] = sed; | |
749 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | 750 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | |
750 | if (i != 0) | 751 | if (i != 0) | |
751 | psed = sc->sc_eds[(i-1) / 2]; | 752 | psed = sc->sc_eds[(i-1) / 2]; | |
752 | else | 753 | else | |
753 | psed= sc->sc_isoc_head; | 754 | psed= sc->sc_isoc_head; | |
754 | sed->next = psed; | 755 | sed->next = psed; | |
755 | sed->ed.ed_nexted = HTOO32(psed->physaddr); | 756 | sed->ed.ed_nexted = HTOO32(psed->physaddr); | |
756 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 757 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
757 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 758 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
758 | } | 759 | } | |
759 | /* | 760 | /* | |
760 | * Fill HCCA interrupt table. The bit reversal is to get | 761 | * Fill HCCA interrupt table. The bit reversal is to get | |
761 | * the tree set up properly to spread the interrupts. | 762 | * the tree set up properly to spread the interrupts. | |
762 | */ | 763 | */ | |
763 | for (i = 0; i < OHCI_NO_INTRS; i++) | 764 | for (i = 0; i < OHCI_NO_INTRS; i++) | |
764 | sc->sc_hcca->hcca_interrupt_table[revbits[i]] = | 765 | sc->sc_hcca->hcca_interrupt_table[revbits[i]] = | |
765 | HTOO32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); | 766 | HTOO32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); | |
766 | usb_syncmem(&sc->sc_hccadma, 0, OHCI_HCCA_SIZE, | 767 | usb_syncmem(&sc->sc_hccadma, 0, OHCI_HCCA_SIZE, | |
767 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 768 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
768 | 769 | |||
769 | #ifdef OHCI_DEBUG | 770 | #ifdef OHCI_DEBUG | |
770 | if (ohcidebug > 15) { | 771 | if (ohcidebug > 15) { | |
771 | for (i = 0; i < OHCI_NO_EDS; i++) { | 772 | for (i = 0; i < OHCI_NO_EDS; i++) { | |
772 | printf("ed#%d ", i); | 773 | printf("ed#%d ", i); | |
773 | ohci_dump_ed(sc, sc->sc_eds[i]); | 774 | ohci_dump_ed(sc, sc->sc_eds[i]); | |
774 | } | 775 | } | |
775 | printf("iso "); | 776 | printf("iso "); | |
776 | ohci_dump_ed(sc, sc->sc_isoc_head); | 777 | ohci_dump_ed(sc, sc->sc_isoc_head); | |
777 | } | 778 | } | |
778 | #endif | 779 | #endif | |
779 | 780 | |||
780 | /* Preserve values programmed by SMM/BIOS but lost over reset. */ | 781 | /* Preserve values programmed by SMM/BIOS but lost over reset. */ | |
781 | ctl = OREAD4(sc, OHCI_CONTROL); | 782 | ctl = OREAD4(sc, OHCI_CONTROL); | |
782 | rwc = ctl & OHCI_RWC; | 783 | rwc = ctl & OHCI_RWC; | |
783 | fm = OREAD4(sc, OHCI_FM_INTERVAL); | 784 | fm = OREAD4(sc, OHCI_FM_INTERVAL); | |
784 | desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); | 785 | desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); | |
785 | descb = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); | 786 | descb = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); | |
786 | 787 | |||
787 | /* Determine in what context we are running. */ | 788 | /* Determine in what context we are running. */ | |
788 | if (ctl & OHCI_IR) { | 789 | if (ctl & OHCI_IR) { | |
789 | /* SMM active, request change */ | 790 | /* SMM active, request change */ | |
790 | DPRINTF(("ohci_init: SMM active, request owner change\n")); | 791 | DPRINTF(("ohci_init: SMM active, request owner change\n")); | |
791 | if ((sc->sc_intre & (OHCI_OC | OHCI_MIE)) == | 792 | if ((sc->sc_intre & (OHCI_OC | OHCI_MIE)) == | |
792 | (OHCI_OC | OHCI_MIE)) | 793 | (OHCI_OC | OHCI_MIE)) | |
793 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_MIE); | 794 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_MIE); | |
794 | s = OREAD4(sc, OHCI_COMMAND_STATUS); | 795 | s = OREAD4(sc, OHCI_COMMAND_STATUS); | |
795 | OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR); | 796 | OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR); | |
796 | for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { | 797 | for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { | |
797 | usb_delay_ms(&sc->sc_bus, 1); | 798 | usb_delay_ms(&sc->sc_bus, 1); | |
798 | ctl = OREAD4(sc, OHCI_CONTROL); | 799 | ctl = OREAD4(sc, OHCI_CONTROL); | |
799 | } | 800 | } | |
800 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_MIE); | 801 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_MIE); | |
801 | if ((ctl & OHCI_IR) == 0) { | 802 | if ((ctl & OHCI_IR) == 0) { | |
802 | aprint_error_dev(sc->sc_dev, | 803 | aprint_error_dev(sc->sc_dev, | |
803 | "SMM does not respond, resetting\n"); | 804 | "SMM does not respond, resetting\n"); | |
804 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); | 805 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); | |
805 | goto reset; | 806 | goto reset; | |
806 | } | 807 | } | |
807 | #if 0 | 808 | #if 0 | |
808 | /* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */ | 809 | /* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */ | |
809 | } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { | 810 | } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { | |
810 | /* BIOS started controller. */ | 811 | /* BIOS started controller. */ | |
811 | DPRINTF(("ohci_init: BIOS active\n")); | 812 | DPRINTF(("ohci_init: BIOS active\n")); | |
812 | if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) { | 813 | if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) { | |
813 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL | rwc); | 814 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL | rwc); | |
814 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | 815 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | |
815 | } | 816 | } | |
816 | #endif | 817 | #endif | |
817 | } else { | 818 | } else { | |
818 | DPRINTF(("ohci_init: cold started\n")); | 819 | DPRINTF(("ohci_init: cold started\n")); | |
819 | reset: | 820 | reset: | |
820 | /* Controller was cold started. */ | 821 | /* Controller was cold started. */ | |
821 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); | 822 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); | |
822 | } | 823 | } | |
823 | 824 | |||
824 | /* | 825 | /* | |
825 | * This reset should not be necessary according to the OHCI spec, but | 826 | * This reset should not be necessary according to the OHCI spec, but | |
826 | * without it some controllers do not start. | 827 | * without it some controllers do not start. | |
827 | */ | 828 | */ | |
828 | DPRINTF(("%s: resetting\n", device_xname(sc->sc_dev))); | 829 | DPRINTF(("%s: resetting\n", device_xname(sc->sc_dev))); | |
829 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); | 830 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); | |
830 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); | 831 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); | |
831 | 832 | |||
832 | /* We now own the host controller and the bus has been reset. */ | 833 | /* We now own the host controller and the bus has been reset. */ | |
833 | 834 | |||
834 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ | 835 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ | |
835 | /* Nominal time for a reset is 10 us. */ | 836 | /* Nominal time for a reset is 10 us. */ | |
836 | for (i = 0; i < 10; i++) { | 837 | for (i = 0; i < 10; i++) { | |
837 | delay(10); | 838 | delay(10); | |
838 | hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; | 839 | hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; | |
839 | if (!hcr) | 840 | if (!hcr) | |
840 | break; | 841 | break; | |
841 | } | 842 | } | |
842 | if (hcr) { | 843 | if (hcr) { | |
843 | aprint_error_dev(sc->sc_dev, "reset timeout\n"); | 844 | aprint_error_dev(sc->sc_dev, "reset timeout\n"); | |
844 | err = USBD_IOERROR; | 845 | err = USBD_IOERROR; | |
845 | goto bad5; | 846 | goto bad5; | |
846 | } | 847 | } | |
847 | #ifdef OHCI_DEBUG | 848 | #ifdef OHCI_DEBUG | |
848 | if (ohcidebug > 15) | 849 | if (ohcidebug > 15) | |
849 | ohci_dumpregs(sc); | 850 | ohci_dumpregs(sc); | |
850 | #endif | 851 | #endif | |
851 | 852 | |||
852 | /* The controller is now in SUSPEND state, we have 2ms to finish. */ | 853 | /* The controller is now in SUSPEND state, we have 2ms to finish. */ | |
853 | 854 | |||
854 | /* Set up HC registers. */ | 855 | /* Set up HC registers. */ | |
855 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); | 856 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); | |
856 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); | 857 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); | |
857 | OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); | 858 | OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); | |
858 | /* disable all interrupts and then switch on all desired interrupts */ | 859 | /* disable all interrupts and then switch on all desired interrupts */ | |
859 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); | 860 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); | |
860 | /* switch on desired functional features */ | 861 | /* switch on desired functional features */ | |
861 | ctl = OREAD4(sc, OHCI_CONTROL); | 862 | ctl = OREAD4(sc, OHCI_CONTROL); | |
862 | ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); | 863 | ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); | |
863 | ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | | 864 | ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | | |
864 | OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL | rwc; | 865 | OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL | rwc; | |
865 | /* And finally start it! */ | 866 | /* And finally start it! */ | |
866 | OWRITE4(sc, OHCI_CONTROL, ctl); | 867 | OWRITE4(sc, OHCI_CONTROL, ctl); | |
867 | 868 | |||
868 | /* | 869 | /* | |
869 | * The controller is now OPERATIONAL. Set a some final | 870 | * The controller is now OPERATIONAL. Set a some final | |
870 | * registers that should be set earlier, but that the | 871 | * registers that should be set earlier, but that the | |
871 | * controller ignores when in the SUSPEND state. | 872 | * controller ignores when in the SUSPEND state. | |
872 | */ | 873 | */ | |
873 | ival = OHCI_GET_IVAL(fm); | 874 | ival = OHCI_GET_IVAL(fm); | |
874 | fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; | 875 | fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; | |
875 | fm |= OHCI_FSMPS(ival) | ival; | 876 | fm |= OHCI_FSMPS(ival) | ival; | |
876 | OWRITE4(sc, OHCI_FM_INTERVAL, fm); | 877 | OWRITE4(sc, OHCI_FM_INTERVAL, fm); | |
877 | per = OHCI_PERIODIC(ival); /* 90% periodic */ | 878 | per = OHCI_PERIODIC(ival); /* 90% periodic */ | |
878 | OWRITE4(sc, OHCI_PERIODIC_START, per); | 879 | OWRITE4(sc, OHCI_PERIODIC_START, per); | |
879 | 880 | |||
880 | /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ | 881 | /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ | |
881 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); | 882 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); | |
882 | OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ | 883 | OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ | |
883 | usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY); | 884 | usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY); | |
884 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); | 885 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); | |
885 | 886 | |||
886 | /* | 887 | /* | |
887 | * The AMD756 requires a delay before re-reading the register, | 888 | * The AMD756 requires a delay before re-reading the register, | |
888 | * otherwise it will occasionally report 0 ports. | 889 | * otherwise it will occasionally report 0 ports. | |
889 | */ | 890 | */ | |
890 | sc->sc_noport = 0; | 891 | sc->sc_noport = 0; | |
891 | for (i = 0; i < 10 && sc->sc_noport == 0; i++) { | 892 | for (i = 0; i < 10 && sc->sc_noport == 0; i++) { | |
892 | usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY); | 893 | usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY); | |
893 | sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); | 894 | sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); | |
894 | } | 895 | } | |
895 | 896 | |||
896 | #ifdef OHCI_DEBUG | 897 | #ifdef OHCI_DEBUG | |
897 | if (ohcidebug > 5) | 898 | if (ohcidebug > 5) | |
898 | ohci_dumpregs(sc); | 899 | ohci_dumpregs(sc); | |
899 | #endif | 900 | #endif | |
900 | 901 | |||
901 | /* Set up the bus struct. */ | 902 | /* Set up the bus struct. */ | |
902 | sc->sc_bus.methods = &ohci_bus_methods; | 903 | sc->sc_bus.methods = &ohci_bus_methods; | |
903 | sc->sc_bus.pipe_size = sizeof(struct ohci_pipe); | 904 | sc->sc_bus.pipe_size = sizeof(struct ohci_pipe); | |
904 | 905 | |||
905 | sc->sc_control = sc->sc_intre = 0; | 906 | sc->sc_control = sc->sc_intre = 0; | |
906 | 907 | |||
907 | /* Finally, turn on interrupts. */ | 908 | /* Finally, turn on interrupts. */ | |
908 | DPRINTFN(1,("ohci_init: enabling %#x\n", sc->sc_eintrs | OHCI_MIE)); | 909 | DPRINTFN(1,("ohci_init: enabling %#x\n", sc->sc_eintrs | OHCI_MIE)); | |
909 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); | 910 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); | |
910 | 911 | |||
911 | return (USBD_NORMAL_COMPLETION); | 912 | return (USBD_NORMAL_COMPLETION); | |
912 | 913 | |||
913 | bad5: | 914 | bad5: | |
914 | for (i = 0; i < OHCI_NO_EDS; i++) | 915 | for (i = 0; i < OHCI_NO_EDS; i++) | |
915 | ohci_free_sed(sc, sc->sc_eds[i]); | 916 | ohci_free_sed(sc, sc->sc_eds[i]); | |
916 | bad4: | 917 | bad4: | |
917 | ohci_free_sed(sc, sc->sc_isoc_head); | 918 | ohci_free_sed(sc, sc->sc_isoc_head); | |
918 | bad3: | 919 | bad3: | |
919 | ohci_free_sed(sc, sc->sc_bulk_head); | 920 | ohci_free_sed(sc, sc->sc_bulk_head); | |
920 | bad2: | 921 | bad2: | |
921 | ohci_free_sed(sc, sc->sc_ctrl_head); | 922 | ohci_free_sed(sc, sc->sc_ctrl_head); | |
922 | bad1: | 923 | bad1: | |
923 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | 924 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | |
924 | sc->sc_hcca = NULL; | 925 | sc->sc_hcca = NULL; | |
925 | return (err); | 926 | return (err); | |
926 | } | 927 | } | |
927 | 928 | |||
928 | usbd_status | 929 | usbd_status | |
929 | ohci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) | 930 | ohci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) | |
930 | { | 931 | { | |
931 | struct ohci_softc *sc = bus->hci_private; | 932 | struct ohci_softc *sc = bus->hci_private; | |
932 | usbd_status status; | 933 | usbd_status status; | |
933 | 934 | |||
934 | status = usb_allocmem(&sc->sc_bus, size, 0, dma); | 935 | status = usb_allocmem(&sc->sc_bus, size, 0, dma); | |
935 | if (status == USBD_NOMEM) | 936 | if (status == USBD_NOMEM) | |
936 | status = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size); | 937 | status = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size); | |
937 | return status; | 938 | return status; | |
938 | } | 939 | } | |
939 | 940 | |||
940 | void | 941 | void | |
941 | ohci_freem(struct usbd_bus *bus, usb_dma_t *dma) | 942 | ohci_freem(struct usbd_bus *bus, usb_dma_t *dma) | |
942 | { | 943 | { | |
943 | struct ohci_softc *sc = bus->hci_private; | 944 | struct ohci_softc *sc = bus->hci_private; | |
944 | if (dma->block->flags & USB_DMA_RESERVE) { | 945 | if (dma->block->flags & USB_DMA_RESERVE) { | |
945 | usb_reserve_freem(&sc->sc_dma_reserve, dma); | 946 | usb_reserve_freem(&sc->sc_dma_reserve, dma); | |
946 | return; | 947 | return; | |
947 | } | 948 | } | |
948 | usb_freemem(&sc->sc_bus, dma); | 949 | usb_freemem(&sc->sc_bus, dma); | |
949 | } | 950 | } | |
950 | 951 | |||
951 | usbd_xfer_handle | 952 | usbd_xfer_handle | |
952 | ohci_allocx(struct usbd_bus *bus) | 953 | ohci_allocx(struct usbd_bus *bus) | |
953 | { | 954 | { | |
954 | struct ohci_softc *sc = bus->hci_private; | 955 | struct ohci_softc *sc = bus->hci_private; | |
955 | usbd_xfer_handle xfer; | 956 | usbd_xfer_handle xfer; | |
956 | 957 | |||
957 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | 958 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | |
958 | if (xfer != NULL) { | 959 | if (xfer != NULL) { | |
959 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | 960 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | |
960 | #ifdef DIAGNOSTIC | 961 | #ifdef DIAGNOSTIC | |
961 | if (xfer->busy_free != XFER_FREE) { | 962 | if (xfer->busy_free != XFER_FREE) { | |
962 | printf("ohci_allocx: xfer=%p not free, 0x%08x\n", xfer, | 963 | printf("ohci_allocx: xfer=%p not free, 0x%08x\n", xfer, | |
963 | xfer->busy_free); | 964 | xfer->busy_free); | |
964 | } | 965 | } | |
965 | #endif | 966 | #endif | |
966 | } else { | 967 | } else { | |
967 | xfer = kmem_alloc(sizeof(struct ohci_xfer), KM_SLEEP); | 968 | xfer = kmem_alloc(sizeof(struct ohci_xfer), KM_SLEEP); | |
968 | } | 969 | } | |
969 | if (xfer != NULL) { | 970 | if (xfer != NULL) { | |
970 | memset(xfer, 0, sizeof (struct ohci_xfer)); | 971 | memset(xfer, 0, sizeof (struct ohci_xfer)); | |
971 | #ifdef DIAGNOSTIC | 972 | #ifdef DIAGNOSTIC | |
972 | xfer->busy_free = XFER_BUSY; | 973 | xfer->busy_free = XFER_BUSY; | |
973 | #endif | 974 | #endif | |
974 | } | 975 | } | |
975 | return (xfer); | 976 | return (xfer); | |
976 | } | 977 | } | |
977 | 978 | |||
978 | void | 979 | void | |
979 | ohci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) | 980 | ohci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) | |
980 | { | 981 | { | |
981 | struct ohci_softc *sc = bus->hci_private; | 982 | struct ohci_softc *sc = bus->hci_private; | |
982 | 983 | |||
983 | #ifdef DIAGNOSTIC | 984 | #ifdef DIAGNOSTIC | |
984 | if (xfer->busy_free != XFER_BUSY) { | 985 | if (xfer->busy_free != XFER_BUSY) { | |
985 | printf("ohci_freex: xfer=%p not busy, 0x%08x\n", xfer, | 986 | printf("ohci_freex: xfer=%p not busy, 0x%08x\n", xfer, | |
986 | xfer->busy_free); | 987 | xfer->busy_free); | |
987 | } | 988 | } | |
988 | xfer->busy_free = XFER_FREE; | 989 | xfer->busy_free = XFER_FREE; | |
989 | #endif | 990 | #endif | |
990 | SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next); | 991 | SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next); | |
991 | } | 992 | } | |
992 | 993 | |||
993 | Static void | 994 | Static void | |
994 | ohci_get_locks(struct usbd_bus *bus, kmutex_t **intr, kmutex_t **thread) | 995 | ohci_get_locks(struct usbd_bus *bus, kmutex_t **intr, kmutex_t **thread) | |
995 | { | 996 | { | |
996 | struct ohci_softc *sc = bus->hci_private; | 997 | struct ohci_softc *sc = bus->hci_private; | |
997 | 998 | |||
998 | *intr = &sc->sc_intr_lock; | 999 | *intr = &sc->sc_intr_lock; | |
999 | *thread = &sc->sc_lock; | 1000 | *thread = &sc->sc_lock; | |
1000 | } | 1001 | } | |
1001 | 1002 | |||
1002 | /* | 1003 | /* | |
1003 | * Shut down the controller when the system is going down. | 1004 | * Shut down the controller when the system is going down. | |
1004 | */ | 1005 | */ | |
1005 | bool | 1006 | bool | |
1006 | ohci_shutdown(device_t self, int flags) | 1007 | ohci_shutdown(device_t self, int flags) | |
1007 | { | 1008 | { | |
1008 | ohci_softc_t *sc = device_private(self); | 1009 | ohci_softc_t *sc = device_private(self); | |
1009 | 1010 | |||
1010 | DPRINTF(("ohci_shutdown: stopping the HC\n")); | 1011 | DPRINTF(("ohci_shutdown: stopping the HC\n")); | |
1011 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); | 1012 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); | |
1012 | return true; | 1013 | return true; | |
1013 | } | 1014 | } | |
1014 | 1015 | |||
1015 | bool | 1016 | bool | |
1016 | ohci_resume(device_t dv, const pmf_qual_t *qual) | 1017 | ohci_resume(device_t dv, const pmf_qual_t *qual) | |
1017 | { | 1018 | { | |
1018 | ohci_softc_t *sc = device_private(dv); | 1019 | ohci_softc_t *sc = device_private(dv); | |
1019 | uint32_t ctl; | 1020 | uint32_t ctl; | |
1020 | 1021 | |||
1021 | mutex_spin_enter(&sc->sc_intr_lock); | 1022 | mutex_spin_enter(&sc->sc_intr_lock); | |
1022 | sc->sc_bus.use_polling++; | 1023 | sc->sc_bus.use_polling++; | |
1023 | mutex_spin_exit(&sc->sc_intr_lock); | 1024 | mutex_spin_exit(&sc->sc_intr_lock); | |
1024 | 1025 | |||
1025 | /* Some broken BIOSes do not recover these values */ | 1026 | /* Some broken BIOSes do not recover these values */ | |
1026 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); | 1027 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); | |
1027 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, | 1028 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, | |
1028 | sc->sc_ctrl_head->physaddr); | 1029 | sc->sc_ctrl_head->physaddr); | |
1029 | OWRITE4(sc, OHCI_BULK_HEAD_ED, | 1030 | OWRITE4(sc, OHCI_BULK_HEAD_ED, | |
1030 | sc->sc_bulk_head->physaddr); | 1031 | sc->sc_bulk_head->physaddr); | |
1031 | if (sc->sc_intre) | 1032 | if (sc->sc_intre) | |
1032 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_intre & | 1033 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_intre & | |
1033 | (OHCI_ALL_INTRS | OHCI_MIE)); | 1034 | (OHCI_ALL_INTRS | OHCI_MIE)); | |
1034 | if (sc->sc_control) | 1035 | if (sc->sc_control) | |
1035 | ctl = sc->sc_control; | 1036 | ctl = sc->sc_control; | |
1036 | else | 1037 | else | |
1037 | ctl = OREAD4(sc, OHCI_CONTROL); | 1038 | ctl = OREAD4(sc, OHCI_CONTROL); | |
1038 | ctl |= OHCI_HCFS_RESUME; | 1039 | ctl |= OHCI_HCFS_RESUME; | |
1039 | OWRITE4(sc, OHCI_CONTROL, ctl); | 1040 | OWRITE4(sc, OHCI_CONTROL, ctl); | |
1040 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | 1041 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | |
1041 | ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL; | 1042 | ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL; | |
1042 | OWRITE4(sc, OHCI_CONTROL, ctl); | 1043 | OWRITE4(sc, OHCI_CONTROL, ctl); | |
1043 | usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); | 1044 | usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); | |
1044 | sc->sc_control = sc->sc_intre = 0; | 1045 | sc->sc_control = sc->sc_intre = 0; | |
1045 | 1046 | |||
1046 | mutex_spin_enter(&sc->sc_intr_lock); | 1047 | mutex_spin_enter(&sc->sc_intr_lock); | |
1047 | sc->sc_bus.use_polling--; | 1048 | sc->sc_bus.use_polling--; | |
1048 | mutex_spin_exit(&sc->sc_intr_lock); | 1049 | mutex_spin_exit(&sc->sc_intr_lock); | |
1049 | 1050 | |||
1050 | return true; | 1051 | return true; | |
1051 | } | 1052 | } | |
1052 | 1053 | |||
1053 | bool | 1054 | bool | |
1054 | ohci_suspend(device_t dv, const pmf_qual_t *qual) | 1055 | ohci_suspend(device_t dv, const pmf_qual_t *qual) | |
1055 | { | 1056 | { | |
1056 | ohci_softc_t *sc = device_private(dv); | 1057 | ohci_softc_t *sc = device_private(dv); | |
1057 | uint32_t ctl; | 1058 | uint32_t ctl; | |
1058 | 1059 | |||
1059 | mutex_spin_enter(&sc->sc_intr_lock); | 1060 | mutex_spin_enter(&sc->sc_intr_lock); | |
1060 | sc->sc_bus.use_polling++; | 1061 | sc->sc_bus.use_polling++; | |
1061 | mutex_spin_exit(&sc->sc_intr_lock); | 1062 | mutex_spin_exit(&sc->sc_intr_lock); | |
1062 | 1063 | |||
1063 | ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK; | 1064 | ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK; | |
1064 | if (sc->sc_control == 0) { | 1065 | if (sc->sc_control == 0) { | |
1065 | /* | 1066 | /* | |
1066 | * Preserve register values, in case that BIOS | 1067 | * Preserve register values, in case that BIOS | |
1067 | * does not recover them. | 1068 | * does not recover them. | |
1068 | */ | 1069 | */ | |
1069 | sc->sc_control = ctl; | 1070 | sc->sc_control = ctl; | |
1070 | sc->sc_intre = OREAD4(sc, | 1071 | sc->sc_intre = OREAD4(sc, | |
1071 | OHCI_INTERRUPT_ENABLE); | 1072 | OHCI_INTERRUPT_ENABLE); | |
1072 | } | 1073 | } | |
1073 | ctl |= OHCI_HCFS_SUSPEND; | 1074 | ctl |= OHCI_HCFS_SUSPEND; | |
1074 | OWRITE4(sc, OHCI_CONTROL, ctl); | 1075 | OWRITE4(sc, OHCI_CONTROL, ctl); | |
1075 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); | 1076 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); | |
1076 | 1077 | |||
1077 | mutex_spin_enter(&sc->sc_intr_lock); | 1078 | mutex_spin_enter(&sc->sc_intr_lock); | |
1078 | sc->sc_bus.use_polling--; | 1079 | sc->sc_bus.use_polling--; | |
1079 | mutex_spin_exit(&sc->sc_intr_lock); | 1080 | mutex_spin_exit(&sc->sc_intr_lock); | |
1080 | 1081 | |||
1081 | return true; | 1082 | return true; | |
1082 | } | 1083 | } | |
1083 | 1084 | |||
1084 | #ifdef OHCI_DEBUG | 1085 | #ifdef OHCI_DEBUG | |
1085 | void | 1086 | void | |
1086 | ohci_dumpregs(ohci_softc_t *sc) | 1087 | ohci_dumpregs(ohci_softc_t *sc) | |
1087 | { | 1088 | { | |
1088 | DPRINTF(("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n", | 1089 | DPRINTF(("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n", | |
1089 | OREAD4(sc, OHCI_REVISION), | 1090 | OREAD4(sc, OHCI_REVISION), | |
1090 | OREAD4(sc, OHCI_CONTROL), | 1091 | OREAD4(sc, OHCI_CONTROL), | |
1091 | OREAD4(sc, OHCI_COMMAND_STATUS))); | 1092 | OREAD4(sc, OHCI_COMMAND_STATUS))); | |
1092 | DPRINTF((" intrstat=0x%08x intre=0x%08x intrd=0x%08x\n", | 1093 | DPRINTF((" intrstat=0x%08x intre=0x%08x intrd=0x%08x\n", | |
1093 | OREAD4(sc, OHCI_INTERRUPT_STATUS), | 1094 | OREAD4(sc, OHCI_INTERRUPT_STATUS), | |
1094 | OREAD4(sc, OHCI_INTERRUPT_ENABLE), | 1095 | OREAD4(sc, OHCI_INTERRUPT_ENABLE), | |
1095 | OREAD4(sc, OHCI_INTERRUPT_DISABLE))); | 1096 | OREAD4(sc, OHCI_INTERRUPT_DISABLE))); | |
1096 | DPRINTF((" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n", | 1097 | DPRINTF((" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n", | |
1097 | OREAD4(sc, OHCI_HCCA), | 1098 | OREAD4(sc, OHCI_HCCA), | |
1098 | OREAD4(sc, OHCI_PERIOD_CURRENT_ED), | 1099 | OREAD4(sc, OHCI_PERIOD_CURRENT_ED), | |
1099 | OREAD4(sc, OHCI_CONTROL_HEAD_ED))); | 1100 | OREAD4(sc, OHCI_CONTROL_HEAD_ED))); | |
1100 | DPRINTF((" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n", | 1101 | DPRINTF((" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n", | |
1101 | OREAD4(sc, OHCI_CONTROL_CURRENT_ED), | 1102 | OREAD4(sc, OHCI_CONTROL_CURRENT_ED), | |
1102 | OREAD4(sc, OHCI_BULK_HEAD_ED), | 1103 | OREAD4(sc, OHCI_BULK_HEAD_ED), | |
1103 | OREAD4(sc, OHCI_BULK_CURRENT_ED))); | 1104 | OREAD4(sc, OHCI_BULK_CURRENT_ED))); | |
1104 | DPRINTF((" done=0x%08x fmival=0x%08x fmrem=0x%08x\n", | 1105 | DPRINTF((" done=0x%08x fmival=0x%08x fmrem=0x%08x\n", | |
1105 | OREAD4(sc, OHCI_DONE_HEAD), | 1106 | OREAD4(sc, OHCI_DONE_HEAD), | |
1106 | OREAD4(sc, OHCI_FM_INTERVAL), | 1107 | OREAD4(sc, OHCI_FM_INTERVAL), | |
1107 | OREAD4(sc, OHCI_FM_REMAINING))); | 1108 | OREAD4(sc, OHCI_FM_REMAINING))); | |
1108 | DPRINTF((" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n", | 1109 | DPRINTF((" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n", | |
1109 | OREAD4(sc, OHCI_FM_NUMBER), | 1110 | OREAD4(sc, OHCI_FM_NUMBER), | |
1110 | OREAD4(sc, OHCI_PERIODIC_START), | 1111 | OREAD4(sc, OHCI_PERIODIC_START), | |
1111 | OREAD4(sc, OHCI_LS_THRESHOLD))); | 1112 | OREAD4(sc, OHCI_LS_THRESHOLD))); | |
1112 | DPRINTF((" desca=0x%08x descb=0x%08x stat=0x%08x\n", | 1113 | DPRINTF((" desca=0x%08x descb=0x%08x stat=0x%08x\n", | |
1113 | OREAD4(sc, OHCI_RH_DESCRIPTOR_A), | 1114 | OREAD4(sc, OHCI_RH_DESCRIPTOR_A), | |
1114 | OREAD4(sc, OHCI_RH_DESCRIPTOR_B), | 1115 | OREAD4(sc, OHCI_RH_DESCRIPTOR_B), | |
1115 | OREAD4(sc, OHCI_RH_STATUS))); | 1116 | OREAD4(sc, OHCI_RH_STATUS))); | |
1116 | DPRINTF((" port1=0x%08x port2=0x%08x\n", | 1117 | DPRINTF((" port1=0x%08x port2=0x%08x\n", | |
1117 | OREAD4(sc, OHCI_RH_PORT_STATUS(1)), | 1118 | OREAD4(sc, OHCI_RH_PORT_STATUS(1)), | |
1118 | OREAD4(sc, OHCI_RH_PORT_STATUS(2)))); | 1119 | OREAD4(sc, OHCI_RH_PORT_STATUS(2)))); | |
1119 | DPRINTF((" HCCA: frame_number=0x%04x done_head=0x%08x\n", | 1120 | DPRINTF((" HCCA: frame_number=0x%04x done_head=0x%08x\n", | |
1120 | O32TOH(sc->sc_hcca->hcca_frame_number), | 1121 | O32TOH(sc->sc_hcca->hcca_frame_number), | |
1121 | O32TOH(sc->sc_hcca->hcca_done_head))); | 1122 | O32TOH(sc->sc_hcca->hcca_done_head))); | |
1122 | } | 1123 | } | |
1123 | #endif | 1124 | #endif | |
1124 | 1125 | |||
1125 | Static int ohci_intr1(ohci_softc_t *); | 1126 | Static int ohci_intr1(ohci_softc_t *); | |
1126 | 1127 | |||
1127 | int | 1128 | int | |
1128 | ohci_intr(void *p) | 1129 | ohci_intr(void *p) | |
1129 | { | 1130 | { | |
1130 | ohci_softc_t *sc = p; | 1131 | ohci_softc_t *sc = p; | |
1131 | int ret = 0; | 1132 | int ret = 0; | |
1132 | 1133 | |||
1133 | if (sc == NULL) | 1134 | if (sc == NULL) | |
1134 | return (0); | 1135 | return (0); | |
1135 | 1136 | |||
1136 | mutex_spin_enter(&sc->sc_intr_lock); | 1137 | mutex_spin_enter(&sc->sc_intr_lock); | |
1137 | 1138 | |||
1138 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) | 1139 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) | |
1139 | goto done; | 1140 | goto done; | |
1140 | 1141 | |||
1141 | /* If we get an interrupt while polling, then just ignore it. */ | 1142 | /* If we get an interrupt while polling, then just ignore it. */ | |
1142 | if (sc->sc_bus.use_polling) { | 1143 | if (sc->sc_bus.use_polling) { | |
1143 | #ifdef DIAGNOSTIC | 1144 | #ifdef DIAGNOSTIC | |
1144 | DPRINTFN(16, ("ohci_intr: ignored interrupt while polling\n")); | 1145 | DPRINTFN(16, ("ohci_intr: ignored interrupt while polling\n")); | |
1145 | #endif | 1146 | #endif | |
1146 | /* for level triggered intrs, should do something to ack */ | 1147 | /* for level triggered intrs, should do something to ack */ | |
1147 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, | 1148 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, | |
1148 | OREAD4(sc, OHCI_INTERRUPT_STATUS)); | 1149 | OREAD4(sc, OHCI_INTERRUPT_STATUS)); | |
1149 | 1150 | |||
1150 | goto done; | 1151 | goto done; | |
1151 | } | 1152 | } | |
1152 | 1153 | |||
1153 | ret = ohci_intr1(sc); | 1154 | ret = ohci_intr1(sc); | |
1154 | 1155 | |||
1155 | done: | 1156 | done: | |
1156 | mutex_spin_exit(&sc->sc_intr_lock); | 1157 | mutex_spin_exit(&sc->sc_intr_lock); | |
1157 | return ret; | 1158 | return ret; | |
1158 | } | 1159 | } | |
1159 | 1160 | |||
1160 | Static int | 1161 | Static int | |
1161 | ohci_intr1(ohci_softc_t *sc) | 1162 | ohci_intr1(ohci_softc_t *sc) | |
1162 | { | 1163 | { | |
1163 | u_int32_t intrs, eintrs; | 1164 | u_int32_t intrs, eintrs; | |
1164 | 1165 | |||
1165 | DPRINTFN(14,("ohci_intr1: enter\n")); | 1166 | DPRINTFN(14,("ohci_intr1: enter\n")); | |
1166 | 1167 | |||
1167 | /* In case the interrupt occurs before initialization has completed. */ | 1168 | /* In case the interrupt occurs before initialization has completed. */ | |
1168 | if (sc == NULL || sc->sc_hcca == NULL) { | 1169 | if (sc == NULL || sc->sc_hcca == NULL) { | |
1169 | #ifdef DIAGNOSTIC | 1170 | #ifdef DIAGNOSTIC | |
1170 | printf("ohci_intr: sc->sc_hcca == NULL\n"); | 1171 | printf("ohci_intr: sc->sc_hcca == NULL\n"); | |
1171 | #endif | 1172 | #endif | |
1172 | return (0); | 1173 | return (0); | |
1173 | } | 1174 | } | |
1174 | 1175 | |||
1175 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | 1176 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | |
1176 | 1177 | |||
1177 | intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS); | 1178 | intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS); | |
1178 | if (!intrs) | 1179 | if (!intrs) | |
1179 | return (0); | 1180 | return (0); | |
1180 | 1181 | |||
1181 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs & ~(OHCI_MIE|OHCI_WDH)); /* Acknowledge */ | 1182 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs & ~(OHCI_MIE|OHCI_WDH)); /* Acknowledge */ | |
1182 | eintrs = intrs & sc->sc_eintrs; | 1183 | eintrs = intrs & sc->sc_eintrs; | |
1183 | DPRINTFN(7, ("ohci_intr: sc=%p intrs=%#x(%#x) eintrs=%#x(%#x)\n", | 1184 | DPRINTFN(7, ("ohci_intr: sc=%p intrs=%#x(%#x) eintrs=%#x(%#x)\n", | |
1184 | sc, (u_int)intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS), | 1185 | sc, (u_int)intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS), | |
1185 | (u_int)eintrs, sc->sc_eintrs)); | 1186 | (u_int)eintrs, sc->sc_eintrs)); | |
1186 | 1187 | |||
1187 | if (!eintrs) { | 1188 | if (!eintrs) { | |
1188 | return (0); | 1189 | return (0); | |
1189 | } | 1190 | } | |
1190 | 1191 | |||
1191 | sc->sc_bus.intr_context++; | 1192 | sc->sc_bus.intr_context++; | |
1192 | sc->sc_bus.no_intrs++; | 1193 | sc->sc_bus.no_intrs++; | |
1193 | if (eintrs & OHCI_SO) { | 1194 | if (eintrs & OHCI_SO) { | |
1194 | sc->sc_overrun_cnt++; | 1195 | sc->sc_overrun_cnt++; | |
1195 | if (usbd_ratecheck(&sc->sc_overrun_ntc)) { | 1196 | if (usbd_ratecheck(&sc->sc_overrun_ntc)) { | |
1196 | printf("%s: %u scheduling overruns\n", | 1197 | printf("%s: %u scheduling overruns\n", | |
1197 | device_xname(sc->sc_dev), sc->sc_overrun_cnt); | 1198 | device_xname(sc->sc_dev), sc->sc_overrun_cnt); | |
1198 | sc->sc_overrun_cnt = 0; | 1199 | sc->sc_overrun_cnt = 0; | |
1199 | } | 1200 | } | |
1200 | /* XXX do what */ | 1201 | /* XXX do what */ | |
1201 | eintrs &= ~OHCI_SO; | 1202 | eintrs &= ~OHCI_SO; | |
1202 | } | 1203 | } | |
1203 | if (eintrs & OHCI_WDH) { | 1204 | if (eintrs & OHCI_WDH) { | |
1204 | /* | 1205 | /* | |
1205 | * We block the interrupt below, and reenable it later from | 1206 | * We block the interrupt below, and reenable it later from | |
1206 | * ohci_softintr(). | 1207 | * ohci_softintr(). | |
1207 | */ | 1208 | */ | |
1208 | usb_schedsoftintr(&sc->sc_bus); | 1209 | usb_schedsoftintr(&sc->sc_bus); | |
1209 | } | 1210 | } | |
1210 | if (eintrs & OHCI_RD) { | 1211 | if (eintrs & OHCI_RD) { | |
1211 | printf("%s: resume detect\n", device_xname(sc->sc_dev)); | 1212 | printf("%s: resume detect\n", device_xname(sc->sc_dev)); | |
1212 | /* XXX process resume detect */ | 1213 | /* XXX process resume detect */ | |
1213 | } | 1214 | } | |
1214 | if (eintrs & OHCI_UE) { | 1215 | if (eintrs & OHCI_UE) { | |
1215 | printf("%s: unrecoverable error, controller halted\n", | 1216 | printf("%s: unrecoverable error, controller halted\n", | |
1216 | device_xname(sc->sc_dev)); | 1217 | device_xname(sc->sc_dev)); | |
1217 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); | 1218 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); | |
1218 | /* XXX what else */ | 1219 | /* XXX what else */ | |
1219 | } | 1220 | } | |
1220 | if (eintrs & OHCI_RHSC) { | 1221 | if (eintrs & OHCI_RHSC) { | |
1221 | /* | 1222 | /* | |
1222 | * We block the interrupt below, and reenable it later from | 1223 | * We block the interrupt below, and reenable it later from | |
1223 | * a timeout. | 1224 | * a timeout. | |
1224 | */ | 1225 | */ | |
1225 | softint_schedule(sc->sc_rhsc_si); | 1226 | softint_schedule(sc->sc_rhsc_si); | |
1226 | } | 1227 | } | |
1227 | 1228 | |||
1228 | sc->sc_bus.intr_context--; | 1229 | sc->sc_bus.intr_context--; | |
1229 | 1230 | |||
1230 | if (eintrs != 0) { | 1231 | if (eintrs != 0) { | |
1231 | /* Block unprocessed interrupts. */ | 1232 | /* Block unprocessed interrupts. */ | |
1232 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs); | 1233 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs); | |
1233 | sc->sc_eintrs &= ~eintrs; | 1234 | sc->sc_eintrs &= ~eintrs; | |
1234 | DPRINTFN(1, ("%s: blocking intrs 0x%x\n", | 1235 | DPRINTFN(1, ("%s: blocking intrs 0x%x\n", | |
1235 | device_xname(sc->sc_dev), eintrs)); | 1236 | device_xname(sc->sc_dev), eintrs)); | |
1236 | } | 1237 | } | |
1237 | 1238 | |||
1238 | return (1); | 1239 | return (1); | |
1239 | } | 1240 | } | |
1240 | 1241 | |||
1241 | void | 1242 | void | |
1242 | ohci_rhsc_enable(void *v_sc) | 1243 | ohci_rhsc_enable(void *v_sc) | |
1243 | { | 1244 | { | |
1244 | ohci_softc_t *sc = v_sc; | 1245 | ohci_softc_t *sc = v_sc; | |
1245 | 1246 | |||
1246 | DPRINTFN(1, ("%s: %s\n", __func__, device_xname(sc->sc_dev))); | 1247 | DPRINTFN(1, ("%s: %s\n", __func__, device_xname(sc->sc_dev))); | |
1247 | mutex_spin_enter(&sc->sc_intr_lock); | 1248 | mutex_spin_enter(&sc->sc_intr_lock); | |
1248 | sc->sc_eintrs |= OHCI_RHSC; | 1249 | sc->sc_eintrs |= OHCI_RHSC; | |
1249 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); | 1250 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); | |
1250 | mutex_spin_exit(&sc->sc_intr_lock); | 1251 | mutex_spin_exit(&sc->sc_intr_lock); | |
1251 | } | 1252 | } | |
1252 | 1253 | |||
1253 | #ifdef OHCI_DEBUG | 1254 | #ifdef OHCI_DEBUG | |
1254 | const char *ohci_cc_strs[] = { | 1255 | const char *ohci_cc_strs[] = { | |
1255 | "NO_ERROR", | 1256 | "NO_ERROR", | |
1256 | "CRC", | 1257 | "CRC", | |
1257 | "BIT_STUFFING", | 1258 | "BIT_STUFFING", | |
1258 | "DATA_TOGGLE_MISMATCH", | 1259 | "DATA_TOGGLE_MISMATCH", | |
1259 | "STALL", | 1260 | "STALL", | |
1260 | "DEVICE_NOT_RESPONDING", | 1261 | "DEVICE_NOT_RESPONDING", | |
1261 | "PID_CHECK_FAILURE", | 1262 | "PID_CHECK_FAILURE", | |
1262 | "UNEXPECTED_PID", | 1263 | "UNEXPECTED_PID", | |
1263 | "DATA_OVERRUN", | 1264 | "DATA_OVERRUN", | |
1264 | "DATA_UNDERRUN", | 1265 | "DATA_UNDERRUN", | |
1265 | "BUFFER_OVERRUN", | 1266 | "BUFFER_OVERRUN", | |
1266 | "BUFFER_UNDERRUN", | 1267 | "BUFFER_UNDERRUN", | |
1267 | "reserved", | 1268 | "reserved", | |
1268 | "reserved", | 1269 | "reserved", | |
1269 | "NOT_ACCESSED", | 1270 | "NOT_ACCESSED", | |
1270 | "NOT_ACCESSED", | 1271 | "NOT_ACCESSED", | |
1271 | }; | 1272 | }; | |
1272 | #endif | 1273 | #endif | |
1273 | 1274 | |||
1274 | void | 1275 | void | |
1275 | ohci_softintr(void *v) | 1276 | ohci_softintr(void *v) | |
1276 | { | 1277 | { | |
1277 | struct usbd_bus *bus = v; | 1278 | struct usbd_bus *bus = v; | |
1278 | ohci_softc_t *sc = bus->hci_private; | 1279 | ohci_softc_t *sc = bus->hci_private; | |
1279 | ohci_soft_itd_t *sitd, *sidone, *sitdnext; | 1280 | ohci_soft_itd_t *sitd, *sidone, *sitdnext; | |
1280 | ohci_soft_td_t *std, *sdone, *stdnext; | 1281 | ohci_soft_td_t *std, *sdone, *stdnext; | |
1281 | usbd_xfer_handle xfer; | 1282 | usbd_xfer_handle xfer; | |
1282 | struct ohci_pipe *opipe; | 1283 | struct ohci_pipe *opipe; | |
1283 | int len, cc; | 1284 | int len, cc; | |
1284 | int i, j, actlen, iframes, uedir; | 1285 | int i, j, actlen, iframes, uedir; | |
1285 | ohci_physaddr_t done; | 1286 | ohci_physaddr_t done; | |
1286 | 1287 | |||
1287 | DPRINTFN(10,("ohci_softintr: enter\n")); | 1288 | DPRINTFN(10,("ohci_softintr: enter\n")); | |
1288 | 1289 | |||
1289 | mutex_enter(&sc->sc_lock); | 1290 | mutex_enter(&sc->sc_lock); | |
1290 | 1291 | |||
1291 | sc->sc_bus.intr_context++; | 1292 | sc->sc_bus.intr_context++; | |
1292 | 1293 | |||
1293 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), | 1294 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), | |
1294 | sizeof(sc->sc_hcca->hcca_done_head), | 1295 | sizeof(sc->sc_hcca->hcca_done_head), | |
1295 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1296 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1296 | done = O32TOH(sc->sc_hcca->hcca_done_head) & ~OHCI_DONE_INTRS; | 1297 | done = O32TOH(sc->sc_hcca->hcca_done_head) & ~OHCI_DONE_INTRS; | |
1297 | sc->sc_hcca->hcca_done_head = 0; | 1298 | sc->sc_hcca->hcca_done_head = 0; | |
1298 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), | 1299 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), | |
1299 | sizeof(sc->sc_hcca->hcca_done_head), | 1300 | sizeof(sc->sc_hcca->hcca_done_head), | |
1300 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1301 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1301 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_WDH); | 1302 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_WDH); | |
1302 | sc->sc_eintrs |= OHCI_WDH; | 1303 | sc->sc_eintrs |= OHCI_WDH; | |
1303 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_WDH); | 1304 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_WDH); | |
1304 | 1305 | |||
1305 | /* Reverse the done list. */ | 1306 | /* Reverse the done list. */ | |
1306 | for (sdone = NULL, sidone = NULL; done != 0; ) { | 1307 | for (sdone = NULL, sidone = NULL; done != 0; ) { | |
1307 | std = ohci_hash_find_td(sc, done); | 1308 | std = ohci_hash_find_td(sc, done); | |
1308 | if (std != NULL) { | 1309 | if (std != NULL) { | |
1309 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | 1310 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | |
1310 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1311 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1311 | std->dnext = sdone; | 1312 | std->dnext = sdone; | |
1312 | done = O32TOH(std->td.td_nexttd); | 1313 | done = O32TOH(std->td.td_nexttd); | |
1313 | sdone = std; | 1314 | sdone = std; | |
1314 | DPRINTFN(10,("add TD %p\n", std)); | 1315 | DPRINTFN(10,("add TD %p\n", std)); | |
1315 | continue; | 1316 | continue; | |
1316 | } | 1317 | } | |
1317 | sitd = ohci_hash_find_itd(sc, done); | 1318 | sitd = ohci_hash_find_itd(sc, done); | |
1318 | if (sitd != NULL) { | 1319 | if (sitd != NULL) { | |
1319 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), | 1320 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), | |
1320 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1321 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1321 | sitd->dnext = sidone; | 1322 | sitd->dnext = sidone; | |
1322 | done = O32TOH(sitd->itd.itd_nextitd); | 1323 | done = O32TOH(sitd->itd.itd_nextitd); | |
1323 | sidone = sitd; | 1324 | sidone = sitd; | |
1324 | DPRINTFN(5,("add ITD %p\n", sitd)); | 1325 | DPRINTFN(5,("add ITD %p\n", sitd)); | |
1325 | continue; | 1326 | continue; | |
1326 | } | 1327 | } | |
1327 | device_printf(sc->sc_dev, "WARNING: addr 0x%08lx not found\n", | 1328 | device_printf(sc->sc_dev, "WARNING: addr 0x%08lx not found\n", | |
1328 | (u_long)done); | 1329 | (u_long)done); | |
1329 | break; | 1330 | break; | |
1330 | } | 1331 | } | |
1331 | 1332 | |||
1332 | DPRINTFN(10,("ohci_softintr: sdone=%p sidone=%p\n", sdone, sidone)); | 1333 | DPRINTFN(10,("ohci_softintr: sdone=%p sidone=%p\n", sdone, sidone)); | |
1333 | 1334 | |||
1334 | #ifdef OHCI_DEBUG | 1335 | #ifdef OHCI_DEBUG | |
1335 | if (ohcidebug > 10) { | 1336 | if (ohcidebug > 10) { | |
1336 | DPRINTF(("ohci_process_done: TD done:\n")); | 1337 | DPRINTF(("ohci_process_done: TD done:\n")); | |
1337 | ohci_dump_tds(sc, sdone); | 1338 | ohci_dump_tds(sc, sdone); | |
1338 | } | 1339 | } | |
1339 | #endif | 1340 | #endif | |
1340 | 1341 | |||
1341 | for (std = sdone; std; std = stdnext) { | 1342 | for (std = sdone; std; std = stdnext) { | |
1342 | xfer = std->xfer; | 1343 | xfer = std->xfer; | |
1343 | stdnext = std->dnext; | 1344 | stdnext = std->dnext; | |
1344 | DPRINTFN(10, ("ohci_process_done: std=%p xfer=%p hcpriv=%p\n", | 1345 | DPRINTFN(10, ("ohci_process_done: std=%p xfer=%p hcpriv=%p\n", | |
1345 | std, xfer, xfer ? xfer->hcpriv : 0)); | 1346 | std, xfer, xfer ? xfer->hcpriv : 0)); | |
1346 | if (xfer == NULL) { | 1347 | if (xfer == NULL) { | |
1347 | /* | 1348 | /* | |
1348 | * xfer == NULL: There seems to be no xfer associated | 1349 | * xfer == NULL: There seems to be no xfer associated | |
1349 | * with this TD. It is tailp that happened to end up on | 1350 | * with this TD. It is tailp that happened to end up on | |
1350 | * the done queue. | 1351 | * the done queue. | |
1351 | * Shouldn't happen, but some chips are broken(?). | 1352 | * Shouldn't happen, but some chips are broken(?). | |
1352 | */ | 1353 | */ | |
1353 | continue; | 1354 | continue; | |
1354 | } | 1355 | } | |
1355 | if (xfer->status == USBD_CANCELLED || | 1356 | if (xfer->status == USBD_CANCELLED || | |
1356 | xfer->status == USBD_TIMEOUT) { | 1357 | xfer->status == USBD_TIMEOUT) { | |
1357 | DPRINTF(("ohci_process_done: cancel/timeout %p\n", | 1358 | DPRINTF(("ohci_process_done: cancel/timeout %p\n", | |
1358 | xfer)); | 1359 | xfer)); | |
1359 | /* Handled by abort routine. */ | 1360 | /* Handled by abort routine. */ | |
1360 | continue; | 1361 | continue; | |
1361 | } | 1362 | } | |
1362 | callout_stop(&xfer->timeout_handle); | 1363 | callout_stop(&xfer->timeout_handle); | |
1363 | 1364 | |||
1364 | len = std->len; | 1365 | len = std->len; | |
1365 | if (std->td.td_cbp != 0) | 1366 | if (std->td.td_cbp != 0) | |
1366 | len -= O32TOH(std->td.td_be) - | 1367 | len -= O32TOH(std->td.td_be) - | |
1367 | O32TOH(std->td.td_cbp) + 1; | 1368 | O32TOH(std->td.td_cbp) + 1; | |
1368 | DPRINTFN(10, ("ohci_process_done: len=%d, flags=0x%x\n", len, | 1369 | DPRINTFN(10, ("ohci_process_done: len=%d, flags=0x%x\n", len, | |
1369 | std->flags)); | 1370 | std->flags)); | |
1370 | if (std->flags & OHCI_ADD_LEN) | 1371 | if (std->flags & OHCI_ADD_LEN) | |
1371 | xfer->actlen += len; | 1372 | xfer->actlen += len; | |
1372 | 1373 | |||
1373 | cc = OHCI_TD_GET_CC(O32TOH(std->td.td_flags)); | 1374 | cc = OHCI_TD_GET_CC(O32TOH(std->td.td_flags)); | |
1374 | if (cc == OHCI_CC_NO_ERROR) { | 1375 | if (cc == OHCI_CC_NO_ERROR) { | |
1375 | if (std->flags & OHCI_CALL_DONE) { | 1376 | if (std->flags & OHCI_CALL_DONE) { | |
1376 | xfer->status = USBD_NORMAL_COMPLETION; | 1377 | xfer->status = USBD_NORMAL_COMPLETION; | |
1377 | usb_transfer_complete(xfer); | 1378 | usb_transfer_complete(xfer); | |
1378 | } | 1379 | } | |
1379 | ohci_free_std(sc, std); | 1380 | ohci_free_std(sc, std); | |
1380 | } else { | 1381 | } else { | |
1381 | /* | 1382 | /* | |
1382 | * Endpoint is halted. First unlink all the TDs | 1383 | * Endpoint is halted. First unlink all the TDs | |
1383 | * belonging to the failed transfer, and then restart | 1384 | * belonging to the failed transfer, and then restart | |
1384 | * the endpoint. | 1385 | * the endpoint. | |
1385 | */ | 1386 | */ | |
1386 | ohci_soft_td_t *p, *n; | 1387 | ohci_soft_td_t *p, *n; | |
1387 | opipe = (struct ohci_pipe *)xfer->pipe; | 1388 | opipe = (struct ohci_pipe *)xfer->pipe; | |
1388 | 1389 | |||
1389 | DPRINTFN(15,("ohci_process_done: error cc=%d (%s)\n", | 1390 | DPRINTFN(15,("ohci_process_done: error cc=%d (%s)\n", | |
1390 | OHCI_TD_GET_CC(O32TOH(std->td.td_flags)), | 1391 | OHCI_TD_GET_CC(O32TOH(std->td.td_flags)), | |
1391 | ohci_cc_strs[OHCI_TD_GET_CC(O32TOH(std->td.td_flags))])); | 1392 | ohci_cc_strs[OHCI_TD_GET_CC(O32TOH(std->td.td_flags))])); | |
1392 | 1393 | |||
1393 | /* remove TDs */ | 1394 | /* remove TDs */ | |
1394 | for (p = std; p->xfer == xfer; p = n) { | 1395 | for (p = std; p->xfer == xfer; p = n) { | |
1395 | n = p->nexttd; | 1396 | n = p->nexttd; | |
1396 | ohci_free_std(sc, p); | 1397 | ohci_free_std(sc, p); | |
1397 | } | 1398 | } | |
1398 | 1399 | |||
1399 | /* clear halt */ | 1400 | /* clear halt */ | |
1400 | opipe->sed->ed.ed_headp = HTOO32(p->physaddr); | 1401 | opipe->sed->ed.ed_headp = HTOO32(p->physaddr); | |
1401 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); | 1402 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); | |
1402 | 1403 | |||
1403 | if (cc == OHCI_CC_STALL) | 1404 | if (cc == OHCI_CC_STALL) | |
1404 | xfer->status = USBD_STALLED; | 1405 | xfer->status = USBD_STALLED; | |
1405 | else | 1406 | else | |
1406 | xfer->status = USBD_IOERROR; | 1407 | xfer->status = USBD_IOERROR; | |
1407 | usb_transfer_complete(xfer); | 1408 | usb_transfer_complete(xfer); | |
1408 | } | 1409 | } | |
1409 | } | 1410 | } | |
1410 | 1411 | |||
1411 | #ifdef OHCI_DEBUG | 1412 | #ifdef OHCI_DEBUG | |
1412 | if (ohcidebug > 10) { | 1413 | if (ohcidebug > 10) { | |
1413 | DPRINTF(("ohci_softintr: ITD done:\n")); | 1414 | DPRINTF(("ohci_softintr: ITD done:\n")); | |
1414 | ohci_dump_itds(sc, sidone); | 1415 | ohci_dump_itds(sc, sidone); | |
1415 | } | 1416 | } | |
1416 | #endif | 1417 | #endif | |
1417 | 1418 | |||
1418 | for (sitd = sidone; sitd != NULL; sitd = sitdnext) { | 1419 | for (sitd = sidone; sitd != NULL; sitd = sitdnext) { | |
1419 | xfer = sitd->xfer; | 1420 | xfer = sitd->xfer; | |
1420 | sitdnext = sitd->dnext; | 1421 | sitdnext = sitd->dnext; | |
1421 | DPRINTFN(1, ("ohci_process_done: sitd=%p xfer=%p hcpriv=%p\n", | 1422 | DPRINTFN(1, ("ohci_process_done: sitd=%p xfer=%p hcpriv=%p\n", | |
1422 | sitd, xfer, xfer ? xfer->hcpriv : 0)); | 1423 | sitd, xfer, xfer ? xfer->hcpriv : 0)); | |
1423 | if (xfer == NULL) | 1424 | if (xfer == NULL) | |
1424 | continue; | 1425 | continue; | |
1425 | if (xfer->status == USBD_CANCELLED || | 1426 | if (xfer->status == USBD_CANCELLED || | |
1426 | xfer->status == USBD_TIMEOUT) { | 1427 | xfer->status == USBD_TIMEOUT) { | |
1427 | DPRINTF(("ohci_process_done: cancel/timeout %p\n", | 1428 | DPRINTF(("ohci_process_done: cancel/timeout %p\n", | |
1428 | xfer)); | 1429 | xfer)); | |
1429 | /* Handled by abort routine. */ | 1430 | /* Handled by abort routine. */ | |
1430 | continue; | 1431 | continue; | |
1431 | } | 1432 | } | |
1432 | #ifdef DIAGNOSTIC | 1433 | #ifdef DIAGNOSTIC | |
1433 | if (sitd->isdone) | 1434 | if (sitd->isdone) | |
1434 | printf("ohci_softintr: sitd=%p is done\n", sitd); | 1435 | printf("ohci_softintr: sitd=%p is done\n", sitd); | |
1435 | sitd->isdone = 1; | 1436 | sitd->isdone = 1; | |
1436 | #endif | 1437 | #endif | |
1437 | if (sitd->flags & OHCI_CALL_DONE) { | 1438 | if (sitd->flags & OHCI_CALL_DONE) { | |
1438 | ohci_soft_itd_t *next; | 1439 | ohci_soft_itd_t *next; | |
1439 | 1440 | |||
1440 | opipe = (struct ohci_pipe *)xfer->pipe; | 1441 | opipe = (struct ohci_pipe *)xfer->pipe; | |
1441 | opipe->u.iso.inuse -= xfer->nframes; | 1442 | opipe->u.iso.inuse -= xfer->nframes; | |
1442 | uedir = UE_GET_DIR(xfer->pipe->endpoint->edesc-> | 1443 | uedir = UE_GET_DIR(xfer->pipe->endpoint->edesc-> | |
1443 | bEndpointAddress); | 1444 | bEndpointAddress); | |
1444 | xfer->status = USBD_NORMAL_COMPLETION; | 1445 | xfer->status = USBD_NORMAL_COMPLETION; | |
1445 | actlen = 0; | 1446 | actlen = 0; | |
1446 | for (i = 0, sitd = xfer->hcpriv;; | 1447 | for (i = 0, sitd = xfer->hcpriv;; | |
1447 | sitd = next) { | 1448 | sitd = next) { | |
1448 | next = sitd->nextitd; | 1449 | next = sitd->nextitd; | |
1449 | if (OHCI_ITD_GET_CC(O32TOH(sitd-> | 1450 | if (OHCI_ITD_GET_CC(O32TOH(sitd-> | |
1450 | itd.itd_flags)) != OHCI_CC_NO_ERROR) | 1451 | itd.itd_flags)) != OHCI_CC_NO_ERROR) | |
1451 | xfer->status = USBD_IOERROR; | 1452 | xfer->status = USBD_IOERROR; | |
1452 | /* For input, update frlengths with actual */ | 1453 | /* For input, update frlengths with actual */ | |
1453 | /* XXX anything necessary for output? */ | 1454 | /* XXX anything necessary for output? */ | |
1454 | if (uedir == UE_DIR_IN && | 1455 | if (uedir == UE_DIR_IN && | |
1455 | xfer->status == USBD_NORMAL_COMPLETION) { | 1456 | xfer->status == USBD_NORMAL_COMPLETION) { | |
1456 | iframes = OHCI_ITD_GET_FC(O32TOH( | 1457 | iframes = OHCI_ITD_GET_FC(O32TOH( | |
1457 | sitd->itd.itd_flags)); | 1458 | sitd->itd.itd_flags)); | |
1458 | for (j = 0; j < iframes; i++, j++) { | 1459 | for (j = 0; j < iframes; i++, j++) { | |
1459 | len = O16TOH(sitd-> | 1460 | len = O16TOH(sitd-> | |
1460 | itd.itd_offset[j]); | 1461 | itd.itd_offset[j]); | |
1461 | if ((OHCI_ITD_PSW_GET_CC(len) & | 1462 | if ((OHCI_ITD_PSW_GET_CC(len) & | |
1462 | OHCI_CC_NOT_ACCESSED_MASK) | 1463 | OHCI_CC_NOT_ACCESSED_MASK) | |
1463 | == OHCI_CC_NOT_ACCESSED) | 1464 | == OHCI_CC_NOT_ACCESSED) | |
1464 | len = 0; | 1465 | len = 0; | |
1465 | else | 1466 | else | |
1466 | len = OHCI_ITD_PSW_LENGTH(len); | 1467 | len = OHCI_ITD_PSW_LENGTH(len); | |
1467 | xfer->frlengths[i] = len; | 1468 | xfer->frlengths[i] = len; | |
1468 | actlen += len; | 1469 | actlen += len; | |
1469 | } | 1470 | } | |
1470 | } | 1471 | } | |
1471 | if (sitd->flags & OHCI_CALL_DONE) | 1472 | if (sitd->flags & OHCI_CALL_DONE) | |
1472 | break; | 1473 | break; | |
1473 | ohci_free_sitd(sc, sitd); | 1474 | ohci_free_sitd(sc, sitd); | |
1474 | } | 1475 | } | |
1475 | ohci_free_sitd(sc, sitd); | 1476 | ohci_free_sitd(sc, sitd); | |
1476 | if (uedir == UE_DIR_IN && | 1477 | if (uedir == UE_DIR_IN && | |
1477 | xfer->status == USBD_NORMAL_COMPLETION) | 1478 | xfer->status == USBD_NORMAL_COMPLETION) | |
1478 | xfer->actlen = actlen; | 1479 | xfer->actlen = actlen; | |
1479 | xfer->hcpriv = NULL; | 1480 | xfer->hcpriv = NULL; | |
1480 | 1481 | |||
1481 | usb_transfer_complete(xfer); | 1482 | usb_transfer_complete(xfer); | |
1482 | } | 1483 | } | |
1483 | } | 1484 | } | |
1484 | 1485 | |||
1485 | if (sc->sc_softwake) { | 1486 | if (sc->sc_softwake) { | |
1486 | sc->sc_softwake = 0; | 1487 | sc->sc_softwake = 0; | |
1487 | cv_broadcast(&sc->sc_softwake_cv); | 1488 | cv_broadcast(&sc->sc_softwake_cv); | |
1488 | } | 1489 | } | |
1489 | 1490 | |||
1490 | sc->sc_bus.intr_context--; | 1491 | sc->sc_bus.intr_context--; | |
1491 | mutex_exit(&sc->sc_lock); | 1492 | mutex_exit(&sc->sc_lock); | |
1492 | 1493 | |||
1493 | DPRINTFN(10,("ohci_softintr: done:\n")); | 1494 | DPRINTFN(10,("ohci_softintr: done:\n")); | |
1494 | } | 1495 | } | |
1495 | 1496 | |||
1496 | void | 1497 | void | |
1497 | ohci_device_ctrl_done(usbd_xfer_handle xfer) | 1498 | ohci_device_ctrl_done(usbd_xfer_handle xfer) | |
1498 | { | 1499 | { | |
1499 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | 1500 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | |
1500 | #ifdef DIAGNOSTIC | 1501 | #ifdef DIAGNOSTIC | |
1501 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 1502 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
1502 | #endif | 1503 | #endif | |
1503 | int len = UGETW(xfer->request.wLength); | 1504 | int len = UGETW(xfer->request.wLength); | |
1504 | int isread = (xfer->request.bmRequestType & UT_READ); | 1505 | int isread = (xfer->request.bmRequestType & UT_READ); | |
1505 | 1506 | |||
1506 | DPRINTFN(10,("ohci_device_ctrl_done: xfer=%p\n", xfer)); | 1507 | DPRINTFN(10,("ohci_device_ctrl_done: xfer=%p\n", xfer)); | |
1507 | 1508 | |||
1508 | KASSERT(mutex_owned(&sc->sc_lock)); | 1509 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1509 | 1510 | |||
1510 | #ifdef DIAGNOSTIC | 1511 | #ifdef DIAGNOSTIC | |
1511 | if (!(xfer->rqflags & URQ_REQUEST)) { | 1512 | if (!(xfer->rqflags & URQ_REQUEST)) { | |
1512 | panic("ohci_device_ctrl_done: not a request"); | 1513 | panic("ohci_device_ctrl_done: not a request"); | |
1513 | } | 1514 | } | |
1514 | #endif | 1515 | #endif | |
1515 | if (len) | 1516 | if (len) | |
1516 | usb_syncmem(&xfer->dmabuf, 0, len, | 1517 | usb_syncmem(&xfer->dmabuf, 0, len, | |
1517 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | 1518 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | |
1518 | usb_syncmem(&opipe->u.ctl.reqdma, 0, | 1519 | usb_syncmem(&opipe->u.ctl.reqdma, 0, | |
1519 | sizeof(usb_device_request_t), BUS_DMASYNC_POSTWRITE); | 1520 | sizeof(usb_device_request_t), BUS_DMASYNC_POSTWRITE); | |
1520 | } | 1521 | } | |
1521 | 1522 | |||
1522 | void | 1523 | void | |
1523 | ohci_device_intr_done(usbd_xfer_handle xfer) | 1524 | ohci_device_intr_done(usbd_xfer_handle xfer) | |
1524 | { | 1525 | { | |
1525 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | 1526 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | |
1526 | ohci_softc_t *sc = opipe->pipe.device->bus->hci_private; | 1527 | ohci_softc_t *sc = opipe->pipe.device->bus->hci_private; | |
1527 | ohci_soft_ed_t *sed = opipe->sed; | 1528 | ohci_soft_ed_t *sed = opipe->sed; | |
1528 | ohci_soft_td_t *data, *tail; | 1529 | ohci_soft_td_t *data, *tail; | |
1529 | int isread = | 1530 | int isread = | |
1530 | (UE_GET_DIR(xfer->pipe->endpoint->edesc->bEndpointAddress) == UE_DIR_IN); | 1531 | (UE_GET_DIR(xfer->pipe->endpoint->edesc->bEndpointAddress) == UE_DIR_IN); | |
1531 | 1532 | |||
1532 | DPRINTFN(10,("ohci_device_intr_done: xfer=%p, actlen=%d\n", | 1533 | DPRINTFN(10,("ohci_device_intr_done: xfer=%p, actlen=%d\n", | |
1533 | xfer, xfer->actlen)); | 1534 | xfer, xfer->actlen)); | |
1534 | 1535 | |||
1535 | KASSERT(mutex_owned(&sc->sc_lock)); | 1536 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1536 | 1537 | |||
1537 | usb_syncmem(&xfer->dmabuf, 0, xfer->length, | 1538 | usb_syncmem(&xfer->dmabuf, 0, xfer->length, | |
1538 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | 1539 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | |
1539 | if (xfer->pipe->repeat) { | 1540 | if (xfer->pipe->repeat) { | |
1540 | data = opipe->tail.td; | 1541 | data = opipe->tail.td; | |
1541 | tail = ohci_alloc_std(sc); /* XXX should reuse TD */ | 1542 | tail = ohci_alloc_std(sc); /* XXX should reuse TD */ | |
1542 | if (tail == NULL) { | 1543 | if (tail == NULL) { | |
1543 | xfer->status = USBD_NOMEM; | 1544 | xfer->status = USBD_NOMEM; | |
1544 | return; | 1545 | return; | |
1545 | } | 1546 | } | |
1546 | tail->xfer = NULL; | 1547 | tail->xfer = NULL; | |
1547 | 1548 | |||
1548 | data->td.td_flags = HTOO32( | 1549 | data->td.td_flags = HTOO32( | |
1549 | OHCI_TD_IN | OHCI_TD_NOCC | | 1550 | OHCI_TD_IN | OHCI_TD_NOCC | | |
1550 | OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY); | 1551 | OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY); | |
1551 | if (xfer->flags & USBD_SHORT_XFER_OK) | 1552 | if (xfer->flags & USBD_SHORT_XFER_OK) | |
1552 | data->td.td_flags |= HTOO32(OHCI_TD_R); | 1553 | data->td.td_flags |= HTOO32(OHCI_TD_R); | |
1553 | data->td.td_cbp = HTOO32(DMAADDR(&xfer->dmabuf, 0)); | 1554 | data->td.td_cbp = HTOO32(DMAADDR(&xfer->dmabuf, 0)); | |
1554 | data->nexttd = tail; | 1555 | data->nexttd = tail; | |
1555 | data->td.td_nexttd = HTOO32(tail->physaddr); | 1556 | data->td.td_nexttd = HTOO32(tail->physaddr); | |
1556 | data->td.td_be = HTOO32(O32TOH(data->td.td_cbp) + | 1557 | data->td.td_be = HTOO32(O32TOH(data->td.td_cbp) + | |
1557 | xfer->length - 1); | 1558 | xfer->length - 1); | |
1558 | data->len = xfer->length; | 1559 | data->len = xfer->length; | |
1559 | data->xfer = xfer; | 1560 | data->xfer = xfer; | |
1560 | data->flags = OHCI_CALL_DONE | OHCI_ADD_LEN; | 1561 | data->flags = OHCI_CALL_DONE | OHCI_ADD_LEN; | |
1561 | usb_syncmem(&data->dma, data->offs, sizeof(data->td), | 1562 | usb_syncmem(&data->dma, data->offs, sizeof(data->td), | |
1562 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1563 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1563 | xfer->hcpriv = data; | 1564 | xfer->hcpriv = data; | |
1564 | xfer->actlen = 0; | 1565 | xfer->actlen = 0; | |
1565 | 1566 | |||
1566 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | 1567 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | |
1567 | usb_syncmem(&sed->dma, | 1568 | usb_syncmem(&sed->dma, | |
1568 | sed->offs + offsetof(ohci_ed_t, ed_tailp), | 1569 | sed->offs + offsetof(ohci_ed_t, ed_tailp), | |
1569 | sizeof(sed->ed.ed_tailp), | 1570 | sizeof(sed->ed.ed_tailp), | |
1570 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1571 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1571 | opipe->tail.td = tail; | 1572 | opipe->tail.td = tail; | |
1572 | } | 1573 | } | |
1573 | } | 1574 | } | |
1574 | 1575 | |||
1575 | void | 1576 | void | |
1576 | ohci_device_bulk_done(usbd_xfer_handle xfer) | 1577 | ohci_device_bulk_done(usbd_xfer_handle xfer) | |
1577 | { | 1578 | { | |
1578 | #ifdef DIAGNOSTIC | 1579 | #ifdef DIAGNOSTIC | |
1579 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 1580 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
1580 | #endif | 1581 | #endif | |
1581 | int isread = | 1582 | int isread = | |
1582 | (UE_GET_DIR(xfer->pipe->endpoint->edesc->bEndpointAddress) == UE_DIR_IN); | 1583 | (UE_GET_DIR(xfer->pipe->endpoint->edesc->bEndpointAddress) == UE_DIR_IN); | |
1583 | 1584 | |||
1584 | KASSERT(mutex_owned(&sc->sc_lock)); | 1585 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1585 | 1586 | |||
1586 | DPRINTFN(10,("ohci_device_bulk_done: xfer=%p, actlen=%d\n", | 1587 | DPRINTFN(10,("ohci_device_bulk_done: xfer=%p, actlen=%d\n", | |
1587 | xfer, xfer->actlen)); | 1588 | xfer, xfer->actlen)); | |
1588 | usb_syncmem(&xfer->dmabuf, 0, xfer->length, | 1589 | usb_syncmem(&xfer->dmabuf, 0, xfer->length, | |
1589 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | 1590 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | |
1590 | } | 1591 | } | |
1591 | 1592 | |||
1592 | Static void | 1593 | Static void | |
1593 | ohci_rhsc_softint(void *arg) | 1594 | ohci_rhsc_softint(void *arg) | |
1594 | { | 1595 | { | |
1595 | ohci_softc_t *sc = arg; | 1596 | ohci_softc_t *sc = arg; | |
1596 | 1597 | |||
1597 | mutex_enter(&sc->sc_lock); | 1598 | mutex_enter(&sc->sc_lock); | |
1598 | 1599 | |||
1599 | ohci_rhsc(sc, sc->sc_intrxfer); | 1600 | ohci_rhsc(sc, sc->sc_intrxfer); | |
1600 | 1601 | |||
1601 | /* Do not allow RHSC interrupts > 1 per second */ | 1602 | /* Do not allow RHSC interrupts > 1 per second */ | |
1602 | callout_reset(&sc->sc_tmo_rhsc, hz, ohci_rhsc_enable, sc); | 1603 | callout_reset(&sc->sc_tmo_rhsc, hz, ohci_rhsc_enable, sc); | |
1603 | 1604 | |||
1604 | mutex_exit(&sc->sc_lock); | 1605 | mutex_exit(&sc->sc_lock); | |
1605 | } | 1606 | } | |
1606 | 1607 | |||
1607 | void | 1608 | void | |
1608 | ohci_rhsc(ohci_softc_t *sc, usbd_xfer_handle xfer) | 1609 | ohci_rhsc(ohci_softc_t *sc, usbd_xfer_handle xfer) | |
1609 | { | 1610 | { | |
1610 | usbd_pipe_handle pipe; | 1611 | usbd_pipe_handle pipe; | |
1611 | u_char *p; | 1612 | u_char *p; | |
1612 | int i, m; | 1613 | int i, m; | |
1613 | int hstatus; | 1614 | int hstatus; | |
1614 | 1615 | |||
1615 | KASSERT(mutex_owned(&sc->sc_lock)); | 1616 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1616 | 1617 | |||
1617 | hstatus = OREAD4(sc, OHCI_RH_STATUS); | 1618 | hstatus = OREAD4(sc, OHCI_RH_STATUS); | |
1618 | DPRINTF(("ohci_rhsc: sc=%p xfer=%p hstatus=0x%08x\n", | 1619 | DPRINTF(("ohci_rhsc: sc=%p xfer=%p hstatus=0x%08x\n", | |
1619 | sc, xfer, hstatus)); | 1620 | sc, xfer, hstatus)); | |
1620 | 1621 | |||
1621 | if (xfer == NULL) { | 1622 | if (xfer == NULL) { | |
1622 | /* Just ignore the change. */ | 1623 | /* Just ignore the change. */ | |
1623 | return; | 1624 | return; | |
1624 | } | 1625 | } | |
1625 | 1626 | |||
1626 | pipe = xfer->pipe; | 1627 | pipe = xfer->pipe; | |
1627 | 1628 | |||
1628 | p = KERNADDR(&xfer->dmabuf, 0); | 1629 | p = KERNADDR(&xfer->dmabuf, 0); | |
1629 | m = min(sc->sc_noport, xfer->length * 8 - 1); | 1630 | m = min(sc->sc_noport, xfer->length * 8 - 1); | |
1630 | memset(p, 0, xfer->length); | 1631 | memset(p, 0, xfer->length); | |
1631 | for (i = 1; i <= m; i++) { | 1632 | for (i = 1; i <= m; i++) { | |
1632 | /* Pick out CHANGE bits from the status reg. */ | 1633 | /* Pick out CHANGE bits from the status reg. */ | |
1633 | if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16) | 1634 | if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16) | |
1634 | p[i/8] |= 1 << (i%8); | 1635 | p[i/8] |= 1 << (i%8); | |
1635 | } | 1636 | } | |
1636 | DPRINTF(("ohci_rhsc: change=0x%02x\n", *p)); | 1637 | DPRINTF(("ohci_rhsc: change=0x%02x\n", *p)); | |
1637 | xfer->actlen = xfer->length; | 1638 | xfer->actlen = xfer->length; | |
1638 | xfer->status = USBD_NORMAL_COMPLETION; | 1639 | xfer->status = USBD_NORMAL_COMPLETION; | |
1639 | 1640 | |||
1640 | usb_transfer_complete(xfer); | 1641 | usb_transfer_complete(xfer); | |
1641 | } | 1642 | } | |
1642 | 1643 | |||
1643 | void | 1644 | void | |
1644 | ohci_root_intr_done(usbd_xfer_handle xfer) | 1645 | ohci_root_intr_done(usbd_xfer_handle xfer) | |
1645 | { | 1646 | { | |
1646 | } | 1647 | } | |
1647 | 1648 | |||
1648 | void | 1649 | void | |
1649 | ohci_root_ctrl_done(usbd_xfer_handle xfer) | 1650 | ohci_root_ctrl_done(usbd_xfer_handle xfer) | |
1650 | { | 1651 | { | |
1651 | } | 1652 | } | |
1652 | 1653 | |||
1653 | /* | 1654 | /* | |
1654 | * Wait here until controller claims to have an interrupt. | 1655 | * Wait here until controller claims to have an interrupt. | |
1655 | * Then call ohci_intr and return. Use timeout to avoid waiting | 1656 | * Then call ohci_intr and return. Use timeout to avoid waiting | |
1656 | * too long. | 1657 | * too long. | |
1657 | */ | 1658 | */ | |
1658 | void | 1659 | void | |
1659 | ohci_waitintr(ohci_softc_t *sc, usbd_xfer_handle xfer) | 1660 | ohci_waitintr(ohci_softc_t *sc, usbd_xfer_handle xfer) | |
1660 | { | 1661 | { | |
1661 | int timo; | 1662 | int timo; | |
1662 | u_int32_t intrs; | 1663 | u_int32_t intrs; | |
1663 | 1664 | |||
1664 | mutex_enter(&sc->sc_lock); | 1665 | mutex_enter(&sc->sc_lock); | |
1665 | 1666 | |||
1666 | xfer->status = USBD_IN_PROGRESS; | 1667 | xfer->status = USBD_IN_PROGRESS; | |
1667 | for (timo = xfer->timeout; timo >= 0; timo--) { | 1668 | for (timo = xfer->timeout; timo >= 0; timo--) { | |
1668 | usb_delay_ms(&sc->sc_bus, 1); | 1669 | usb_delay_ms(&sc->sc_bus, 1); | |
1669 | if (sc->sc_dying) | 1670 | if (sc->sc_dying) | |
1670 | break; | 1671 | break; | |
1671 | intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs; | 1672 | intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs; | |
1672 | DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs)); | 1673 | DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs)); | |
1673 | #ifdef OHCI_DEBUG | 1674 | #ifdef OHCI_DEBUG | |
1674 | if (ohcidebug > 15) | 1675 | if (ohcidebug > 15) | |
1675 | ohci_dumpregs(sc); | 1676 | ohci_dumpregs(sc); | |
1676 | #endif | 1677 | #endif | |
1677 | if (intrs) { | 1678 | if (intrs) { | |
1678 | mutex_spin_enter(&sc->sc_intr_lock); | 1679 | mutex_spin_enter(&sc->sc_intr_lock); | |
1679 | ohci_intr1(sc); | 1680 | ohci_intr1(sc); | |
1680 | mutex_spin_exit(&sc->sc_intr_lock); | 1681 | mutex_spin_exit(&sc->sc_intr_lock); | |
1681 | if (xfer->status != USBD_IN_PROGRESS) | 1682 | if (xfer->status != USBD_IN_PROGRESS) | |
1682 | return; | 1683 | return; | |
1683 | } | 1684 | } | |
1684 | } | 1685 | } | |
1685 | 1686 | |||
1686 | /* Timeout */ | 1687 | /* Timeout */ | |
1687 | DPRINTF(("ohci_waitintr: timeout\n")); | 1688 | DPRINTF(("ohci_waitintr: timeout\n")); | |
1688 | xfer->status = USBD_TIMEOUT; | 1689 | xfer->status = USBD_TIMEOUT; | |
1689 | usb_transfer_complete(xfer); | 1690 | usb_transfer_complete(xfer); | |
1690 | 1691 | |||
1691 | /* XXX should free TD */ | 1692 | /* XXX should free TD */ | |
1692 | 1693 | |||
1693 | mutex_exit(&sc->sc_lock); | 1694 | mutex_exit(&sc->sc_lock); | |
1694 | } | 1695 | } | |
1695 | 1696 | |||
1696 | void | 1697 | void | |
1697 | ohci_poll(struct usbd_bus *bus) | 1698 | ohci_poll(struct usbd_bus *bus) | |
1698 | { | 1699 | { | |
1699 | ohci_softc_t *sc = bus->hci_private; | 1700 | ohci_softc_t *sc = bus->hci_private; | |
1700 | #ifdef OHCI_DEBUG | 1701 | #ifdef OHCI_DEBUG | |
1701 | static int last; | 1702 | static int last; | |
1702 | int new; | 1703 | int new; | |
1703 | new = OREAD4(sc, OHCI_INTERRUPT_STATUS); | 1704 | new = OREAD4(sc, OHCI_INTERRUPT_STATUS); | |
1704 | if (new != last) { | 1705 | if (new != last) { | |
1705 | DPRINTFN(10,("ohci_poll: intrs=0x%04x\n", new)); | 1706 | DPRINTFN(10,("ohci_poll: intrs=0x%04x\n", new)); | |
1706 | last = new; | 1707 | last = new; | |
1707 | } | 1708 | } | |
1708 | #endif | 1709 | #endif | |
1709 | 1710 | |||
1710 | sc->sc_eintrs |= OHCI_WDH; | 1711 | sc->sc_eintrs |= OHCI_WDH; | |
1711 | if (OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs) { | 1712 | if (OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs) { | |
1712 | mutex_spin_enter(&sc->sc_intr_lock); | 1713 | mutex_spin_enter(&sc->sc_intr_lock); | |
1713 | ohci_intr1(sc); | 1714 | ohci_intr1(sc); | |
1714 | mutex_spin_exit(&sc->sc_intr_lock); | 1715 | mutex_spin_exit(&sc->sc_intr_lock); | |
1715 | } | 1716 | } | |
1716 | } | 1717 | } | |
1717 | 1718 | |||
1718 | usbd_status | 1719 | usbd_status | |
1719 | ohci_device_request(usbd_xfer_handle xfer) | 1720 | ohci_device_request(usbd_xfer_handle xfer) | |
1720 | { | 1721 | { | |
1721 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | 1722 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | |
1722 | usb_device_request_t *req = &xfer->request; | 1723 | usb_device_request_t *req = &xfer->request; | |
1723 | usbd_device_handle dev = opipe->pipe.device; | 1724 | usbd_device_handle dev = opipe->pipe.device; | |
1724 | ohci_softc_t *sc = dev->bus->hci_private; | 1725 | ohci_softc_t *sc = dev->bus->hci_private; | |
1725 | int addr = dev->address; | 1726 | int addr = dev->address; | |
1726 | ohci_soft_td_t *setup, *stat, *next, *tail; | 1727 | ohci_soft_td_t *setup, *stat, *next, *tail; | |
1727 | ohci_soft_ed_t *sed; | 1728 | ohci_soft_ed_t *sed; | |
1728 | int isread; | 1729 | int isread; | |
1729 | int len; | 1730 | int len; | |
1730 | usbd_status err; | 1731 | usbd_status err; | |
1731 | 1732 | |||
1732 | KASSERT(mutex_owned(&sc->sc_lock)); | 1733 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1733 | 1734 | |||
1734 | isread = req->bmRequestType & UT_READ; | 1735 | isread = req->bmRequestType & UT_READ; | |
1735 | len = UGETW(req->wLength); | 1736 | len = UGETW(req->wLength); | |
1736 | 1737 | |||
1737 | DPRINTFN(3,("ohci_device_control type=0x%02x, request=0x%02x, " | 1738 | DPRINTFN(3,("ohci_device_control type=0x%02x, request=0x%02x, " | |
1738 | "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n", | 1739 | "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n", | |
1739 | req->bmRequestType, req->bRequest, UGETW(req->wValue), | 1740 | req->bmRequestType, req->bRequest, UGETW(req->wValue), | |
1740 | UGETW(req->wIndex), len, addr, | 1741 | UGETW(req->wIndex), len, addr, | |
1741 | opipe->pipe.endpoint->edesc->bEndpointAddress)); | 1742 | opipe->pipe.endpoint->edesc->bEndpointAddress)); | |
1742 | 1743 | |||
1743 | setup = opipe->tail.td; | 1744 | setup = opipe->tail.td; | |
1744 | stat = ohci_alloc_std(sc); | 1745 | stat = ohci_alloc_std(sc); | |
1745 | if (stat == NULL) { | 1746 | if (stat == NULL) { | |
1746 | err = USBD_NOMEM; | 1747 | err = USBD_NOMEM; | |
1747 | goto bad1; | 1748 | goto bad1; | |
1748 | } | 1749 | } | |
1749 | tail = ohci_alloc_std(sc); | 1750 | tail = ohci_alloc_std(sc); | |
1750 | if (tail == NULL) { | 1751 | if (tail == NULL) { | |
1751 | err = USBD_NOMEM; | 1752 | err = USBD_NOMEM; | |
1752 | goto bad2; | 1753 | goto bad2; | |
1753 | } | 1754 | } | |
1754 | tail->xfer = NULL; | 1755 | tail->xfer = NULL; | |
1755 | 1756 | |||
1756 | sed = opipe->sed; | 1757 | sed = opipe->sed; | |
1757 | opipe->u.ctl.length = len; | 1758 | opipe->u.ctl.length = len; | |
1758 | 1759 | |||
1759 | /* Update device address and length since they may have changed | 1760 | /* Update device address and length since they may have changed | |
1760 | during the setup of the control pipe in usbd_new_device(). */ | 1761 | during the setup of the control pipe in usbd_new_device(). */ | |
1761 | /* XXX This only needs to be done once, but it's too early in open. */ | 1762 | /* XXX This only needs to be done once, but it's too early in open. */ | |
1762 | /* XXXX Should not touch ED here! */ | 1763 | /* XXXX Should not touch ED here! */ | |
1763 | 1764 | |||
1764 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 1765 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
1765 | sizeof(sed->ed.ed_flags), | 1766 | sizeof(sed->ed.ed_flags), | |
1766 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1767 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1767 | sed->ed.ed_flags = HTOO32( | 1768 | sed->ed.ed_flags = HTOO32( | |
1768 | (O32TOH(sed->ed.ed_flags) & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) | | 1769 | (O32TOH(sed->ed.ed_flags) & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) | | |
1769 | OHCI_ED_SET_FA(addr) | | 1770 | OHCI_ED_SET_FA(addr) | | |
1770 | OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize))); | 1771 | OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize))); | |
1771 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 1772 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
1772 | sizeof(sed->ed.ed_flags), | 1773 | sizeof(sed->ed.ed_flags), | |
1773 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1774 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1774 | 1775 | |||
1775 | next = stat; | 1776 | next = stat; | |
1776 | 1777 | |||
1777 | /* Set up data transaction */ | 1778 | /* Set up data transaction */ | |
1778 | if (len != 0) { | 1779 | if (len != 0) { | |
1779 | ohci_soft_td_t *std = stat; | 1780 | ohci_soft_td_t *std = stat; | |
1780 | 1781 | |||
1781 | err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer, | 1782 | err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer, | |
1782 | std, &stat); | 1783 | std, &stat); | |
1783 | stat = stat->nexttd; /* point at free TD */ | 1784 | stat = stat->nexttd; /* point at free TD */ | |
1784 | if (err) | 1785 | if (err) | |
1785 | goto bad3; | 1786 | goto bad3; | |
1786 | /* Start toggle at 1 and then use the carried toggle. */ | 1787 | /* Start toggle at 1 and then use the carried toggle. */ | |
1787 | std->td.td_flags &= HTOO32(~OHCI_TD_TOGGLE_MASK); | 1788 | std->td.td_flags &= HTOO32(~OHCI_TD_TOGGLE_MASK); | |
1788 | std->td.td_flags |= HTOO32(OHCI_TD_TOGGLE_1); | 1789 | std->td.td_flags |= HTOO32(OHCI_TD_TOGGLE_1); | |
1789 | usb_syncmem(&std->dma, | 1790 | usb_syncmem(&std->dma, | |
1790 | std->offs + offsetof(ohci_td_t, td_flags), | 1791 | std->offs + offsetof(ohci_td_t, td_flags), | |
1791 | sizeof(std->td.td_flags), | 1792 | sizeof(std->td.td_flags), | |
1792 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1793 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1793 | } | 1794 | } | |
1794 | 1795 | |||
1795 | memcpy(KERNADDR(&opipe->u.ctl.reqdma, 0), req, sizeof *req); | 1796 | memcpy(KERNADDR(&opipe->u.ctl.reqdma, 0), req, sizeof *req); | |
1796 | usb_syncmem(&opipe->u.ctl.reqdma, 0, sizeof *req, BUS_DMASYNC_PREWRITE); | 1797 | usb_syncmem(&opipe->u.ctl.reqdma, 0, sizeof *req, BUS_DMASYNC_PREWRITE); | |
1797 | 1798 | |||
1798 | setup->td.td_flags = HTOO32(OHCI_TD_SETUP | OHCI_TD_NOCC | | 1799 | setup->td.td_flags = HTOO32(OHCI_TD_SETUP | OHCI_TD_NOCC | | |
1799 | OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); | 1800 | OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); | |
1800 | setup->td.td_cbp = HTOO32(DMAADDR(&opipe->u.ctl.reqdma, 0)); | 1801 | setup->td.td_cbp = HTOO32(DMAADDR(&opipe->u.ctl.reqdma, 0)); | |
1801 | setup->nexttd = next; | 1802 | setup->nexttd = next; | |
1802 | setup->td.td_nexttd = HTOO32(next->physaddr); | 1803 | setup->td.td_nexttd = HTOO32(next->physaddr); | |
1803 | setup->td.td_be = HTOO32(O32TOH(setup->td.td_cbp) + sizeof *req - 1); | 1804 | setup->td.td_be = HTOO32(O32TOH(setup->td.td_cbp) + sizeof *req - 1); | |
1804 | setup->len = 0; | 1805 | setup->len = 0; | |
1805 | setup->xfer = xfer; | 1806 | setup->xfer = xfer; | |
1806 | setup->flags = 0; | 1807 | setup->flags = 0; | |
1807 | xfer->hcpriv = setup; | 1808 | xfer->hcpriv = setup; | |
1808 | usb_syncmem(&setup->dma, setup->offs, sizeof(setup->td), | 1809 | usb_syncmem(&setup->dma, setup->offs, sizeof(setup->td), | |
1809 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1810 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1810 | 1811 | |||
1811 | stat->td.td_flags = HTOO32( | 1812 | stat->td.td_flags = HTOO32( | |
1812 | (isread ? OHCI_TD_OUT : OHCI_TD_IN) | | 1813 | (isread ? OHCI_TD_OUT : OHCI_TD_IN) | | |
1813 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); | 1814 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); | |
1814 | stat->td.td_cbp = 0; | 1815 | stat->td.td_cbp = 0; | |
1815 | stat->nexttd = tail; | 1816 | stat->nexttd = tail; | |
1816 | stat->td.td_nexttd = HTOO32(tail->physaddr); | 1817 | stat->td.td_nexttd = HTOO32(tail->physaddr); | |
1817 | stat->td.td_be = 0; | 1818 | stat->td.td_be = 0; | |
1818 | stat->flags = OHCI_CALL_DONE; | 1819 | stat->flags = OHCI_CALL_DONE; | |
1819 | stat->len = 0; | 1820 | stat->len = 0; | |
1820 | stat->xfer = xfer; | 1821 | stat->xfer = xfer; | |
1821 | usb_syncmem(&stat->dma, stat->offs, sizeof(stat->td), | 1822 | usb_syncmem(&stat->dma, stat->offs, sizeof(stat->td), | |
1822 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1823 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1823 | 1824 | |||
1824 | #ifdef OHCI_DEBUG | 1825 | #ifdef OHCI_DEBUG | |
1825 | if (ohcidebug > 5) { | 1826 | if (ohcidebug > 5) { | |
1826 | DPRINTF(("ohci_device_request:\n")); | 1827 | DPRINTF(("ohci_device_request:\n")); | |
1827 | ohci_dump_ed(sc, sed); | 1828 | ohci_dump_ed(sc, sed); | |
1828 | ohci_dump_tds(sc, setup); | 1829 | ohci_dump_tds(sc, setup); | |
1829 | } | 1830 | } | |
1830 | #endif | 1831 | #endif | |
1831 | 1832 | |||
1832 | /* Insert ED in schedule */ | 1833 | /* Insert ED in schedule */ | |
1833 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | 1834 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | |
1834 | usb_syncmem(&sed->dma, | 1835 | usb_syncmem(&sed->dma, | |
1835 | sed->offs + offsetof(ohci_ed_t, ed_tailp), | 1836 | sed->offs + offsetof(ohci_ed_t, ed_tailp), | |
1836 | sizeof(sed->ed.ed_tailp), | 1837 | sizeof(sed->ed.ed_tailp), | |
1837 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1838 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1838 | opipe->tail.td = tail; | 1839 | opipe->tail.td = tail; | |
1839 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); | 1840 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); | |
1840 | if (xfer->timeout && !sc->sc_bus.use_polling) { | 1841 | if (xfer->timeout && !sc->sc_bus.use_polling) { | |
1841 | callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout), | 1842 | callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout), | |
1842 | ohci_timeout, xfer); | 1843 | ohci_timeout, xfer); | |
1843 | } | 1844 | } | |
1844 | 1845 | |||
1845 | #ifdef OHCI_DEBUG | 1846 | #ifdef OHCI_DEBUG | |
1846 | if (ohcidebug > 20) { | 1847 | if (ohcidebug > 20) { | |
1847 | delay(10000); | 1848 | delay(10000); | |
1848 | DPRINTF(("ohci_device_request: status=%x\n", | 1849 | DPRINTF(("ohci_device_request: status=%x\n", | |
1849 | OREAD4(sc, OHCI_COMMAND_STATUS))); | 1850 | OREAD4(sc, OHCI_COMMAND_STATUS))); | |
1850 | ohci_dumpregs(sc); | 1851 | ohci_dumpregs(sc); | |
1851 | printf("ctrl head:\n"); | 1852 | printf("ctrl head:\n"); | |
1852 | ohci_dump_ed(sc, sc->sc_ctrl_head); | 1853 | ohci_dump_ed(sc, sc->sc_ctrl_head); | |
1853 | printf("sed:\n"); | 1854 | printf("sed:\n"); | |
1854 | ohci_dump_ed(sc, sed); | 1855 | ohci_dump_ed(sc, sed); | |
1855 | ohci_dump_tds(sc, setup); | 1856 | ohci_dump_tds(sc, setup); | |
1856 | } | 1857 | } | |
1857 | #endif | 1858 | #endif | |
1858 | 1859 | |||
1859 | return (USBD_NORMAL_COMPLETION); | 1860 | return (USBD_NORMAL_COMPLETION); | |
1860 | 1861 | |||
1861 | bad3: | 1862 | bad3: | |
1862 | ohci_free_std(sc, tail); | 1863 | ohci_free_std(sc, tail); | |
1863 | bad2: | 1864 | bad2: | |
1864 | ohci_free_std(sc, stat); | 1865 | ohci_free_std(sc, stat); | |
1865 | bad1: | 1866 | bad1: | |
1866 | return (err); | 1867 | return (err); | |
1867 | } | 1868 | } | |
1868 | 1869 | |||
1869 | /* | 1870 | /* | |
1870 | * Add an ED to the schedule. Called at splusb(). | 1871 | * Add an ED to the schedule. Called at splusb(). | |
1871 | */ | 1872 | */ | |
1872 | void | 1873 | Static void | |
1873 | ohci_add_ed(ohci_softc_t *sc, ohci_soft_ed_t *sed, ohci_soft_ed_t *head) | 1874 | ohci_add_ed(ohci_softc_t *sc, ohci_soft_ed_t *sed, ohci_soft_ed_t *head) | |
1874 | { | 1875 | { | |
1875 | DPRINTFN(8,("ohci_add_ed: sed=%p head=%p\n", sed, head)); | 1876 | DPRINTFN(8,("ohci_add_ed: sed=%p head=%p\n", sed, head)); | |
1876 | 1877 | |||
1877 | SPLUSBCHECK; | 1878 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1879 | ||||
1878 | usb_syncmem(&head->dma, head->offs + offsetof(ohci_ed_t, ed_nexted), | 1880 | usb_syncmem(&head->dma, head->offs + offsetof(ohci_ed_t, ed_nexted), | |
1879 | sizeof(head->ed.ed_nexted), | 1881 | sizeof(head->ed.ed_nexted), | |
1880 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1882 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1881 | sed->next = head->next; | 1883 | sed->next = head->next; | |
1882 | sed->ed.ed_nexted = head->ed.ed_nexted; | 1884 | sed->ed.ed_nexted = head->ed.ed_nexted; | |
1883 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_nexted), | 1885 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_nexted), | |
1884 | sizeof(sed->ed.ed_nexted), | 1886 | sizeof(sed->ed.ed_nexted), | |
1885 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1887 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1886 | head->next = sed; | 1888 | head->next = sed; | |
1887 | head->ed.ed_nexted = HTOO32(sed->physaddr); | 1889 | head->ed.ed_nexted = HTOO32(sed->physaddr); | |
1888 | usb_syncmem(&head->dma, head->offs + offsetof(ohci_ed_t, ed_nexted), | 1890 | usb_syncmem(&head->dma, head->offs + offsetof(ohci_ed_t, ed_nexted), | |
1889 | sizeof(head->ed.ed_nexted), | 1891 | sizeof(head->ed.ed_nexted), | |
1890 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1892 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1891 | } | 1893 | } | |
1892 | 1894 | |||
1893 | /* | 1895 | /* | |
1894 | * Remove an ED from the schedule. Called at splusb(). | 1896 | * Remove an ED from the schedule. Called at splusb(). | |
1895 | */ | 1897 | */ | |
1896 | void | 1898 | Static void | |
1897 | ohci_rem_ed(ohci_soft_ed_t *sed, ohci_soft_ed_t *head) | 1899 | ohci_rem_ed(ohci_softc_t *sc, ohci_soft_ed_t *sed, ohci_soft_ed_t *head) | |
1898 | { | 1900 | { | |
1899 | ohci_soft_ed_t *p; | 1901 | ohci_soft_ed_t *p; | |
1900 | 1902 | |||
1901 | SPLUSBCHECK; | 1903 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1902 | 1904 | |||
1903 | /* XXX */ | 1905 | /* XXX */ | |
1904 | for (p = head; p != NULL && p->next != sed; p = p->next) | 1906 | for (p = head; p != NULL && p->next != sed; p = p->next) | |
1905 | ; | 1907 | ; | |
1906 | if (p == NULL) | 1908 | if (p == NULL) | |
1907 | panic("ohci_rem_ed: ED not found"); | 1909 | panic("ohci_rem_ed: ED not found"); | |
1908 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_nexted), | 1910 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_nexted), | |
1909 | sizeof(sed->ed.ed_nexted), | 1911 | sizeof(sed->ed.ed_nexted), | |
1910 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1912 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1911 | p->next = sed->next; | 1913 | p->next = sed->next; | |
1912 | p->ed.ed_nexted = sed->ed.ed_nexted; | 1914 | p->ed.ed_nexted = sed->ed.ed_nexted; | |
1913 | usb_syncmem(&p->dma, p->offs + offsetof(ohci_ed_t, ed_nexted), | 1915 | usb_syncmem(&p->dma, p->offs + offsetof(ohci_ed_t, ed_nexted), | |
1914 | sizeof(p->ed.ed_nexted), | 1916 | sizeof(p->ed.ed_nexted), | |
1915 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1917 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1916 | } | 1918 | } | |
1917 | 1919 | |||
1918 | /* | 1920 | /* | |
1919 | * When a transfer is completed the TD is added to the done queue by | 1921 | * When a transfer is completed the TD is added to the done queue by | |
1920 | * the host controller. This queue is the processed by software. | 1922 | * the host controller. This queue is the processed by software. | |
1921 | * Unfortunately the queue contains the physical address of the TD | 1923 | * Unfortunately the queue contains the physical address of the TD | |
1922 | * and we have no simple way to translate this back to a kernel address. | 1924 | * and we have no simple way to translate this back to a kernel address. | |
1923 | * To make the translation possible (and fast) we use a hash table of | 1925 | * To make the translation possible (and fast) we use a hash table of | |
1924 | * TDs currently in the schedule. The physical address is used as the | 1926 | * TDs currently in the schedule. The physical address is used as the | |
1925 | * hash value. | 1927 | * hash value. | |
1926 | */ | 1928 | */ | |
1927 | 1929 | |||
1928 | #define HASH(a) (((a) >> 4) % OHCI_HASH_SIZE) | 1930 | #define HASH(a) (((a) >> 4) % OHCI_HASH_SIZE) | |
1929 | /* Called at splusb() */ | 1931 | /* Called at splusb() */ | |
1930 | void | 1932 | void | |
1931 | ohci_hash_add_td(ohci_softc_t *sc, ohci_soft_td_t *std) | 1933 | ohci_hash_add_td(ohci_softc_t *sc, ohci_soft_td_t *std) | |
1932 | { | 1934 | { | |
1933 | int h = HASH(std->physaddr); | 1935 | int h = HASH(std->physaddr); | |
1934 | 1936 | |||
1935 | SPLUSBCHECK; | 1937 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1936 | 1938 | |||
1937 | LIST_INSERT_HEAD(&sc->sc_hash_tds[h], std, hnext); | 1939 | LIST_INSERT_HEAD(&sc->sc_hash_tds[h], std, hnext); | |
1938 | } | 1940 | } | |
1939 | 1941 | |||
1940 | /* Called at splusb() */ | 1942 | /* Called at splusb() */ | |
1941 | void | 1943 | void | |
1942 | ohci_hash_rem_td(ohci_softc_t *sc, ohci_soft_td_t *std) | 1944 | ohci_hash_rem_td(ohci_softc_t *sc, ohci_soft_td_t *std) | |
1943 | { | 1945 | { | |
1944 | SPLUSBCHECK; | 1946 | ||
1947 | KASSERT(mutex_owned(&sc->sc_lock)); | |||
1945 | 1948 | |||
1946 | LIST_REMOVE(std, hnext); | 1949 | LIST_REMOVE(std, hnext); | |
1947 | } | 1950 | } | |
1948 | 1951 | |||
1949 | ohci_soft_td_t * | 1952 | ohci_soft_td_t * | |
1950 | ohci_hash_find_td(ohci_softc_t *sc, ohci_physaddr_t a) | 1953 | ohci_hash_find_td(ohci_softc_t *sc, ohci_physaddr_t a) | |
1951 | { | 1954 | { | |
1952 | int h = HASH(a); | 1955 | int h = HASH(a); | |
1953 | ohci_soft_td_t *std; | 1956 | ohci_soft_td_t *std; | |
1954 | 1957 | |||
1955 | for (std = LIST_FIRST(&sc->sc_hash_tds[h]); | 1958 | for (std = LIST_FIRST(&sc->sc_hash_tds[h]); | |
1956 | std != NULL; | 1959 | std != NULL; | |
1957 | std = LIST_NEXT(std, hnext)) | 1960 | std = LIST_NEXT(std, hnext)) | |
1958 | if (std->physaddr == a) | 1961 | if (std->physaddr == a) | |
1959 | return (std); | 1962 | return (std); | |
1960 | return (NULL); | 1963 | return (NULL); | |
1961 | } | 1964 | } | |
1962 | 1965 | |||
1963 | /* Called at splusb() */ | 1966 | /* Called at splusb() */ | |
1964 | void | 1967 | void | |
1965 | ohci_hash_add_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | 1968 | ohci_hash_add_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | |
1966 | { | 1969 | { | |
1967 | int h = HASH(sitd->physaddr); | 1970 | int h = HASH(sitd->physaddr); | |
1968 | 1971 | |||
1969 | SPLUSBCHECK; | 1972 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1970 | 1973 | |||
1971 | DPRINTFN(10,("ohci_hash_add_itd: sitd=%p physaddr=0x%08lx\n", | 1974 | DPRINTFN(10,("ohci_hash_add_itd: sitd=%p physaddr=0x%08lx\n", | |
1972 | sitd, (u_long)sitd->physaddr)); | 1975 | sitd, (u_long)sitd->physaddr)); | |
1973 | 1976 | |||
1974 | LIST_INSERT_HEAD(&sc->sc_hash_itds[h], sitd, hnext); | 1977 | LIST_INSERT_HEAD(&sc->sc_hash_itds[h], sitd, hnext); | |
1975 | } | 1978 | } | |
1976 | 1979 | |||
1977 | /* Called at splusb() */ | 1980 | /* Called at splusb() */ | |
1978 | void | 1981 | void | |
1979 | ohci_hash_rem_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | 1982 | ohci_hash_rem_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | |
1980 | { | 1983 | { | |
1981 | SPLUSBCHECK; | 1984 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1982 | 1985 | |||
1983 | DPRINTFN(10,("ohci_hash_rem_itd: sitd=%p physaddr=0x%08lx\n", | 1986 | DPRINTFN(10,("ohci_hash_rem_itd: sitd=%p physaddr=0x%08lx\n", | |
1984 | sitd, (u_long)sitd->physaddr)); | 1987 | sitd, (u_long)sitd->physaddr)); | |
1985 | 1988 | |||
1986 | LIST_REMOVE(sitd, hnext); | 1989 | LIST_REMOVE(sitd, hnext); | |
1987 | } | 1990 | } | |
1988 | 1991 | |||
1989 | ohci_soft_itd_t * | 1992 | ohci_soft_itd_t * | |
1990 | ohci_hash_find_itd(ohci_softc_t *sc, ohci_physaddr_t a) | 1993 | ohci_hash_find_itd(ohci_softc_t *sc, ohci_physaddr_t a) | |
1991 | { | 1994 | { | |
1992 | int h = HASH(a); | 1995 | int h = HASH(a); | |
1993 | ohci_soft_itd_t *sitd; | 1996 | ohci_soft_itd_t *sitd; | |
1994 | 1997 | |||
1995 | for (sitd = LIST_FIRST(&sc->sc_hash_itds[h]); | 1998 | for (sitd = LIST_FIRST(&sc->sc_hash_itds[h]); | |
1996 | sitd != NULL; | 1999 | sitd != NULL; | |
1997 | sitd = LIST_NEXT(sitd, hnext)) | 2000 | sitd = LIST_NEXT(sitd, hnext)) | |
1998 | if (sitd->physaddr == a) | 2001 | if (sitd->physaddr == a) | |
1999 | return (sitd); | 2002 | return (sitd); | |
2000 | return (NULL); | 2003 | return (NULL); | |
2001 | } | 2004 | } | |
2002 | 2005 | |||
2003 | void | 2006 | void | |
2004 | ohci_timeout(void *addr) | 2007 | ohci_timeout(void *addr) | |
2005 | { | 2008 | { | |
2006 | struct ohci_xfer *oxfer = addr; | 2009 | struct ohci_xfer *oxfer = addr; | |
2007 | struct ohci_pipe *opipe = (struct ohci_pipe *)oxfer->xfer.pipe; | 2010 | struct ohci_pipe *opipe = (struct ohci_pipe *)oxfer->xfer.pipe; | |
2008 | ohci_softc_t *sc = opipe->pipe.device->bus->hci_private; | 2011 | ohci_softc_t *sc = opipe->pipe.device->bus->hci_private; | |
2009 | 2012 | |||
2010 | DPRINTF(("ohci_timeout: oxfer=%p\n", oxfer)); | 2013 | DPRINTF(("ohci_timeout: oxfer=%p\n", oxfer)); | |
2011 | 2014 | |||
2012 | if (sc->sc_dying) { | 2015 | if (sc->sc_dying) { | |
2013 | ohci_abort_xfer(&oxfer->xfer, USBD_TIMEOUT); | 2016 | ohci_abort_xfer(&oxfer->xfer, USBD_TIMEOUT); | |
2014 | return; | 2017 | return; | |
2015 | } | 2018 | } | |
2016 | 2019 | |||
2017 | /* Execute the abort in a process context. */ | 2020 | /* Execute the abort in a process context. */ | |
2018 | usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr); | 2021 | usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr); | |
2019 | usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task, | 2022 | usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task, | |
2020 | USB_TASKQ_HC); | 2023 | USB_TASKQ_HC); | |
2021 | } | 2024 | } | |
2022 | 2025 | |||
2023 | void | 2026 | void | |
2024 | ohci_timeout_task(void *addr) | 2027 | ohci_timeout_task(void *addr) | |
2025 | { | 2028 | { | |
2026 | usbd_xfer_handle xfer = addr; | 2029 | usbd_xfer_handle xfer = addr; | |
2027 | 2030 | |||
2028 | DPRINTF(("ohci_timeout_task: xfer=%p\n", xfer)); | 2031 | DPRINTF(("ohci_timeout_task: xfer=%p\n", xfer)); | |
2029 | 2032 | |||
2030 | ohci_abort_xfer(xfer, USBD_TIMEOUT); | 2033 | ohci_abort_xfer(xfer, USBD_TIMEOUT); | |
2031 | } | 2034 | } | |
2032 | 2035 | |||
2033 | #ifdef OHCI_DEBUG | 2036 | #ifdef OHCI_DEBUG | |
2034 | void | 2037 | void | |
2035 | ohci_dump_tds(ohci_softc_t *sc, ohci_soft_td_t *std) | 2038 | ohci_dump_tds(ohci_softc_t *sc, ohci_soft_td_t *std) | |
2036 | { | 2039 | { | |
2037 | for (; std; std = std->nexttd) | 2040 | for (; std; std = std->nexttd) | |
2038 | ohci_dump_td(sc, std); | 2041 | ohci_dump_td(sc, std); | |
2039 | } | 2042 | } | |
2040 | 2043 | |||
2041 | void | 2044 | void | |
2042 | ohci_dump_td(ohci_softc_t *sc, ohci_soft_td_t *std) | 2045 | ohci_dump_td(ohci_softc_t *sc, ohci_soft_td_t *std) | |
2043 | { | 2046 | { | |
2044 | char sbuf[128]; | 2047 | char sbuf[128]; | |
2045 | 2048 | |||
2046 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | 2049 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | |
2047 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 2050 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
2048 | snprintb(sbuf, sizeof(sbuf), | 2051 | snprintb(sbuf, sizeof(sbuf), | |
2049 | "\20\23R\24OUT\25IN\31TOG1\32SETTOGGLE", | 2052 | "\20\23R\24OUT\25IN\31TOG1\32SETTOGGLE", | |
2050 | (u_int32_t)O32TOH(std->td.td_flags)); | 2053 | (u_int32_t)O32TOH(std->td.td_flags)); | |
2051 | printf("TD(%p) at %08lx: %s delay=%d ec=%d cc=%d\ncbp=0x%08lx " | 2054 | printf("TD(%p) at %08lx: %s delay=%d ec=%d cc=%d\ncbp=0x%08lx " | |
2052 | "nexttd=0x%08lx be=0x%08lx\n", | 2055 | "nexttd=0x%08lx be=0x%08lx\n", | |
2053 | std, (u_long)std->physaddr, sbuf, | 2056 | std, (u_long)std->physaddr, sbuf, | |
2054 | OHCI_TD_GET_DI(O32TOH(std->td.td_flags)), | 2057 | OHCI_TD_GET_DI(O32TOH(std->td.td_flags)), | |
2055 | OHCI_TD_GET_EC(O32TOH(std->td.td_flags)), | 2058 | OHCI_TD_GET_EC(O32TOH(std->td.td_flags)), | |
2056 | OHCI_TD_GET_CC(O32TOH(std->td.td_flags)), | 2059 | OHCI_TD_GET_CC(O32TOH(std->td.td_flags)), | |
2057 | (u_long)O32TOH(std->td.td_cbp), | 2060 | (u_long)O32TOH(std->td.td_cbp), | |
2058 | (u_long)O32TOH(std->td.td_nexttd), | 2061 | (u_long)O32TOH(std->td.td_nexttd), | |
2059 | (u_long)O32TOH(std->td.td_be)); | 2062 | (u_long)O32TOH(std->td.td_be)); | |
2060 | } | 2063 | } | |
2061 | 2064 | |||
2062 | void | 2065 | void | |
2063 | ohci_dump_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | 2066 | ohci_dump_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | |
2064 | { | 2067 | { | |
2065 | int i; | 2068 | int i; | |
2066 | 2069 | |||
2067 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), | 2070 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), | |
2068 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 2071 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
2069 | printf("ITD(%p) at %08lx: sf=%d di=%d fc=%d cc=%d\n" | 2072 | printf("ITD(%p) at %08lx: sf=%d di=%d fc=%d cc=%d\n" | |
2070 | "bp0=0x%08lx next=0x%08lx be=0x%08lx\n", | 2073 | "bp0=0x%08lx next=0x%08lx be=0x%08lx\n", | |
2071 | sitd, (u_long)sitd->physaddr, | 2074 | sitd, (u_long)sitd->physaddr, | |
2072 | OHCI_ITD_GET_SF(O32TOH(sitd->itd.itd_flags)), | 2075 | OHCI_ITD_GET_SF(O32TOH(sitd->itd.itd_flags)), | |
2073 | OHCI_ITD_GET_DI(O32TOH(sitd->itd.itd_flags)), | 2076 | OHCI_ITD_GET_DI(O32TOH(sitd->itd.itd_flags)), | |
2074 | OHCI_ITD_GET_FC(O32TOH(sitd->itd.itd_flags)), | 2077 | OHCI_ITD_GET_FC(O32TOH(sitd->itd.itd_flags)), | |
2075 | OHCI_ITD_GET_CC(O32TOH(sitd->itd.itd_flags)), | 2078 | OHCI_ITD_GET_CC(O32TOH(sitd->itd.itd_flags)), | |
2076 | (u_long)O32TOH(sitd->itd.itd_bp0), | 2079 | (u_long)O32TOH(sitd->itd.itd_bp0), | |
2077 | (u_long)O32TOH(sitd->itd.itd_nextitd), | 2080 | (u_long)O32TOH(sitd->itd.itd_nextitd), | |
2078 | (u_long)O32TOH(sitd->itd.itd_be)); | 2081 | (u_long)O32TOH(sitd->itd.itd_be)); | |
2079 | for (i = 0; i < OHCI_ITD_NOFFSET; i++) | 2082 | for (i = 0; i < OHCI_ITD_NOFFSET; i++) | |
2080 | printf("offs[%d]=0x%04x ", i, | 2083 | printf("offs[%d]=0x%04x ", i, | |
2081 | (u_int)O16TOH(sitd->itd.itd_offset[i])); | 2084 | (u_int)O16TOH(sitd->itd.itd_offset[i])); | |
2082 | printf("\n"); | 2085 | printf("\n"); | |
2083 | } | 2086 | } | |
2084 | 2087 | |||
2085 | void | 2088 | void | |
2086 | ohci_dump_itds(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | 2089 | ohci_dump_itds(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | |
2087 | { | 2090 | { | |
2088 | for (; sitd; sitd = sitd->nextitd) | 2091 | for (; sitd; sitd = sitd->nextitd) | |
2089 | ohci_dump_itd(sc, sitd); | 2092 | ohci_dump_itd(sc, sitd); | |
2090 | } | 2093 | } | |
2091 | 2094 | |||
2092 | void | 2095 | void | |
2093 | ohci_dump_ed(ohci_softc_t *sc, ohci_soft_ed_t *sed) | 2096 | ohci_dump_ed(ohci_softc_t *sc, ohci_soft_ed_t *sed) | |
2094 | { | 2097 | { | |
2095 | char sbuf[128], sbuf2[128]; | 2098 | char sbuf[128], sbuf2[128]; | |
2096 | 2099 | |||
2097 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 2100 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
2098 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 2101 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
2099 | snprintb(sbuf, sizeof(sbuf), | 2102 | snprintb(sbuf, sizeof(sbuf), | |
2100 | "\20\14OUT\15IN\16LOWSPEED\17SKIP\20ISO", | 2103 | "\20\14OUT\15IN\16LOWSPEED\17SKIP\20ISO", | |
2101 | (u_int32_t)O32TOH(sed->ed.ed_flags)); | 2104 | (u_int32_t)O32TOH(sed->ed.ed_flags)); | |
2102 | snprintb(sbuf2, sizeof(sbuf2), "\20\1HALT\2CARRY", | 2105 | snprintb(sbuf2, sizeof(sbuf2), "\20\1HALT\2CARRY", | |
2103 | (u_int32_t)O32TOH(sed->ed.ed_headp)); | 2106 | (u_int32_t)O32TOH(sed->ed.ed_headp)); | |
2104 | 2107 | |||
2105 | printf("ED(%p) at 0x%08lx: addr=%d endpt=%d maxp=%d flags=%s\ntailp=0x%08lx " | 2108 | printf("ED(%p) at 0x%08lx: addr=%d endpt=%d maxp=%d flags=%s\ntailp=0x%08lx " | |
2106 | "headflags=%s headp=0x%08lx nexted=0x%08lx\n", | 2109 | "headflags=%s headp=0x%08lx nexted=0x%08lx\n", | |
2107 | sed, (u_long)sed->physaddr, | 2110 | sed, (u_long)sed->physaddr, | |
2108 | OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)), | 2111 | OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)), | |
2109 | OHCI_ED_GET_EN(O32TOH(sed->ed.ed_flags)), | 2112 | OHCI_ED_GET_EN(O32TOH(sed->ed.ed_flags)), | |
2110 | OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)), sbuf, | 2113 | OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)), sbuf, | |
2111 | (u_long)O32TOH(sed->ed.ed_tailp), sbuf2, | 2114 | (u_long)O32TOH(sed->ed.ed_tailp), sbuf2, | |
2112 | (u_long)O32TOH(sed->ed.ed_headp), | 2115 | (u_long)O32TOH(sed->ed.ed_headp), | |
2113 | (u_long)O32TOH(sed->ed.ed_nexted)); | 2116 | (u_long)O32TOH(sed->ed.ed_nexted)); | |
2114 | } | 2117 | } | |
2115 | #endif | 2118 | #endif | |
2116 | 2119 | |||
2117 | usbd_status | 2120 | usbd_status | |
2118 | ohci_open(usbd_pipe_handle pipe) | 2121 | ohci_open(usbd_pipe_handle pipe) | |
2119 | { | 2122 | { | |
2120 | usbd_device_handle dev = pipe->device; | 2123 | usbd_device_handle dev = pipe->device; | |
2121 | ohci_softc_t *sc = dev->bus->hci_private; | 2124 | ohci_softc_t *sc = dev->bus->hci_private; | |
2122 | usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc; | 2125 | usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc; | |
2123 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | 2126 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | |
2124 | u_int8_t addr = dev->address; | 2127 | u_int8_t addr = dev->address; | |
2125 | u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE; | 2128 | u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE; | |
2126 | ohci_soft_ed_t *sed; | 2129 | ohci_soft_ed_t *sed; | |
2127 | ohci_soft_td_t *std; | 2130 | ohci_soft_td_t *std; | |
2128 | ohci_soft_itd_t *sitd; | 2131 | ohci_soft_itd_t *sitd; | |
2129 | ohci_physaddr_t tdphys; | 2132 | ohci_physaddr_t tdphys; | |
2130 | u_int32_t fmt; | 2133 | u_int32_t fmt; | |
2131 | usbd_status err = USBD_NOMEM; | 2134 | usbd_status err = USBD_NOMEM; | |
2132 | int ival; | 2135 | int ival; | |
2133 | 2136 | |||
2134 | DPRINTFN(1, ("ohci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", | 2137 | DPRINTFN(1, ("ohci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", | |
2135 | pipe, addr, ed->bEndpointAddress, sc->sc_addr)); | 2138 | pipe, addr, ed->bEndpointAddress, sc->sc_addr)); | |
2136 | 2139 | |||
2137 | if (sc->sc_dying) { | 2140 | if (sc->sc_dying) { | |
2138 | err = USBD_IOERROR; | 2141 | err = USBD_IOERROR; | |
2139 | goto bad0; | 2142 | goto bad0; | |
2140 | } | 2143 | } | |
2141 | 2144 | |||
2142 | std = NULL; | 2145 | std = NULL; | |
2143 | sed = NULL; | 2146 | sed = NULL; | |
2144 | 2147 | |||
2145 | if (addr == sc->sc_addr) { | 2148 | if (addr == sc->sc_addr) { | |
2146 | switch (ed->bEndpointAddress) { | 2149 | switch (ed->bEndpointAddress) { | |
2147 | case USB_CONTROL_ENDPOINT: | 2150 | case USB_CONTROL_ENDPOINT: | |
2148 | pipe->methods = &ohci_root_ctrl_methods; | 2151 | pipe->methods = &ohci_root_ctrl_methods; | |
2149 | break; | 2152 | break; | |
2150 | case UE_DIR_IN | OHCI_INTR_ENDPT: | 2153 | case UE_DIR_IN | OHCI_INTR_ENDPT: | |
2151 | pipe->methods = &ohci_root_intr_methods; | 2154 | pipe->methods = &ohci_root_intr_methods; | |
2152 | break; | 2155 | break; | |
2153 | default: | 2156 | default: | |
2154 | err = USBD_INVAL; | 2157 | err = USBD_INVAL; | |
2155 | goto bad0; | 2158 | goto bad0; | |
2156 | } | 2159 | } | |
2157 | } else { | 2160 | } else { | |
2158 | sed = ohci_alloc_sed(sc); | 2161 | sed = ohci_alloc_sed(sc); | |
2159 | if (sed == NULL) | 2162 | if (sed == NULL) | |
2160 | goto bad0; | 2163 | goto bad0; | |
2161 | opipe->sed = sed; | 2164 | opipe->sed = sed; | |
2162 | if (xfertype == UE_ISOCHRONOUS) { | 2165 | if (xfertype == UE_ISOCHRONOUS) { | |
2163 | sitd = ohci_alloc_sitd(sc); | 2166 | sitd = ohci_alloc_sitd(sc); | |
2164 | if (sitd == NULL) | 2167 | if (sitd == NULL) | |
2165 | goto bad1; | 2168 | goto bad1; | |
2166 | opipe->tail.itd = sitd; | 2169 | opipe->tail.itd = sitd; | |
2167 | tdphys = sitd->physaddr; | 2170 | tdphys = sitd->physaddr; | |
2168 | fmt = OHCI_ED_FORMAT_ISO; | 2171 | fmt = OHCI_ED_FORMAT_ISO; | |
2169 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 2172 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
2170 | fmt |= OHCI_ED_DIR_IN; | 2173 | fmt |= OHCI_ED_DIR_IN; | |
2171 | else | 2174 | else | |
2172 | fmt |= OHCI_ED_DIR_OUT; | 2175 | fmt |= OHCI_ED_DIR_OUT; | |
2173 | } else { | 2176 | } else { | |
2174 | std = ohci_alloc_std(sc); | 2177 | std = ohci_alloc_std(sc); | |
2175 | if (std == NULL) | 2178 | if (std == NULL) | |
2176 | goto bad1; | 2179 | goto bad1; | |
2177 | opipe->tail.td = std; | 2180 | opipe->tail.td = std; | |
2178 | tdphys = std->physaddr; | 2181 | tdphys = std->physaddr; | |
2179 | fmt = OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD; | 2182 | fmt = OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD; | |
2180 | } | 2183 | } | |
2181 | sed->ed.ed_flags = HTOO32( | 2184 | sed->ed.ed_flags = HTOO32( | |
2182 | OHCI_ED_SET_FA(addr) | | 2185 | OHCI_ED_SET_FA(addr) | | |
2183 | OHCI_ED_SET_EN(UE_GET_ADDR(ed->bEndpointAddress)) | | 2186 | OHCI_ED_SET_EN(UE_GET_ADDR(ed->bEndpointAddress)) | | |
2184 | (dev->speed == USB_SPEED_LOW ? OHCI_ED_SPEED : 0) | | 2187 | (dev->speed == USB_SPEED_LOW ? OHCI_ED_SPEED : 0) | | |
2185 | fmt | | 2188 | fmt | | |
2186 | OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize))); | 2189 | OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize))); | |
2187 | sed->ed.ed_headp = HTOO32(tdphys | | 2190 | sed->ed.ed_headp = HTOO32(tdphys | | |
2188 | (pipe->endpoint->datatoggle ? OHCI_TOGGLECARRY : 0)); | 2191 | (pipe->endpoint->datatoggle ? OHCI_TOGGLECARRY : 0)); | |
2189 | sed->ed.ed_tailp = HTOO32(tdphys); | 2192 | sed->ed.ed_tailp = HTOO32(tdphys); | |
2190 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 2193 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
2191 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2194 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2192 | 2195 | |||
2193 | switch (xfertype) { | 2196 | switch (xfertype) { | |
2194 | case UE_CONTROL: | 2197 | case UE_CONTROL: | |
2195 | pipe->methods = &ohci_device_ctrl_methods; | 2198 | pipe->methods = &ohci_device_ctrl_methods; | |
2196 | err = usb_allocmem(&sc->sc_bus, | 2199 | err = usb_allocmem(&sc->sc_bus, | |
2197 | sizeof(usb_device_request_t), | 2200 | sizeof(usb_device_request_t), | |
2198 | 0, &opipe->u.ctl.reqdma); | 2201 | 0, &opipe->u.ctl.reqdma); | |
2199 | if (err) | 2202 | if (err) | |
2200 | goto bad; | 2203 | goto bad; | |
2201 | mutex_enter(&sc->sc_lock); | 2204 | mutex_enter(&sc->sc_lock); | |
2202 | ohci_add_ed(sc, sed, sc->sc_ctrl_head); | 2205 | ohci_add_ed(sc, sed, sc->sc_ctrl_head); | |
2203 | mutex_exit(&sc->sc_lock); | 2206 | mutex_exit(&sc->sc_lock); | |
2204 | break; | 2207 | break; | |
2205 | case UE_INTERRUPT: | 2208 | case UE_INTERRUPT: | |
2206 | pipe->methods = &ohci_device_intr_methods; | 2209 | pipe->methods = &ohci_device_intr_methods; | |
2207 | ival = pipe->interval; | 2210 | ival = pipe->interval; | |
2208 | if (ival == USBD_DEFAULT_INTERVAL) | 2211 | if (ival == USBD_DEFAULT_INTERVAL) | |
2209 | ival = ed->bInterval; | 2212 | ival = ed->bInterval; | |
2210 | return (ohci_device_setintr(sc, opipe, ival)); | 2213 | return (ohci_device_setintr(sc, opipe, ival)); | |
2211 | case UE_ISOCHRONOUS: | 2214 | case UE_ISOCHRONOUS: | |
2212 | pipe->methods = &ohci_device_isoc_methods; | 2215 | pipe->methods = &ohci_device_isoc_methods; | |
2213 | return (ohci_setup_isoc(pipe)); | 2216 | return (ohci_setup_isoc(pipe)); | |
2214 | case UE_BULK: | 2217 | case UE_BULK: | |
2215 | pipe->methods = &ohci_device_bulk_methods; | 2218 | pipe->methods = &ohci_device_bulk_methods; | |
2216 | mutex_enter(&sc->sc_lock); | 2219 | mutex_enter(&sc->sc_lock); | |
2217 | ohci_add_ed(sc, sed, sc->sc_bulk_head); | 2220 | ohci_add_ed(sc, sed, sc->sc_bulk_head); | |
2218 | mutex_exit(&sc->sc_lock); | 2221 | mutex_exit(&sc->sc_lock); | |
2219 | break; | 2222 | break; | |
2220 | } | 2223 | } | |
2221 | } | 2224 | } | |
2222 | 2225 | |||
2223 | return USBD_NORMAL_COMPLETION; | 2226 | return USBD_NORMAL_COMPLETION; | |
2224 | 2227 | |||
2225 | bad: | 2228 | bad: | |
2226 | if (std != NULL) | 2229 | if (std != NULL) | |
2227 | ohci_free_std(sc, std); | 2230 | ohci_free_std(sc, std); | |
2228 | bad1: | 2231 | bad1: | |
2229 | if (sed != NULL) | 2232 | if (sed != NULL) | |
2230 | ohci_free_sed(sc, sed); | 2233 | ohci_free_sed(sc, sed); | |
2231 | bad0: | 2234 | bad0: | |
2232 | return err; | 2235 | return err; | |
2233 | 2236 | |||
2234 | } | 2237 | } | |
2235 | 2238 | |||
2236 | /* | 2239 | /* | |
2237 | * Close a reqular pipe. | 2240 | * Close a reqular pipe. | |
2238 | * Assumes that there are no pending transactions. | 2241 | * Assumes that there are no pending transactions. | |
2239 | */ | 2242 | */ | |
2240 | void | 2243 | void | |
2241 | ohci_close_pipe(usbd_pipe_handle pipe, ohci_soft_ed_t *head) | 2244 | ohci_close_pipe(usbd_pipe_handle pipe, ohci_soft_ed_t *head) | |
2242 | { | 2245 | { | |
2243 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | 2246 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | |
2244 | ohci_softc_t *sc = pipe->device->bus->hci_private; | 2247 | ohci_softc_t *sc = pipe->device->bus->hci_private; | |
2245 | ohci_soft_ed_t *sed = opipe->sed; | 2248 | ohci_soft_ed_t *sed = opipe->sed; | |
2246 | 2249 | |||
2247 | KASSERT(mutex_owned(&sc->sc_lock)); | 2250 | KASSERT(mutex_owned(&sc->sc_lock)); | |
2248 | 2251 | |||
2249 | #ifdef DIAGNOSTIC | 2252 | #ifdef DIAGNOSTIC | |
2250 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | 2253 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | |
2251 | if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) != | 2254 | if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) != | |
2252 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) { | 2255 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) { | |
2253 | ohci_soft_td_t *std; | 2256 | ohci_soft_td_t *std; | |
2254 | std = ohci_hash_find_td(sc, O32TOH(sed->ed.ed_headp)); | 2257 | std = ohci_hash_find_td(sc, O32TOH(sed->ed.ed_headp)); | |
2255 | printf("ohci_close_pipe: pipe not empty sed=%p hd=0x%x " | 2258 | printf("ohci_close_pipe: pipe not empty sed=%p hd=0x%x " | |
2256 | "tl=0x%x pipe=%p, std=%p\n", sed, | 2259 | "tl=0x%x pipe=%p, std=%p\n", sed, | |
2257 | (int)O32TOH(sed->ed.ed_headp), | 2260 | (int)O32TOH(sed->ed.ed_headp), | |
2258 | (int)O32TOH(sed->ed.ed_tailp), | 2261 | (int)O32TOH(sed->ed.ed_tailp), | |
2259 | pipe, std); | 2262 | pipe, std); | |
2260 | #ifdef USB_DEBUG | 2263 | #ifdef USB_DEBUG | |
2261 | usbd_dump_pipe(&opipe->pipe); | 2264 | usbd_dump_pipe(&opipe->pipe); | |
2262 | #endif | 2265 | #endif | |
2263 | #ifdef OHCI_DEBUG | 2266 | #ifdef OHCI_DEBUG | |
2264 | ohci_dump_ed(sc, sed); | 2267 | ohci_dump_ed(sc, sed); | |
2265 | if (std) | 2268 | if (std) | |
2266 | ohci_dump_td(sc, std); | 2269 | ohci_dump_td(sc, std); | |
2267 | #endif | 2270 | #endif | |
2268 | usb_delay_ms(&sc->sc_bus, 2); | 2271 | usb_delay_ms(&sc->sc_bus, 2); | |
2269 | if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) != | 2272 | if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) != | |
2270 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) | 2273 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) | |
2271 | printf("ohci_close_pipe: pipe still not empty\n"); | 2274 | printf("ohci_close_pipe: pipe still not empty\n"); | |
2272 | } | 2275 | } | |
2273 | #endif | 2276 | #endif | |
2274 | ohci_rem_ed(sed, head); | 2277 | ohci_rem_ed(sc, sed, head); | |
2275 | /* Make sure the host controller is not touching this ED */ | 2278 | /* Make sure the host controller is not touching this ED */ | |
2276 | usb_delay_ms(&sc->sc_bus, 1); | 2279 | usb_delay_ms(&sc->sc_bus, 1); | |
2277 | pipe->endpoint->datatoggle = | 2280 | pipe->endpoint->datatoggle = | |
2278 | (O32TOH(sed->ed.ed_headp) & OHCI_TOGGLECARRY) ? 1 : 0; | 2281 | (O32TOH(sed->ed.ed_headp) & OHCI_TOGGLECARRY) ? 1 : 0; | |
2279 | ohci_free_sed(sc, opipe->sed); | 2282 | ohci_free_sed(sc, opipe->sed); | |
2280 | } | 2283 | } | |
2281 | 2284 | |||
2282 | /* | 2285 | /* | |
2283 | * Abort a device request. | 2286 | * Abort a device request. | |
2284 | * If this routine is called at splusb() it guarantees that the request | 2287 | * If this routine is called at splusb() it guarantees that the request | |
2285 | * will be removed from the hardware scheduling and that the callback | 2288 | * will be removed from the hardware scheduling and that the callback | |
2286 | * for it will be called with USBD_CANCELLED status. | 2289 | * for it will be called with USBD_CANCELLED status. | |
2287 | * It's impossible to guarantee that the requested transfer will not | 2290 | * It's impossible to guarantee that the requested transfer will not | |
2288 | * have happened since the hardware runs concurrently. | 2291 | * have happened since the hardware runs concurrently. | |
2289 | * If the transaction has already happened we rely on the ordinary | 2292 | * If the transaction has already happened we rely on the ordinary | |
2290 | * interrupt processing to process it. | 2293 | * interrupt processing to process it. | |
2291 | */ | 2294 | */ | |
2292 | void | 2295 | void | |
2293 | ohci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) | 2296 | ohci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) | |
2294 | { | 2297 | { | |
2295 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | 2298 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | |
2296 | ohci_softc_t *sc = opipe->pipe.device->bus->hci_private; | 2299 | ohci_softc_t *sc = opipe->pipe.device->bus->hci_private; | |
2297 | ohci_soft_ed_t *sed = opipe->sed; | 2300 | ohci_soft_ed_t *sed = opipe->sed; | |
2298 | ohci_soft_td_t *p, *n; | 2301 | ohci_soft_td_t *p, *n; | |
2299 | ohci_physaddr_t headp; | 2302 | ohci_physaddr_t headp; | |
2300 | int hit; | 2303 | int hit; | |
2301 | int wake; | 2304 | int wake; | |
2302 | 2305 | |||
2303 | DPRINTF(("ohci_abort_xfer: xfer=%p pipe=%p sed=%p\n", xfer, opipe,sed)); | 2306 | DPRINTF(("ohci_abort_xfer: xfer=%p pipe=%p sed=%p\n", xfer, opipe,sed)); | |
2304 | 2307 | |||
2305 | if (sc->sc_dying) { | 2308 | if (sc->sc_dying) { | |
2306 | /* If we're dying, just do the software part. */ | 2309 | /* If we're dying, just do the software part. */ | |
2307 | mutex_enter(&sc->sc_lock); | 2310 | mutex_enter(&sc->sc_lock); | |
2308 | xfer->status = status; /* make software ignore it */ | 2311 | xfer->status = status; /* make software ignore it */ | |
2309 | callout_halt(&xfer->timeout_handle, &sc->sc_lock); | 2312 | callout_halt(&xfer->timeout_handle, &sc->sc_lock); | |
2310 | usb_transfer_complete(xfer); | 2313 | usb_transfer_complete(xfer); | |
2311 | mutex_exit(&sc->sc_lock); | 2314 | mutex_exit(&sc->sc_lock); | |
2312 | return; | 2315 | return; | |
2313 | } | 2316 | } | |
2314 | 2317 | |||
2315 | if (xfer->device->bus->intr_context || !curproc) | 2318 | if (xfer->device->bus->intr_context || !curproc) | |
2316 | panic("ohci_abort_xfer: not in process context"); | 2319 | panic("ohci_abort_xfer: not in process context"); | |
2317 | 2320 | |||
2318 | mutex_enter(&sc->sc_lock); | 2321 | mutex_enter(&sc->sc_lock); | |
2319 | 2322 | |||
2320 | /* | 2323 | /* | |
2321 | * If an abort is already in progress then just wait for it to | 2324 | * If an abort is already in progress then just wait for it to | |
2322 | * complete and return. | 2325 | * complete and return. | |
2323 | */ | 2326 | */ | |
2324 | if (xfer->hcflags & UXFER_ABORTING) { | 2327 | if (xfer->hcflags & UXFER_ABORTING) { | |
2325 | DPRINTFN(2, ("ohci_abort_xfer: already aborting\n")); | 2328 | DPRINTFN(2, ("ohci_abort_xfer: already aborting\n")); | |
2326 | #ifdef DIAGNOSTIC | 2329 | #ifdef DIAGNOSTIC | |
2327 | if (status == USBD_TIMEOUT) | 2330 | if (status == USBD_TIMEOUT) | |
2328 | printf("0hci_abort_xfer: TIMEOUT while aborting\n"); | 2331 | printf("0hci_abort_xfer: TIMEOUT while aborting\n"); | |
2329 | #endif | 2332 | #endif | |
2330 | /* Override the status which might be USBD_TIMEOUT. */ | 2333 | /* Override the status which might be USBD_TIMEOUT. */ | |
2331 | xfer->status = status; | 2334 | xfer->status = status; | |
2332 | DPRINTFN(2, ("ohci_abort_xfer: waiting for abort to finish\n")); | 2335 | DPRINTFN(2, ("ohci_abort_xfer: waiting for abort to finish\n")); | |
2333 | xfer->hcflags |= UXFER_ABORTWAIT; | 2336 | xfer->hcflags |= UXFER_ABORTWAIT; | |
2334 | while (xfer->hcflags & UXFER_ABORTING) | 2337 | while (xfer->hcflags & UXFER_ABORTING) | |
2335 | cv_wait(&xfer->hccv, &sc->sc_lock); | 2338 | cv_wait(&xfer->hccv, &sc->sc_lock); | |
2336 | goto done; | 2339 | goto done; | |
2337 | return; | 2340 | return; | |
2338 | } | 2341 | } | |
2339 | xfer->hcflags |= UXFER_ABORTING; | 2342 | xfer->hcflags |= UXFER_ABORTING; | |
2340 | 2343 | |||
2341 | /* | 2344 | /* | |
2342 | * Step 1: Make interrupt routine and hardware ignore xfer. | 2345 | * Step 1: Make interrupt routine and hardware ignore xfer. | |
2343 | */ | 2346 | */ | |
2344 | xfer->status = status; /* make software ignore it */ | 2347 | xfer->status = status; /* make software ignore it */ | |
2345 | callout_stop(&xfer->timeout_handle); | 2348 | callout_stop(&xfer->timeout_handle); | |
2346 | DPRINTFN(1,("ohci_abort_xfer: stop ed=%p\n", sed)); | 2349 | DPRINTFN(1,("ohci_abort_xfer: stop ed=%p\n", sed)); | |
2347 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 2350 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
2348 | sizeof(sed->ed.ed_flags), | 2351 | sizeof(sed->ed.ed_flags), | |
2349 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 2352 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
2350 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); /* force hardware skip */ | 2353 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); /* force hardware skip */ | |
2351 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 2354 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
2352 | sizeof(sed->ed.ed_flags), | 2355 | sizeof(sed->ed.ed_flags), | |
2353 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2356 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2354 | 2357 | |||
2355 | /* | 2358 | /* | |
2356 | * Step 2: Wait until we know hardware has finished any possible | 2359 | * Step 2: Wait until we know hardware has finished any possible | |
2357 | * use of the xfer. Also make sure the soft interrupt routine | 2360 | * use of the xfer. Also make sure the soft interrupt routine | |
2358 | * has run. | 2361 | * has run. | |
2359 | */ | 2362 | */ | |
2360 | usb_delay_ms(opipe->pipe.device->bus, 20); /* Hardware finishes in 1ms */ | 2363 | usb_delay_ms(opipe->pipe.device->bus, 20); /* Hardware finishes in 1ms */ | |
2361 | sc->sc_softwake = 1; | 2364 | sc->sc_softwake = 1; | |
2362 | usb_schedsoftintr(&sc->sc_bus); | 2365 | usb_schedsoftintr(&sc->sc_bus); | |
2363 | cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); | 2366 | cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); | |
2364 | 2367 | |||
2365 | /* | 2368 | /* | |
2366 | * Step 3: Remove any vestiges of the xfer from the hardware. | 2369 | * Step 3: Remove any vestiges of the xfer from the hardware. | |
2367 | * The complication here is that the hardware may have executed | 2370 | * The complication here is that the hardware may have executed | |
2368 | * beyond the xfer we're trying to abort. So as we're scanning | 2371 | * beyond the xfer we're trying to abort. So as we're scanning | |
2369 | * the TDs of this xfer we check if the hardware points to | 2372 | * the TDs of this xfer we check if the hardware points to | |
2370 | * any of them. | 2373 | * any of them. | |
2371 | */ | 2374 | */ | |
2372 | p = xfer->hcpriv; | 2375 | p = xfer->hcpriv; | |
2373 | #ifdef DIAGNOSTIC | 2376 | #ifdef DIAGNOSTIC | |
2374 | if (p == NULL) { | 2377 | if (p == NULL) { | |
2375 | xfer->hcflags &= ~UXFER_ABORTING; /* XXX */ | 2378 | xfer->hcflags &= ~UXFER_ABORTING; /* XXX */ | |
2376 | printf("ohci_abort_xfer: hcpriv is NULL\n"); | 2379 | printf("ohci_abort_xfer: hcpriv is NULL\n"); | |
2377 | goto done; | 2380 | goto done; | |
2378 | } | 2381 | } | |
2379 | #endif | 2382 | #endif | |
2380 | #ifdef OHCI_DEBUG | 2383 | #ifdef OHCI_DEBUG | |
2381 | if (ohcidebug > 1) { | 2384 | if (ohcidebug > 1) { | |
2382 | DPRINTF(("ohci_abort_xfer: sed=\n")); | 2385 | DPRINTF(("ohci_abort_xfer: sed=\n")); | |
2383 | ohci_dump_ed(sc, sed); | 2386 | ohci_dump_ed(sc, sed); | |
2384 | ohci_dump_tds(sc, p); | 2387 | ohci_dump_tds(sc, p); | |
2385 | } | 2388 | } | |
2386 | #endif | 2389 | #endif | |
2387 | headp = O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK; | 2390 | headp = O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK; | |
2388 | hit = 0; | 2391 | hit = 0; | |
2389 | for (; p->xfer == xfer; p = n) { | 2392 | for (; p->xfer == xfer; p = n) { | |
2390 | hit |= headp == p->physaddr; | 2393 | hit |= headp == p->physaddr; | |
2391 | n = p->nexttd; | 2394 | n = p->nexttd; | |
2392 | ohci_free_std(sc, p); | 2395 | ohci_free_std(sc, p); | |
2393 | } | 2396 | } | |
2394 | /* Zap headp register if hardware pointed inside the xfer. */ | 2397 | /* Zap headp register if hardware pointed inside the xfer. */ | |
2395 | if (hit) { | 2398 | if (hit) { | |
2396 | DPRINTFN(1,("ohci_abort_xfer: set hd=0x%08x, tl=0x%08x\n", | 2399 | DPRINTFN(1,("ohci_abort_xfer: set hd=0x%08x, tl=0x%08x\n", | |
2397 | (int)p->physaddr, (int)O32TOH(sed->ed.ed_tailp))); | 2400 | (int)p->physaddr, (int)O32TOH(sed->ed.ed_tailp))); | |
2398 | sed->ed.ed_headp = HTOO32(p->physaddr); /* unlink TDs */ | 2401 | sed->ed.ed_headp = HTOO32(p->physaddr); /* unlink TDs */ | |
2399 | usb_syncmem(&sed->dma, | 2402 | usb_syncmem(&sed->dma, | |
2400 | sed->offs + offsetof(ohci_ed_t, ed_headp), | 2403 | sed->offs + offsetof(ohci_ed_t, ed_headp), | |
2401 | sizeof(sed->ed.ed_headp), | 2404 | sizeof(sed->ed.ed_headp), | |
2402 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2405 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2403 | } else { | 2406 | } else { | |
2404 | DPRINTFN(1,("ohci_abort_xfer: no hit\n")); | 2407 | DPRINTFN(1,("ohci_abort_xfer: no hit\n")); | |
2405 | } | 2408 | } | |
2406 | 2409 | |||
2407 | /* | 2410 | /* | |
2408 | * Step 4: Turn on hardware again. | 2411 | * Step 4: Turn on hardware again. | |
2409 | */ | 2412 | */ | |
2410 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 2413 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
2411 | sizeof(sed->ed.ed_flags), | 2414 | sizeof(sed->ed.ed_flags), | |
2412 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 2415 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
2413 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); /* remove hardware skip */ | 2416 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); /* remove hardware skip */ | |
2414 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 2417 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
2415 | sizeof(sed->ed.ed_flags), | 2418 | sizeof(sed->ed.ed_flags), | |
2416 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2419 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2417 | 2420 | |||
2418 | /* | 2421 | /* | |
2419 | * Step 5: Execute callback. | 2422 | * Step 5: Execute callback. | |
2420 | */ | 2423 | */ | |
2421 | wake = xfer->hcflags & UXFER_ABORTWAIT; | 2424 | wake = xfer->hcflags & UXFER_ABORTWAIT; | |
2422 | xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | 2425 | xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |
2423 | usb_transfer_complete(xfer); | 2426 | usb_transfer_complete(xfer); | |
2424 | if (wake) | 2427 | if (wake) | |
2425 | cv_broadcast(&xfer->hccv); | 2428 | cv_broadcast(&xfer->hccv); | |
2426 | 2429 | |||
2427 | done: | 2430 | done: | |
2428 | mutex_exit(&sc->sc_lock); | 2431 | mutex_exit(&sc->sc_lock); | |
2429 | } | 2432 | } | |
2430 | 2433 | |||
2431 | /* | 2434 | /* | |
2432 | * Data structures and routines to emulate the root hub. | 2435 | * Data structures and routines to emulate the root hub. | |
2433 | */ | 2436 | */ | |
2434 | Static usb_device_descriptor_t ohci_devd = { | 2437 | Static usb_device_descriptor_t ohci_devd = { | |
2435 | USB_DEVICE_DESCRIPTOR_SIZE, | 2438 | USB_DEVICE_DESCRIPTOR_SIZE, | |
2436 | UDESC_DEVICE, /* type */ | 2439 | UDESC_DEVICE, /* type */ | |
2437 | {0x00, 0x01}, /* USB version */ | 2440 | {0x00, 0x01}, /* USB version */ | |
2438 | UDCLASS_HUB, /* class */ | 2441 | UDCLASS_HUB, /* class */ | |
2439 | UDSUBCLASS_HUB, /* subclass */ | 2442 | UDSUBCLASS_HUB, /* subclass */ | |
2440 | UDPROTO_FSHUB, /* protocol */ | 2443 | UDPROTO_FSHUB, /* protocol */ | |
2441 | 64, /* max packet */ | 2444 | 64, /* max packet */ | |
2442 | {0},{0},{0x00,0x01}, /* device id */ | 2445 | {0},{0},{0x00,0x01}, /* device id */ | |
2443 | 1,2,0, /* string indicies */ | 2446 | 1,2,0, /* string indicies */ | |
2444 | 1 /* # of configurations */ | 2447 | 1 /* # of configurations */ | |
2445 | }; | 2448 | }; | |
2446 | 2449 | |||
2447 | Static const usb_config_descriptor_t ohci_confd = { | 2450 | Static const usb_config_descriptor_t ohci_confd = { | |
2448 | USB_CONFIG_DESCRIPTOR_SIZE, | 2451 | USB_CONFIG_DESCRIPTOR_SIZE, | |
2449 | UDESC_CONFIG, | 2452 | UDESC_CONFIG, | |
2450 | {USB_CONFIG_DESCRIPTOR_SIZE + | 2453 | {USB_CONFIG_DESCRIPTOR_SIZE + | |
2451 | USB_INTERFACE_DESCRIPTOR_SIZE + | 2454 | USB_INTERFACE_DESCRIPTOR_SIZE + | |
2452 | USB_ENDPOINT_DESCRIPTOR_SIZE}, | 2455 | USB_ENDPOINT_DESCRIPTOR_SIZE}, | |
2453 | 1, | 2456 | 1, | |
2454 | 1, | 2457 | 1, | |
2455 | 0, | 2458 | 0, | |
2456 | UC_ATTR_MBO | UC_SELF_POWERED, | 2459 | UC_ATTR_MBO | UC_SELF_POWERED, | |
2457 | 0 /* max power */ | 2460 | 0 /* max power */ | |
2458 | }; | 2461 | }; | |
2459 | 2462 | |||
2460 | Static const usb_interface_descriptor_t ohci_ifcd = { | 2463 | Static const usb_interface_descriptor_t ohci_ifcd = { | |
2461 | USB_INTERFACE_DESCRIPTOR_SIZE, | 2464 | USB_INTERFACE_DESCRIPTOR_SIZE, | |
2462 | UDESC_INTERFACE, | 2465 | UDESC_INTERFACE, | |
2463 | 0, | 2466 | 0, | |
2464 | 0, | 2467 | 0, | |
2465 | 1, | 2468 | 1, | |
2466 | UICLASS_HUB, | 2469 | UICLASS_HUB, | |
2467 | UISUBCLASS_HUB, | 2470 | UISUBCLASS_HUB, | |
2468 | UIPROTO_FSHUB, | 2471 | UIPROTO_FSHUB, | |
2469 | 0 | 2472 | 0 | |
2470 | }; | 2473 | }; | |
2471 | 2474 | |||
2472 | Static const usb_endpoint_descriptor_t ohci_endpd = { | 2475 | Static const usb_endpoint_descriptor_t ohci_endpd = { | |
2473 | .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, | 2476 | .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, | |
2474 | .bDescriptorType = UDESC_ENDPOINT, | 2477 | .bDescriptorType = UDESC_ENDPOINT, | |
2475 | .bEndpointAddress = UE_DIR_IN | OHCI_INTR_ENDPT, | 2478 | .bEndpointAddress = UE_DIR_IN | OHCI_INTR_ENDPT, | |
2476 | .bmAttributes = UE_INTERRUPT, | 2479 | .bmAttributes = UE_INTERRUPT, | |
2477 | .wMaxPacketSize = {8, 0}, /* max packet */ | 2480 | .wMaxPacketSize = {8, 0}, /* max packet */ | |
2478 | .bInterval = 255, | 2481 | .bInterval = 255, | |
2479 | }; | 2482 | }; | |
2480 | 2483 | |||
2481 | Static const usb_hub_descriptor_t ohci_hubd = { | 2484 | Static const usb_hub_descriptor_t ohci_hubd = { | |
2482 | .bDescLength = USB_HUB_DESCRIPTOR_SIZE, | 2485 | .bDescLength = USB_HUB_DESCRIPTOR_SIZE, | |
2483 | .bDescriptorType = UDESC_HUB, | 2486 | .bDescriptorType = UDESC_HUB, | |
2484 | }; | 2487 | }; | |
2485 | 2488 | |||
2486 | /* | 2489 | /* | |
2487 | * Simulate a hardware hub by handling all the necessary requests. | 2490 | * Simulate a hardware hub by handling all the necessary requests. | |
2488 | */ | 2491 | */ | |
2489 | Static usbd_status | 2492 | Static usbd_status | |
2490 | ohci_root_ctrl_transfer(usbd_xfer_handle xfer) | 2493 | ohci_root_ctrl_transfer(usbd_xfer_handle xfer) | |
2491 | { | 2494 | { | |
2492 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2495 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2493 | usbd_status err; | 2496 | usbd_status err; | |
2494 | 2497 | |||
2495 | /* Insert last in queue. */ | 2498 | /* Insert last in queue. */ | |
2496 | mutex_enter(&sc->sc_lock); | 2499 | mutex_enter(&sc->sc_lock); | |
2497 | err = usb_insert_transfer(xfer); | 2500 | err = usb_insert_transfer(xfer); | |
2498 | mutex_exit(&sc->sc_lock); | 2501 | mutex_exit(&sc->sc_lock); | |
2499 | if (err) | 2502 | if (err) | |
2500 | return (err); | 2503 | return (err); | |
2501 | 2504 | |||
2502 | /* Pipe isn't running, start first */ | 2505 | /* Pipe isn't running, start first */ | |
2503 | return (ohci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 2506 | return (ohci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
2504 | } | 2507 | } | |
2505 | 2508 | |||
2506 | Static usbd_status | 2509 | Static usbd_status | |
2507 | ohci_root_ctrl_start(usbd_xfer_handle xfer) | 2510 | ohci_root_ctrl_start(usbd_xfer_handle xfer) | |
2508 | { | 2511 | { | |
2509 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2512 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2510 | usb_device_request_t *req; | 2513 | usb_device_request_t *req; | |
2511 | void *buf = NULL; | 2514 | void *buf = NULL; | |
2512 | int port, i; | 2515 | int port, i; | |
2513 | int len, value, index, l, totlen = 0; | 2516 | int len, value, index, l, totlen = 0; | |
2514 | usb_port_status_t ps; | 2517 | usb_port_status_t ps; | |
2515 | usb_hub_descriptor_t hubd; | 2518 | usb_hub_descriptor_t hubd; | |
2516 | usbd_status err; | 2519 | usbd_status err; | |
2517 | u_int32_t v; | 2520 | u_int32_t v; | |
2518 | 2521 | |||
2519 | if (sc->sc_dying) | 2522 | if (sc->sc_dying) | |
2520 | return (USBD_IOERROR); | 2523 | return (USBD_IOERROR); | |
2521 | 2524 | |||
2522 | #ifdef DIAGNOSTIC | 2525 | #ifdef DIAGNOSTIC | |
2523 | if (!(xfer->rqflags & URQ_REQUEST)) | 2526 | if (!(xfer->rqflags & URQ_REQUEST)) | |
2524 | /* XXX panic */ | 2527 | /* XXX panic */ | |
2525 | return (USBD_INVAL); | 2528 | return (USBD_INVAL); | |
2526 | #endif | 2529 | #endif | |
2527 | req = &xfer->request; | 2530 | req = &xfer->request; | |
2528 | 2531 | |||
2529 | DPRINTFN(4,("ohci_root_ctrl_control type=0x%02x request=%02x\n", | 2532 | DPRINTFN(4,("ohci_root_ctrl_control type=0x%02x request=%02x\n", | |
2530 | req->bmRequestType, req->bRequest)); | 2533 | req->bmRequestType, req->bRequest)); | |
2531 | 2534 | |||
2532 | len = UGETW(req->wLength); | 2535 | len = UGETW(req->wLength); | |
2533 | value = UGETW(req->wValue); | 2536 | value = UGETW(req->wValue); | |
2534 | index = UGETW(req->wIndex); | 2537 | index = UGETW(req->wIndex); | |
2535 | 2538 | |||
2536 | if (len != 0) | 2539 | if (len != 0) | |
2537 | buf = KERNADDR(&xfer->dmabuf, 0); | 2540 | buf = KERNADDR(&xfer->dmabuf, 0); | |
2538 | 2541 | |||
2539 | #define C(x,y) ((x) | ((y) << 8)) | 2542 | #define C(x,y) ((x) | ((y) << 8)) | |
2540 | switch(C(req->bRequest, req->bmRequestType)) { | 2543 | switch(C(req->bRequest, req->bmRequestType)) { | |
2541 | case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): | 2544 | case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): | |
2542 | case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): | 2545 | case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): | |
2543 | case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): | 2546 | case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): | |
2544 | /* | 2547 | /* | |
2545 | * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops | 2548 | * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops | |
2546 | * for the integrated root hub. | 2549 | * for the integrated root hub. | |
2547 | */ | 2550 | */ | |
2548 | break; | 2551 | break; | |
2549 | case C(UR_GET_CONFIG, UT_READ_DEVICE): | 2552 | case C(UR_GET_CONFIG, UT_READ_DEVICE): | |
2550 | if (len > 0) { | 2553 | if (len > 0) { | |
2551 | *(u_int8_t *)buf = sc->sc_conf; | 2554 | *(u_int8_t *)buf = sc->sc_conf; | |
2552 | totlen = 1; | 2555 | totlen = 1; | |
2553 | } | 2556 | } | |
2554 | break; | 2557 | break; | |
2555 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): | 2558 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): | |
2556 | DPRINTFN(8,("ohci_root_ctrl_control wValue=0x%04x\n", value)); | 2559 | DPRINTFN(8,("ohci_root_ctrl_control wValue=0x%04x\n", value)); | |
2557 | if (len == 0) | 2560 | if (len == 0) | |
2558 | break; | 2561 | break; | |
2559 | switch(value >> 8) { | 2562 | switch(value >> 8) { | |
2560 | case UDESC_DEVICE: | 2563 | case UDESC_DEVICE: | |
2561 | if ((value & 0xff) != 0) { | 2564 | if ((value & 0xff) != 0) { | |
2562 | err = USBD_IOERROR; | 2565 | err = USBD_IOERROR; | |
2563 | goto ret; | 2566 | goto ret; | |
2564 | } | 2567 | } | |
2565 | totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); | 2568 | totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); | |
2566 | USETW(ohci_devd.idVendor, sc->sc_id_vendor); | 2569 | USETW(ohci_devd.idVendor, sc->sc_id_vendor); | |
2567 | memcpy(buf, &ohci_devd, l); | 2570 | memcpy(buf, &ohci_devd, l); | |
2568 | break; | 2571 | break; | |
2569 | case UDESC_CONFIG: | 2572 | case UDESC_CONFIG: | |
2570 | if ((value & 0xff) != 0) { | 2573 | if ((value & 0xff) != 0) { | |
2571 | err = USBD_IOERROR; | 2574 | err = USBD_IOERROR; | |
2572 | goto ret; | 2575 | goto ret; | |
2573 | } | 2576 | } | |
2574 | totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE); | 2577 | totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE); | |
2575 | memcpy(buf, &ohci_confd, l); | 2578 | memcpy(buf, &ohci_confd, l); | |
2576 | buf = (char *)buf + l; | 2579 | buf = (char *)buf + l; | |
2577 | len -= l; | 2580 | len -= l; | |
2578 | l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE); | 2581 | l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE); | |
2579 | totlen += l; | 2582 | totlen += l; | |
2580 | memcpy(buf, &ohci_ifcd, l); | 2583 | memcpy(buf, &ohci_ifcd, l); | |
2581 | buf = (char *)buf + l; | 2584 | buf = (char *)buf + l; | |
2582 | len -= l; | 2585 | len -= l; | |
2583 | l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE); | 2586 | l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE); | |
2584 | totlen += l; | 2587 | totlen += l; | |
2585 | memcpy(buf, &ohci_endpd, l); | 2588 | memcpy(buf, &ohci_endpd, l); | |
2586 | break; | 2589 | break; | |
2587 | case UDESC_STRING: | 2590 | case UDESC_STRING: | |
2588 | #define sd ((usb_string_descriptor_t *)buf) | 2591 | #define sd ((usb_string_descriptor_t *)buf) | |
2589 | switch (value & 0xff) { | 2592 | switch (value & 0xff) { | |
2590 | case 0: /* Language table */ | 2593 | case 0: /* Language table */ | |
2591 | totlen = usb_makelangtbl(sd, len); | 2594 | totlen = usb_makelangtbl(sd, len); | |
2592 | break; | 2595 | break; | |
2593 | case 1: /* Vendor */ | 2596 | case 1: /* Vendor */ | |
2594 | totlen = usb_makestrdesc(sd, len, | 2597 | totlen = usb_makestrdesc(sd, len, | |
2595 | sc->sc_vendor); | 2598 | sc->sc_vendor); | |
2596 | break; | 2599 | break; | |
2597 | case 2: /* Product */ | 2600 | case 2: /* Product */ | |
2598 | totlen = usb_makestrdesc(sd, len, | 2601 | totlen = usb_makestrdesc(sd, len, | |
2599 | "OHCI root hub"); | 2602 | "OHCI root hub"); | |
2600 | break; | 2603 | break; | |
2601 | } | 2604 | } | |
2602 | #undef sd | 2605 | #undef sd | |
2603 | break; | 2606 | break; | |
2604 | default: | 2607 | default: | |
2605 | err = USBD_IOERROR; | 2608 | err = USBD_IOERROR; | |
2606 | goto ret; | 2609 | goto ret; | |
2607 | } | 2610 | } | |
2608 | break; | 2611 | break; | |
2609 | case C(UR_GET_INTERFACE, UT_READ_INTERFACE): | 2612 | case C(UR_GET_INTERFACE, UT_READ_INTERFACE): | |
2610 | if (len > 0) { | 2613 | if (len > 0) { | |
2611 | *(u_int8_t *)buf = 0; | 2614 | *(u_int8_t *)buf = 0; | |
2612 | totlen = 1; | 2615 | totlen = 1; | |
2613 | } | 2616 | } | |
2614 | break; | 2617 | break; | |
2615 | case C(UR_GET_STATUS, UT_READ_DEVICE): | 2618 | case C(UR_GET_STATUS, UT_READ_DEVICE): | |
2616 | if (len > 1) { | 2619 | if (len > 1) { | |
2617 | USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED); | 2620 | USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED); | |
2618 | totlen = 2; | 2621 | totlen = 2; | |
2619 | } | 2622 | } | |
2620 | break; | 2623 | break; | |
2621 | case C(UR_GET_STATUS, UT_READ_INTERFACE): | 2624 | case C(UR_GET_STATUS, UT_READ_INTERFACE): | |
2622 | case C(UR_GET_STATUS, UT_READ_ENDPOINT): | 2625 | case C(UR_GET_STATUS, UT_READ_ENDPOINT): | |
2623 | if (len > 1) { | 2626 | if (len > 1) { | |
2624 | USETW(((usb_status_t *)buf)->wStatus, 0); | 2627 | USETW(((usb_status_t *)buf)->wStatus, 0); | |
2625 | totlen = 2; | 2628 | totlen = 2; | |
2626 | } | 2629 | } | |
2627 | break; | 2630 | break; | |
2628 | case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): | 2631 | case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): | |
2629 | if (value >= USB_MAX_DEVICES) { | 2632 | if (value >= USB_MAX_DEVICES) { | |
2630 | err = USBD_IOERROR; | 2633 | err = USBD_IOERROR; | |
2631 | goto ret; | 2634 | goto ret; | |
2632 | } | 2635 | } | |
2633 | sc->sc_addr = value; | 2636 | sc->sc_addr = value; | |
2634 | break; | 2637 | break; | |
2635 | case C(UR_SET_CONFIG, UT_WRITE_DEVICE): | 2638 | case C(UR_SET_CONFIG, UT_WRITE_DEVICE): | |
2636 | if (value != 0 && value != 1) { | 2639 | if (value != 0 && value != 1) { | |
2637 | err = USBD_IOERROR; | 2640 | err = USBD_IOERROR; | |
2638 | goto ret; | 2641 | goto ret; | |
2639 | } | 2642 | } | |
2640 | sc->sc_conf = value; | 2643 | sc->sc_conf = value; | |
2641 | break; | 2644 | break; | |
2642 | case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): | 2645 | case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): | |
2643 | break; | 2646 | break; | |
2644 | case C(UR_SET_FEATURE, UT_WRITE_DEVICE): | 2647 | case C(UR_SET_FEATURE, UT_WRITE_DEVICE): | |
2645 | case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): | 2648 | case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): | |
2646 | case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): | 2649 | case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): | |
2647 | err = USBD_IOERROR; | 2650 | err = USBD_IOERROR; | |
2648 | goto ret; | 2651 | goto ret; | |
2649 | case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): | 2652 | case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): | |
2650 | break; | 2653 | break; | |
2651 | case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): | 2654 | case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): | |
2652 | break; | 2655 | break; | |
2653 | /* Hub requests */ | 2656 | /* Hub requests */ | |
2654 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): | 2657 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): | |
2655 | break; | 2658 | break; | |
2656 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): | 2659 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): | |
2657 | DPRINTFN(8, ("ohci_root_ctrl_control: UR_CLEAR_PORT_FEATURE " | 2660 | DPRINTFN(8, ("ohci_root_ctrl_control: UR_CLEAR_PORT_FEATURE " | |
2658 | "port=%d feature=%d\n", | 2661 | "port=%d feature=%d\n", | |
2659 | index, value)); | 2662 | index, value)); | |
2660 | if (index < 1 || index > sc->sc_noport) { | 2663 | if (index < 1 || index > sc->sc_noport) { | |
2661 | err = USBD_IOERROR; | 2664 | err = USBD_IOERROR; | |
2662 | goto ret; | 2665 | goto ret; | |
2663 | } | 2666 | } | |
2664 | port = OHCI_RH_PORT_STATUS(index); | 2667 | port = OHCI_RH_PORT_STATUS(index); | |
2665 | switch(value) { | 2668 | switch(value) { | |
2666 | case UHF_PORT_ENABLE: | 2669 | case UHF_PORT_ENABLE: | |
2667 | OWRITE4(sc, port, UPS_CURRENT_CONNECT_STATUS); | 2670 | OWRITE4(sc, port, UPS_CURRENT_CONNECT_STATUS); | |
2668 | break; | 2671 | break; | |
2669 | case UHF_PORT_SUSPEND: | 2672 | case UHF_PORT_SUSPEND: | |
2670 | OWRITE4(sc, port, UPS_OVERCURRENT_INDICATOR); | 2673 | OWRITE4(sc, port, UPS_OVERCURRENT_INDICATOR); | |
2671 | break; | 2674 | break; | |
2672 | case UHF_PORT_POWER: | 2675 | case UHF_PORT_POWER: | |
2673 | /* Yes, writing to the LOW_SPEED bit clears power. */ | 2676 | /* Yes, writing to the LOW_SPEED bit clears power. */ | |
2674 | OWRITE4(sc, port, UPS_LOW_SPEED); | 2677 | OWRITE4(sc, port, UPS_LOW_SPEED); | |
2675 | break; | 2678 | break; | |
2676 | case UHF_C_PORT_CONNECTION: | 2679 | case UHF_C_PORT_CONNECTION: | |
2677 | OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16); | 2680 | OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16); | |
2678 | break; | 2681 | break; | |
2679 | case UHF_C_PORT_ENABLE: | 2682 | case UHF_C_PORT_ENABLE: | |
2680 | OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16); | 2683 | OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16); | |
2681 | break; | 2684 | break; | |
2682 | case UHF_C_PORT_SUSPEND: | 2685 | case UHF_C_PORT_SUSPEND: | |
2683 | OWRITE4(sc, port, UPS_C_SUSPEND << 16); | 2686 | OWRITE4(sc, port, UPS_C_SUSPEND << 16); | |
2684 | break; | 2687 | break; | |
2685 | case UHF_C_PORT_OVER_CURRENT: | 2688 | case UHF_C_PORT_OVER_CURRENT: | |
2686 | OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16); | 2689 | OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16); | |
2687 | break; | 2690 | break; | |
2688 | case UHF_C_PORT_RESET: | 2691 | case UHF_C_PORT_RESET: | |
2689 | OWRITE4(sc, port, UPS_C_PORT_RESET << 16); | 2692 | OWRITE4(sc, port, UPS_C_PORT_RESET << 16); | |
2690 | break; | 2693 | break; | |
2691 | default: | 2694 | default: | |
2692 | err = USBD_IOERROR; | 2695 | err = USBD_IOERROR; | |
2693 | goto ret; | 2696 | goto ret; | |
2694 | } | 2697 | } | |
2695 | switch(value) { | 2698 | switch(value) { | |
2696 | case UHF_C_PORT_CONNECTION: | 2699 | case UHF_C_PORT_CONNECTION: | |
2697 | case UHF_C_PORT_ENABLE: | 2700 | case UHF_C_PORT_ENABLE: | |
2698 | case UHF_C_PORT_SUSPEND: | 2701 | case UHF_C_PORT_SUSPEND: | |
2699 | case UHF_C_PORT_OVER_CURRENT: | 2702 | case UHF_C_PORT_OVER_CURRENT: | |
2700 | case UHF_C_PORT_RESET: | 2703 | case UHF_C_PORT_RESET: | |
2701 | /* Enable RHSC interrupt if condition is cleared. */ | 2704 | /* Enable RHSC interrupt if condition is cleared. */ | |
2702 | if ((OREAD4(sc, port) >> 16) == 0) | 2705 | if ((OREAD4(sc, port) >> 16) == 0) | |
2703 | ohci_rhsc_enable(sc); | 2706 | ohci_rhsc_enable(sc); | |
2704 | break; | 2707 | break; | |
2705 | default: | 2708 | default: | |
2706 | break; | 2709 | break; | |
2707 | } | 2710 | } | |
2708 | break; | 2711 | break; | |
2709 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): | 2712 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): | |
2710 | if (len == 0) | 2713 | if (len == 0) | |
2711 | break; | 2714 | break; | |
2712 | if ((value & 0xff) != 0) { | 2715 | if ((value & 0xff) != 0) { | |
2713 | err = USBD_IOERROR; | 2716 | err = USBD_IOERROR; | |
2714 | goto ret; | 2717 | goto ret; | |
2715 | } | 2718 | } | |
2716 | v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); | 2719 | v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); | |
2717 | hubd = ohci_hubd; | 2720 | hubd = ohci_hubd; | |
2718 | hubd.bNbrPorts = sc->sc_noport; | 2721 | hubd.bNbrPorts = sc->sc_noport; | |
2719 | USETW(hubd.wHubCharacteristics, | 2722 | USETW(hubd.wHubCharacteristics, | |
2720 | (v & OHCI_NPS ? UHD_PWR_NO_SWITCH : | 2723 | (v & OHCI_NPS ? UHD_PWR_NO_SWITCH : | |
2721 | v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL) | 2724 | v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL) | |
2722 | /* XXX overcurrent */ | 2725 | /* XXX overcurrent */ | |
2723 | ); | 2726 | ); | |
2724 | hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v); | 2727 | hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v); | |
2725 | v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); | 2728 | v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); | |
2726 | for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8) | 2729 | for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8) | |
2727 | hubd.DeviceRemovable[i++] = (u_int8_t)v; | 2730 | hubd.DeviceRemovable[i++] = (u_int8_t)v; | |
2728 | hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i; | 2731 | hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i; | |
2729 | l = min(len, hubd.bDescLength); | 2732 | l = min(len, hubd.bDescLength); | |
2730 | totlen = l; | 2733 | totlen = l; | |
2731 | memcpy(buf, &hubd, l); | 2734 | memcpy(buf, &hubd, l); | |
2732 | break; | 2735 | break; | |
2733 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): | 2736 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): | |
2734 | if (len != 4) { | 2737 | if (len != 4) { | |
2735 | err = USBD_IOERROR; | 2738 | err = USBD_IOERROR; | |
2736 | goto ret; | 2739 | goto ret; | |
2737 | } | 2740 | } | |
2738 | memset(buf, 0, len); /* ? XXX */ | 2741 | memset(buf, 0, len); /* ? XXX */ | |
2739 | totlen = len; | 2742 | totlen = len; | |
2740 | break; | 2743 | break; | |
2741 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): | 2744 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): | |
2742 | DPRINTFN(8,("ohci_root_ctrl_transfer: get port status i=%d\n", | 2745 | DPRINTFN(8,("ohci_root_ctrl_transfer: get port status i=%d\n", | |
2743 | index)); | 2746 | index)); | |
2744 | if (index < 1 || index > sc->sc_noport) { | 2747 | if (index < 1 || index > sc->sc_noport) { | |
2745 | err = USBD_IOERROR; | 2748 | err = USBD_IOERROR; | |
2746 | goto ret; | 2749 | goto ret; | |
2747 | } | 2750 | } | |
2748 | if (len != 4) { | 2751 | if (len != 4) { | |
2749 | err = USBD_IOERROR; | 2752 | err = USBD_IOERROR; | |
2750 | goto ret; | 2753 | goto ret; | |
2751 | } | 2754 | } | |
2752 | v = OREAD4(sc, OHCI_RH_PORT_STATUS(index)); | 2755 | v = OREAD4(sc, OHCI_RH_PORT_STATUS(index)); | |
2753 | DPRINTFN(8,("ohci_root_ctrl_transfer: port status=0x%04x\n", | 2756 | DPRINTFN(8,("ohci_root_ctrl_transfer: port status=0x%04x\n", | |
2754 | v)); | 2757 | v)); | |
2755 | USETW(ps.wPortStatus, v); | 2758 | USETW(ps.wPortStatus, v); | |
2756 | USETW(ps.wPortChange, v >> 16); | 2759 | USETW(ps.wPortChange, v >> 16); | |
2757 | l = min(len, sizeof ps); | 2760 | l = min(len, sizeof ps); | |
2758 | memcpy(buf, &ps, l); | 2761 | memcpy(buf, &ps, l); | |
2759 | totlen = l; | 2762 | totlen = l; | |
2760 | break; | 2763 | break; | |
2761 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): | 2764 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): | |
2762 | err = USBD_IOERROR; | 2765 | err = USBD_IOERROR; | |
2763 | goto ret; | 2766 | goto ret; | |
2764 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): | 2767 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): | |
2765 | break; | 2768 | break; | |
2766 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): | 2769 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): | |
2767 | if (index < 1 || index > sc->sc_noport) { | 2770 | if (index < 1 || index > sc->sc_noport) { | |
2768 | err = USBD_IOERROR; | 2771 | err = USBD_IOERROR; | |
2769 | goto ret; | 2772 | goto ret; | |
2770 | } | 2773 | } | |
2771 | port = OHCI_RH_PORT_STATUS(index); | 2774 | port = OHCI_RH_PORT_STATUS(index); | |
2772 | switch(value) { | 2775 | switch(value) { | |
2773 | case UHF_PORT_ENABLE: | 2776 | case UHF_PORT_ENABLE: | |
2774 | OWRITE4(sc, port, UPS_PORT_ENABLED); | 2777 | OWRITE4(sc, port, UPS_PORT_ENABLED); | |
2775 | break; | 2778 | break; | |
2776 | case UHF_PORT_SUSPEND: | 2779 | case UHF_PORT_SUSPEND: | |
2777 | OWRITE4(sc, port, UPS_SUSPEND); | 2780 | OWRITE4(sc, port, UPS_SUSPEND); | |
2778 | break; | 2781 | break; | |
2779 | case UHF_PORT_RESET: | 2782 | case UHF_PORT_RESET: | |
2780 | DPRINTFN(5,("ohci_root_ctrl_transfer: reset port %d\n", | 2783 | DPRINTFN(5,("ohci_root_ctrl_transfer: reset port %d\n", | |
2781 | index)); | 2784 | index)); | |
2782 | OWRITE4(sc, port, UPS_RESET); | 2785 | OWRITE4(sc, port, UPS_RESET); | |
2783 | for (i = 0; i < 5; i++) { | 2786 | for (i = 0; i < 5; i++) { | |
2784 | usb_delay_ms(&sc->sc_bus, | 2787 | usb_delay_ms(&sc->sc_bus, | |
2785 | USB_PORT_ROOT_RESET_DELAY); | 2788 | USB_PORT_ROOT_RESET_DELAY); | |
2786 | if (sc->sc_dying) { | 2789 | if (sc->sc_dying) { | |
2787 | err = USBD_IOERROR; | 2790 | err = USBD_IOERROR; | |
2788 | goto ret; | 2791 | goto ret; | |
2789 | } | 2792 | } | |
2790 | if ((OREAD4(sc, port) & UPS_RESET) == 0) | 2793 | if ((OREAD4(sc, port) & UPS_RESET) == 0) | |
2791 | break; | 2794 | break; | |
2792 | } | 2795 | } | |
2793 | DPRINTFN(8,("ohci port %d reset, status = 0x%04x\n", | 2796 | DPRINTFN(8,("ohci port %d reset, status = 0x%04x\n", | |
2794 | index, OREAD4(sc, port))); | 2797 | index, OREAD4(sc, port))); | |
2795 | break; | 2798 | break; | |
2796 | case UHF_PORT_POWER: | 2799 | case UHF_PORT_POWER: | |
2797 | DPRINTFN(2,("ohci_root_ctrl_transfer: set port power " | 2800 | DPRINTFN(2,("ohci_root_ctrl_transfer: set port power " | |
2798 | "%d\n", index)); | 2801 | "%d\n", index)); | |
2799 | OWRITE4(sc, port, UPS_PORT_POWER); | 2802 | OWRITE4(sc, port, UPS_PORT_POWER); | |
2800 | break; | 2803 | break; | |
2801 | default: | 2804 | default: | |
2802 | err = USBD_IOERROR; | 2805 | err = USBD_IOERROR; | |
2803 | goto ret; | 2806 | goto ret; | |
2804 | } | 2807 | } | |
2805 | break; | 2808 | break; | |
2806 | default: | 2809 | default: | |
2807 | err = USBD_IOERROR; | 2810 | err = USBD_IOERROR; | |
2808 | goto ret; | 2811 | goto ret; | |
2809 | } | 2812 | } | |
2810 | xfer->actlen = totlen; | 2813 | xfer->actlen = totlen; | |
2811 | err = USBD_NORMAL_COMPLETION; | 2814 | err = USBD_NORMAL_COMPLETION; | |
2812 | ret: | 2815 | ret: | |
2813 | xfer->status = err; | 2816 | xfer->status = err; | |
2814 | mutex_enter(&sc->sc_lock); | 2817 | mutex_enter(&sc->sc_lock); | |
2815 | usb_transfer_complete(xfer); | 2818 | usb_transfer_complete(xfer); | |
2816 | mutex_exit(&sc->sc_lock); | 2819 | mutex_exit(&sc->sc_lock); | |
2817 | return (USBD_IN_PROGRESS); | 2820 | return (USBD_IN_PROGRESS); | |
2818 | } | 2821 | } | |
2819 | 2822 | |||
2820 | /* Abort a root control request. */ | 2823 | /* Abort a root control request. */ | |
2821 | Static void | 2824 | Static void | |
2822 | ohci_root_ctrl_abort(usbd_xfer_handle xfer) | 2825 | ohci_root_ctrl_abort(usbd_xfer_handle xfer) | |
2823 | { | 2826 | { | |
2824 | /* Nothing to do, all transfers are synchronous. */ | 2827 | /* Nothing to do, all transfers are synchronous. */ | |
2825 | } | 2828 | } | |
2826 | 2829 | |||
2827 | /* Close the root pipe. */ | 2830 | /* Close the root pipe. */ | |
2828 | Static void | 2831 | Static void | |
2829 | ohci_root_ctrl_close(usbd_pipe_handle pipe) | 2832 | ohci_root_ctrl_close(usbd_pipe_handle pipe) | |
2830 | { | 2833 | { | |
2831 | DPRINTF(("ohci_root_ctrl_close\n")); | 2834 | DPRINTF(("ohci_root_ctrl_close\n")); | |
2832 | /* Nothing to do. */ | 2835 | /* Nothing to do. */ | |
2833 | } | 2836 | } | |
2834 | 2837 | |||
2835 | Static usbd_status | 2838 | Static usbd_status | |
2836 | ohci_root_intr_transfer(usbd_xfer_handle xfer) | 2839 | ohci_root_intr_transfer(usbd_xfer_handle xfer) | |
2837 | { | 2840 | { | |
2838 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2841 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2839 | usbd_status err; | 2842 | usbd_status err; | |
2840 | 2843 | |||
2841 | /* Insert last in queue. */ | 2844 | /* Insert last in queue. */ | |
2842 | mutex_enter(&sc->sc_lock); | 2845 | mutex_enter(&sc->sc_lock); | |
2843 | err = usb_insert_transfer(xfer); | 2846 | err = usb_insert_transfer(xfer); | |
2844 | mutex_exit(&sc->sc_lock); | 2847 | mutex_exit(&sc->sc_lock); | |
2845 | if (err) | 2848 | if (err) | |
2846 | return (err); | 2849 | return (err); | |
2847 | 2850 | |||
2848 | /* Pipe isn't running, start first */ | 2851 | /* Pipe isn't running, start first */ | |
2849 | return (ohci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 2852 | return (ohci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
2850 | } | 2853 | } | |
2851 | 2854 | |||
2852 | Static usbd_status | 2855 | Static usbd_status | |
2853 | ohci_root_intr_start(usbd_xfer_handle xfer) | 2856 | ohci_root_intr_start(usbd_xfer_handle xfer) | |
2854 | { | 2857 | { | |
2855 | usbd_pipe_handle pipe = xfer->pipe; | 2858 | usbd_pipe_handle pipe = xfer->pipe; | |
2856 | ohci_softc_t *sc = pipe->device->bus->hci_private; | 2859 | ohci_softc_t *sc = pipe->device->bus->hci_private; | |
2857 | 2860 | |||
2858 | if (sc->sc_dying) | 2861 | if (sc->sc_dying) | |
2859 | return (USBD_IOERROR); | 2862 | return (USBD_IOERROR); | |
2860 | 2863 | |||
2861 | mutex_enter(&sc->sc_lock); | 2864 | mutex_enter(&sc->sc_lock); | |
2862 | KASSERT(sc->sc_intrxfer == NULL); | 2865 | KASSERT(sc->sc_intrxfer == NULL); | |
2863 | sc->sc_intrxfer = xfer; | 2866 | sc->sc_intrxfer = xfer; | |
2864 | mutex_exit(&sc->sc_lock); | 2867 | mutex_exit(&sc->sc_lock); | |
2865 | 2868 | |||
2866 | return (USBD_IN_PROGRESS); | 2869 | return (USBD_IN_PROGRESS); | |
2867 | } | 2870 | } | |
2868 | 2871 | |||
2869 | /* Abort a root interrupt request. */ | 2872 | /* Abort a root interrupt request. */ | |
2870 | Static void | 2873 | Static void | |
2871 | ohci_root_intr_abort(usbd_xfer_handle xfer) | 2874 | ohci_root_intr_abort(usbd_xfer_handle xfer) | |
2872 | { | 2875 | { | |
2873 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2876 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2874 | 2877 | |||
2875 | if (xfer->pipe->intrxfer == xfer) { | 2878 | if (xfer->pipe->intrxfer == xfer) { | |
2876 | DPRINTF(("ohci_root_intr_abort: remove\n")); | 2879 | DPRINTF(("ohci_root_intr_abort: remove\n")); | |
2877 | xfer->pipe->intrxfer = NULL; | 2880 | xfer->pipe->intrxfer = NULL; | |
2878 | } | 2881 | } | |
2879 | xfer->status = USBD_CANCELLED; | 2882 | xfer->status = USBD_CANCELLED; | |
2880 | mutex_enter(&sc->sc_lock); | 2883 | mutex_enter(&sc->sc_lock); | |
2881 | usb_transfer_complete(xfer); | 2884 | usb_transfer_complete(xfer); | |
2882 | mutex_exit(&sc->sc_lock); | 2885 | mutex_exit(&sc->sc_lock); | |
2883 | } | 2886 | } | |
2884 | 2887 | |||
2885 | /* Close the root pipe. */ | 2888 | /* Close the root pipe. */ | |
2886 | Static void | 2889 | Static void | |
2887 | ohci_root_intr_close(usbd_pipe_handle pipe) | 2890 | ohci_root_intr_close(usbd_pipe_handle pipe) | |
2888 | { | 2891 | { | |
2889 | ohci_softc_t *sc = pipe->device->bus->hci_private; | 2892 | ohci_softc_t *sc = pipe->device->bus->hci_private; | |
2890 | 2893 | |||
2891 | DPRINTF(("ohci_root_intr_close\n")); | 2894 | DPRINTF(("ohci_root_intr_close\n")); | |
2892 | 2895 | |||
2893 | sc->sc_intrxfer = NULL; | 2896 | sc->sc_intrxfer = NULL; | |
2894 | } | 2897 | } | |
2895 | 2898 | |||
2896 | /************************/ | 2899 | /************************/ | |
2897 | 2900 | |||
2898 | Static usbd_status | 2901 | Static usbd_status | |
2899 | ohci_device_ctrl_transfer(usbd_xfer_handle xfer) | 2902 | ohci_device_ctrl_transfer(usbd_xfer_handle xfer) | |
2900 | { | 2903 | { | |
2901 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2904 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2902 | usbd_status err; | 2905 | usbd_status err; | |
2903 | 2906 | |||
2904 | /* Insert last in queue. */ | 2907 | /* Insert last in queue. */ | |
2905 | mutex_enter(&sc->sc_lock); | 2908 | mutex_enter(&sc->sc_lock); | |
2906 | err = usb_insert_transfer(xfer); | 2909 | err = usb_insert_transfer(xfer); | |
2907 | mutex_exit(&sc->sc_lock); | 2910 | mutex_exit(&sc->sc_lock); | |
2908 | if (err) | 2911 | if (err) | |
2909 | return (err); | 2912 | return (err); | |
2910 | 2913 | |||
2911 | /* Pipe isn't running, start first */ | 2914 | /* Pipe isn't running, start first */ | |
2912 | return (ohci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 2915 | return (ohci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
2913 | } | 2916 | } | |
2914 | 2917 | |||
2915 | Static usbd_status | 2918 | Static usbd_status | |
2916 | ohci_device_ctrl_start(usbd_xfer_handle xfer) | 2919 | ohci_device_ctrl_start(usbd_xfer_handle xfer) | |
2917 | { | 2920 | { | |
2918 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2921 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2919 | usbd_status err; | 2922 | usbd_status err; | |
2920 | 2923 | |||
2921 | if (sc->sc_dying) | 2924 | if (sc->sc_dying) | |
2922 | return (USBD_IOERROR); | 2925 | return (USBD_IOERROR); | |
2923 | 2926 | |||
2924 | #ifdef DIAGNOSTIC | 2927 | #ifdef DIAGNOSTIC | |
2925 | if (!(xfer->rqflags & URQ_REQUEST)) { | 2928 | if (!(xfer->rqflags & URQ_REQUEST)) { | |
2926 | /* XXX panic */ | 2929 | /* XXX panic */ | |
2927 | printf("ohci_device_ctrl_transfer: not a request\n"); | 2930 | printf("ohci_device_ctrl_transfer: not a request\n"); | |
2928 | return (USBD_INVAL); | 2931 | return (USBD_INVAL); | |
2929 | } | 2932 | } | |
2930 | #endif | 2933 | #endif | |
2931 | 2934 | |||
2932 | mutex_enter(&sc->sc_lock); | 2935 | mutex_enter(&sc->sc_lock); | |
2933 | err = ohci_device_request(xfer); | 2936 | err = ohci_device_request(xfer); | |
2934 | mutex_exit(&sc->sc_lock); | 2937 | mutex_exit(&sc->sc_lock); | |
2935 | if (err) | 2938 | if (err) | |
2936 | return (err); | 2939 | return (err); | |
2937 | 2940 | |||
2938 | if (sc->sc_bus.use_polling) | 2941 | if (sc->sc_bus.use_polling) | |
2939 | ohci_waitintr(sc, xfer); | 2942 | ohci_waitintr(sc, xfer); | |
2940 | return (USBD_IN_PROGRESS); | 2943 | return (USBD_IN_PROGRESS); | |
2941 | } | 2944 | } | |
2942 | 2945 | |||
2943 | /* Abort a device control request. */ | 2946 | /* Abort a device control request. */ | |
2944 | Static void | 2947 | Static void | |
2945 | ohci_device_ctrl_abort(usbd_xfer_handle xfer) | 2948 | ohci_device_ctrl_abort(usbd_xfer_handle xfer) | |
2946 | { | 2949 | { | |
2947 | DPRINTF(("ohci_device_ctrl_abort: xfer=%p\n", xfer)); | 2950 | DPRINTF(("ohci_device_ctrl_abort: xfer=%p\n", xfer)); | |
2948 | ohci_abort_xfer(xfer, USBD_CANCELLED); | 2951 | ohci_abort_xfer(xfer, USBD_CANCELLED); | |
2949 | } | 2952 | } | |
2950 | 2953 | |||
2951 | /* Close a device control pipe. */ | 2954 | /* Close a device control pipe. */ | |
2952 | Static void | 2955 | Static void | |
2953 | ohci_device_ctrl_close(usbd_pipe_handle pipe) | 2956 | ohci_device_ctrl_close(usbd_pipe_handle pipe) | |
2954 | { | 2957 | { | |
2955 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | 2958 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | |
2956 | ohci_softc_t *sc = pipe->device->bus->hci_private; | 2959 | ohci_softc_t *sc = pipe->device->bus->hci_private; | |
2957 | 2960 | |||
2958 | DPRINTF(("ohci_device_ctrl_close: pipe=%p\n", pipe)); | 2961 | DPRINTF(("ohci_device_ctrl_close: pipe=%p\n", pipe)); | |
2959 | mutex_enter(&sc->sc_lock); | 2962 | mutex_enter(&sc->sc_lock); | |
2960 | ohci_close_pipe(pipe, sc->sc_ctrl_head); | 2963 | ohci_close_pipe(pipe, sc->sc_ctrl_head); | |
2961 | mutex_exit(&sc->sc_lock); | 2964 | mutex_exit(&sc->sc_lock); | |
2962 | ohci_free_std(sc, opipe->tail.td); | 2965 | ohci_free_std(sc, opipe->tail.td); | |
2963 | } | 2966 | } | |
2964 | 2967 | |||
2965 | /************************/ | 2968 | /************************/ | |
2966 | 2969 | |||
2967 | Static void | 2970 | Static void | |
2968 | ohci_device_clear_toggle(usbd_pipe_handle pipe) | 2971 | ohci_device_clear_toggle(usbd_pipe_handle pipe) | |
2969 | { | 2972 | { | |
2970 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | 2973 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | |
2971 | ohci_softc_t *sc = pipe->device->bus->hci_private; | 2974 | ohci_softc_t *sc = pipe->device->bus->hci_private; | |
2972 | 2975 | |||
2973 | opipe->sed->ed.ed_headp &= HTOO32(~OHCI_TOGGLECARRY); | 2976 | opipe->sed->ed.ed_headp &= HTOO32(~OHCI_TOGGLECARRY); | |
2974 | } | 2977 | } | |
2975 | 2978 | |||
2976 | Static void | 2979 | Static void | |
2977 | ohci_noop(usbd_pipe_handle pipe) | 2980 | ohci_noop(usbd_pipe_handle pipe) | |
2978 | { | 2981 | { | |
2979 | } | 2982 | } | |
2980 | 2983 | |||
2981 | Static usbd_status | 2984 | Static usbd_status | |
2982 | ohci_device_bulk_transfer(usbd_xfer_handle xfer) | 2985 | ohci_device_bulk_transfer(usbd_xfer_handle xfer) | |
2983 | { | 2986 | { | |
2984 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2987 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2985 | usbd_status err; | 2988 | usbd_status err; | |
2986 | 2989 | |||
2987 | /* Insert last in queue. */ | 2990 | /* Insert last in queue. */ | |
2988 | mutex_enter(&sc->sc_lock); | 2991 | mutex_enter(&sc->sc_lock); | |
2989 | err = usb_insert_transfer(xfer); | 2992 | err = usb_insert_transfer(xfer); | |
2990 | mutex_exit(&sc->sc_lock); | 2993 | mutex_exit(&sc->sc_lock); | |
2991 | if (err) | 2994 | if (err) | |
2992 | return (err); | 2995 | return (err); | |
2993 | 2996 | |||
2994 | /* Pipe isn't running, start first */ | 2997 | /* Pipe isn't running, start first */ | |
2995 | return (ohci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 2998 | return (ohci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
2996 | } | 2999 | } | |
2997 | 3000 | |||
2998 | Static usbd_status | 3001 | Static usbd_status | |
2999 | ohci_device_bulk_start(usbd_xfer_handle xfer) | 3002 | ohci_device_bulk_start(usbd_xfer_handle xfer) | |
3000 | { | 3003 | { | |
3001 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | 3004 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | |
3002 | usbd_device_handle dev = opipe->pipe.device; | 3005 | usbd_device_handle dev = opipe->pipe.device; | |
3003 | ohci_softc_t *sc = dev->bus->hci_private; | 3006 | ohci_softc_t *sc = dev->bus->hci_private; | |
3004 | int addr = dev->address; | 3007 | int addr = dev->address; | |
3005 | ohci_soft_td_t *data, *tail, *tdp; | 3008 | ohci_soft_td_t *data, *tail, *tdp; | |
3006 | ohci_soft_ed_t *sed; | 3009 | ohci_soft_ed_t *sed; | |
3007 | int len, isread, endpt; | 3010 | int len, isread, endpt; | |
3008 | usbd_status err; | 3011 | usbd_status err; | |
3009 | 3012 | |||
3010 | if (sc->sc_dying) | 3013 | if (sc->sc_dying) | |
3011 | return (USBD_IOERROR); | 3014 | return (USBD_IOERROR); | |
3012 | 3015 | |||
3013 | #ifdef DIAGNOSTIC | 3016 | #ifdef DIAGNOSTIC | |
3014 | if (xfer->rqflags & URQ_REQUEST) { | 3017 | if (xfer->rqflags & URQ_REQUEST) { | |
3015 | /* XXX panic */ | 3018 | /* XXX panic */ | |
3016 | printf("ohci_device_bulk_start: a request\n"); | 3019 | printf("ohci_device_bulk_start: a request\n"); | |
3017 | return (USBD_INVAL); | 3020 | return (USBD_INVAL); | |
3018 | } | 3021 | } | |
3019 | #endif | 3022 | #endif | |
3020 | 3023 | |||
3021 | mutex_enter(&sc->sc_lock); | 3024 | mutex_enter(&sc->sc_lock); | |
3022 | 3025 | |||
3023 | len = xfer->length; | 3026 | len = xfer->length; | |
3024 | endpt = xfer->pipe->endpoint->edesc->bEndpointAddress; | 3027 | endpt = xfer->pipe->endpoint->edesc->bEndpointAddress; | |
3025 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | 3028 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | |
3026 | sed = opipe->sed; | 3029 | sed = opipe->sed; | |
3027 | 3030 | |||
3028 | DPRINTFN(4,("ohci_device_bulk_start: xfer=%p len=%d isread=%d " | 3031 | DPRINTFN(4,("ohci_device_bulk_start: xfer=%p len=%d isread=%d " | |
3029 | "flags=%d endpt=%d\n", xfer, len, isread, xfer->flags, | 3032 | "flags=%d endpt=%d\n", xfer, len, isread, xfer->flags, | |
3030 | endpt)); | 3033 | endpt)); | |
3031 | 3034 | |||
3032 | opipe->u.bulk.isread = isread; | 3035 | opipe->u.bulk.isread = isread; | |
3033 | opipe->u.bulk.length = len; | 3036 | opipe->u.bulk.length = len; | |
3034 | 3037 | |||
3035 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 3038 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
3036 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3039 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3037 | /* Update device address */ | 3040 | /* Update device address */ | |
3038 | sed->ed.ed_flags = HTOO32( | 3041 | sed->ed.ed_flags = HTOO32( | |
3039 | (O32TOH(sed->ed.ed_flags) & ~OHCI_ED_ADDRMASK) | | 3042 | (O32TOH(sed->ed.ed_flags) & ~OHCI_ED_ADDRMASK) | | |
3040 | OHCI_ED_SET_FA(addr)); | 3043 | OHCI_ED_SET_FA(addr)); | |
3041 | 3044 | |||
3042 | /* Allocate a chain of new TDs (including a new tail). */ | 3045 | /* Allocate a chain of new TDs (including a new tail). */ | |
3043 | data = opipe->tail.td; | 3046 | data = opipe->tail.td; | |
3044 | err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer, | 3047 | err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer, | |
3045 | data, &tail); | 3048 | data, &tail); | |
3046 | /* We want interrupt at the end of the transfer. */ | 3049 | /* We want interrupt at the end of the transfer. */ | |
3047 | tail->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); | 3050 | tail->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); | |
3048 | tail->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); | 3051 | tail->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); | |
3049 | tail->flags |= OHCI_CALL_DONE; | 3052 | tail->flags |= OHCI_CALL_DONE; | |
3050 | tail = tail->nexttd; /* point at sentinel */ | 3053 | tail = tail->nexttd; /* point at sentinel */ | |
3051 | usb_syncmem(&tail->dma, tail->offs + offsetof(ohci_td_t, td_flags), | 3054 | usb_syncmem(&tail->dma, tail->offs + offsetof(ohci_td_t, td_flags), | |
3052 | sizeof(tail->td.td_flags), | 3055 | sizeof(tail->td.td_flags), | |
3053 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3056 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3054 | if (err) { | 3057 | if (err) { | |
3055 | mutex_exit(&sc->sc_lock); | 3058 | mutex_exit(&sc->sc_lock); | |
3056 | return (err); | 3059 | return (err); | |
3057 | } | 3060 | } | |
3058 | 3061 | |||
3059 | tail->xfer = NULL; | 3062 | tail->xfer = NULL; | |
3060 | xfer->hcpriv = data; | 3063 | xfer->hcpriv = data; | |
3061 | 3064 | |||
3062 | DPRINTFN(4,("ohci_device_bulk_start: ed_flags=0x%08x td_flags=0x%08x " | 3065 | DPRINTFN(4,("ohci_device_bulk_start: ed_flags=0x%08x td_flags=0x%08x " | |
3063 | "td_cbp=0x%08x td_be=0x%08x\n", | 3066 | "td_cbp=0x%08x td_be=0x%08x\n", | |
3064 | (int)O32TOH(sed->ed.ed_flags), | 3067 | (int)O32TOH(sed->ed.ed_flags), | |
3065 | (int)O32TOH(data->td.td_flags), | 3068 | (int)O32TOH(data->td.td_flags), | |
3066 | (int)O32TOH(data->td.td_cbp), | 3069 | (int)O32TOH(data->td.td_cbp), | |
3067 | (int)O32TOH(data->td.td_be))); | 3070 | (int)O32TOH(data->td.td_be))); | |
3068 | 3071 | |||
3069 | #ifdef OHCI_DEBUG | 3072 | #ifdef OHCI_DEBUG | |
3070 | if (ohcidebug > 5) { | 3073 | if (ohcidebug > 5) { | |
3071 | ohci_dump_ed(sc, sed); | 3074 | ohci_dump_ed(sc, sed); | |
3072 | ohci_dump_tds(sc, data); | 3075 | ohci_dump_tds(sc, data); | |
3073 | } | 3076 | } | |
3074 | #endif | 3077 | #endif | |
3075 | 3078 | |||
3076 | /* Insert ED in schedule */ | 3079 | /* Insert ED in schedule */ | |
3077 | for (tdp = data; tdp != tail; tdp = tdp->nexttd) { | 3080 | for (tdp = data; tdp != tail; tdp = tdp->nexttd) { | |
3078 | tdp->xfer = xfer; | 3081 | tdp->xfer = xfer; | |
3079 | } | 3082 | } | |
3080 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | 3083 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | |
3081 | opipe->tail.td = tail; | 3084 | opipe->tail.td = tail; | |
3082 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | 3085 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | |
3083 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 3086 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
3084 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3087 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3085 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); | 3088 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); | |
3086 | if (xfer->timeout && !sc->sc_bus.use_polling) { | 3089 | if (xfer->timeout && !sc->sc_bus.use_polling) { | |
3087 | callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout), | 3090 | callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout), | |
3088 | ohci_timeout, xfer); | 3091 | ohci_timeout, xfer); | |
3089 | } | 3092 | } | |
3090 | mutex_exit(&sc->sc_lock); | 3093 | mutex_exit(&sc->sc_lock); | |
3091 | 3094 | |||
3092 | #if 0 | 3095 | #if 0 | |
3093 | /* This goes wrong if we are too slow. */ | 3096 | /* This goes wrong if we are too slow. */ | |
3094 | if (ohcidebug > 10) { | 3097 | if (ohcidebug > 10) { | |
3095 | delay(10000); | 3098 | delay(10000); | |
3096 | DPRINTF(("ohci_device_intr_transfer: status=%x\n", | 3099 | DPRINTF(("ohci_device_intr_transfer: status=%x\n", | |
3097 | OREAD4(sc, OHCI_COMMAND_STATUS))); | 3100 | OREAD4(sc, OHCI_COMMAND_STATUS))); | |
3098 | ohci_dump_ed(sc, sed); | 3101 | ohci_dump_ed(sc, sed); | |
3099 | ohci_dump_tds(sc, data); | 3102 | ohci_dump_tds(sc, data); | |
3100 | } | 3103 | } | |
3101 | #endif | 3104 | #endif | |
3102 | 3105 | |||
3103 | return (USBD_IN_PROGRESS); | 3106 | return (USBD_IN_PROGRESS); | |
3104 | } | 3107 | } | |
3105 | 3108 | |||
3106 | Static void | 3109 | Static void | |
3107 | ohci_device_bulk_abort(usbd_xfer_handle xfer) | 3110 | ohci_device_bulk_abort(usbd_xfer_handle xfer) | |
3108 | { | 3111 | { | |
3109 | DPRINTF(("ohci_device_bulk_abort: xfer=%p\n", xfer)); | 3112 | DPRINTF(("ohci_device_bulk_abort: xfer=%p\n", xfer)); | |
3110 | ohci_abort_xfer(xfer, USBD_CANCELLED); | 3113 | ohci_abort_xfer(xfer, USBD_CANCELLED); | |
3111 | } | 3114 | } | |
3112 | 3115 | |||
3113 | /* | 3116 | /* | |
3114 | * Close a device bulk pipe. | 3117 | * Close a device bulk pipe. | |
3115 | */ | 3118 | */ | |
3116 | Static void | 3119 | Static void | |
3117 | ohci_device_bulk_close(usbd_pipe_handle pipe) | 3120 | ohci_device_bulk_close(usbd_pipe_handle pipe) | |
3118 | { | 3121 | { | |
3119 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | 3122 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | |
3120 | ohci_softc_t *sc = pipe->device->bus->hci_private; | 3123 | ohci_softc_t *sc = pipe->device->bus->hci_private; | |
3121 | 3124 | |||
3122 | DPRINTF(("ohci_device_bulk_close: pipe=%p\n", pipe)); | 3125 | DPRINTF(("ohci_device_bulk_close: pipe=%p\n", pipe)); | |
3123 | mutex_enter(&sc->sc_lock); | 3126 | mutex_enter(&sc->sc_lock); | |
3124 | ohci_close_pipe(pipe, sc->sc_bulk_head); | 3127 | ohci_close_pipe(pipe, sc->sc_bulk_head); | |
3125 | mutex_exit(&sc->sc_lock); | 3128 | mutex_exit(&sc->sc_lock); | |
3126 | ohci_free_std(sc, opipe->tail.td); | 3129 | ohci_free_std(sc, opipe->tail.td); | |
3127 | } | 3130 | } | |
3128 | 3131 | |||
3129 | /************************/ | 3132 | /************************/ | |
3130 | 3133 | |||
3131 | Static usbd_status | 3134 | Static usbd_status | |
3132 | ohci_device_intr_transfer(usbd_xfer_handle xfer) | 3135 | ohci_device_intr_transfer(usbd_xfer_handle xfer) | |
3133 | { | 3136 | { | |
3134 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 3137 | ohci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
3135 | usbd_status err; | 3138 | usbd_status err; | |
3136 | 3139 | |||
3137 | /* Insert last in queue. */ | 3140 | /* Insert last in queue. */ | |
3138 | mutex_enter(&sc->sc_lock); | 3141 | mutex_enter(&sc->sc_lock); | |
3139 | err = usb_insert_transfer(xfer); | 3142 | err = usb_insert_transfer(xfer); | |
3140 | mutex_exit(&sc->sc_lock); | 3143 | mutex_exit(&sc->sc_lock); | |
3141 | if (err) | 3144 | if (err) | |
3142 | return (err); | 3145 | return (err); | |
3143 | 3146 | |||
3144 | /* Pipe isn't running, start first */ | 3147 | /* Pipe isn't running, start first */ | |
3145 | return (ohci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 3148 | return (ohci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
3146 | } | 3149 | } | |
3147 | 3150 | |||
3148 | Static usbd_status | 3151 | Static usbd_status | |
3149 | ohci_device_intr_start(usbd_xfer_handle xfer) | 3152 | ohci_device_intr_start(usbd_xfer_handle xfer) | |
3150 | { | 3153 | { | |
3151 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | 3154 | struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe; | |
3152 | usbd_device_handle dev = opipe->pipe.device; | 3155 | usbd_device_handle dev = opipe->pipe.device; | |
3153 | ohci_softc_t *sc = dev->bus->hci_private; | 3156 | ohci_softc_t *sc = dev->bus->hci_private; | |
3154 | ohci_soft_ed_t *sed = opipe->sed; | 3157 | ohci_soft_ed_t *sed = opipe->sed; | |
3155 | ohci_soft_td_t *data, *tail; | 3158 | ohci_soft_td_t *data, *tail; | |
3156 | int len, isread, endpt; | 3159 | int len, isread, endpt; | |
3157 | 3160 | |||
3158 | if (sc->sc_dying) | 3161 | if (sc->sc_dying) | |
3159 | return (USBD_IOERROR); | 3162 | return (USBD_IOERROR); | |
3160 | 3163 | |||
3161 | DPRINTFN(3, ("ohci_device_intr_transfer: xfer=%p len=%d " | 3164 | DPRINTFN(3, ("ohci_device_intr_transfer: xfer=%p len=%d " | |
3162 | "flags=%d priv=%p\n", | 3165 | "flags=%d priv=%p\n", | |
3163 | xfer, xfer->length, xfer->flags, xfer->priv)); | 3166 | xfer, xfer->length, xfer->flags, xfer->priv)); | |
3164 | 3167 | |||
3165 | #ifdef DIAGNOSTIC | 3168 | #ifdef DIAGNOSTIC | |
3166 | if (xfer->rqflags & URQ_REQUEST) | 3169 | if (xfer->rqflags & URQ_REQUEST) | |
3167 | panic("ohci_device_intr_transfer: a request"); | 3170 | panic("ohci_device_intr_transfer: a request"); | |
3168 | #endif | 3171 | #endif | |
3169 | 3172 | |||
3170 | len = xfer->length; | 3173 | len = xfer->length; | |
3171 | endpt = xfer->pipe->endpoint->edesc->bEndpointAddress; | 3174 | endpt = xfer->pipe->endpoint->edesc->bEndpointAddress; | |
3172 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | 3175 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | |
3173 | 3176 | |||
3174 | data = opipe->tail.td; | 3177 | data = opipe->tail.td; | |
3175 | tail = ohci_alloc_std(sc); | 3178 | tail = ohci_alloc_std(sc); | |
3176 | if (tail == NULL) | 3179 | if (tail == NULL) | |
3177 | return (USBD_NOMEM); | 3180 | return (USBD_NOMEM); | |
3178 | tail->xfer = NULL; | 3181 | tail->xfer = NULL; | |
3179 | 3182 | |||
3180 | data->td.td_flags = HTOO32( | 3183 | data->td.td_flags = HTOO32( | |
3181 | isread ? OHCI_TD_IN : OHCI_TD_OUT | | 3184 | isread ? OHCI_TD_IN : OHCI_TD_OUT | | |
3182 | OHCI_TD_NOCC | | 3185 | OHCI_TD_NOCC | | |
3183 | OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY); | 3186 | OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY); | |
3184 | if (xfer->flags & USBD_SHORT_XFER_OK) | 3187 | if (xfer->flags & USBD_SHORT_XFER_OK) | |
3185 | data->td.td_flags |= HTOO32(OHCI_TD_R); | 3188 | data->td.td_flags |= HTOO32(OHCI_TD_R); | |
3186 | data->td.td_cbp = HTOO32(DMAADDR(&xfer->dmabuf, 0)); | 3189 | data->td.td_cbp = HTOO32(DMAADDR(&xfer->dmabuf, 0)); | |
3187 | data->nexttd = tail; | 3190 | data->nexttd = tail; | |
3188 | data->td.td_nexttd = HTOO32(tail->physaddr); | 3191 | data->td.td_nexttd = HTOO32(tail->physaddr); | |
3189 | data->td.td_be = HTOO32(O32TOH(data->td.td_cbp) + len - 1); | 3192 | data->td.td_be = HTOO32(O32TOH(data->td.td_cbp) + len - 1); | |
3190 | data->len = len; | 3193 | data->len = len; | |
3191 | data->xfer = xfer; | 3194 | data->xfer = xfer; | |
3192 | data->flags = OHCI_CALL_DONE | OHCI_ADD_LEN; | 3195 | data->flags = OHCI_CALL_DONE | OHCI_ADD_LEN; | |
3193 | usb_syncmem(&data->dma, data->offs, sizeof(data->td), | 3196 | usb_syncmem(&data->dma, data->offs, sizeof(data->td), | |
3194 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3197 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3195 | xfer->hcpriv = data; | 3198 | xfer->hcpriv = data; | |
3196 | 3199 | |||
3197 | #ifdef OHCI_DEBUG | 3200 | #ifdef OHCI_DEBUG | |
3198 | if (ohcidebug > 5) { | 3201 | if (ohcidebug > 5) { | |
3199 | DPRINTF(("ohci_device_intr_transfer:\n")); | 3202 | DPRINTF(("ohci_device_intr_transfer:\n")); | |
3200 | ohci_dump_ed(sc, sed); | 3203 | ohci_dump_ed(sc, sed); | |
3201 | ohci_dump_tds(sc, data); | 3204 | ohci_dump_tds(sc, data); | |
3202 | } | 3205 | } | |
3203 | #endif | 3206 | #endif | |
3204 | 3207 | |||
3205 | /* Insert ED in schedule */ | 3208 | /* Insert ED in schedule */ | |
3206 | mutex_enter(&sc->sc_lock); | 3209 | mutex_enter(&sc->sc_lock); | |
3207 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 3210 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
3208 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3211 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3209 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | 3212 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | |
3210 | opipe->tail.td = tail; | 3213 | opipe->tail.td = tail; | |
3211 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | 3214 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | |
3212 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | 3215 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | |
3213 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3216 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3214 | 3217 | |||
3215 | #if 0 | 3218 | #if 0 | |
3216 | /* | 3219 | /* | |
3217 | * This goes horribly wrong, printing thousands of descriptors, | 3220 | * This goes horribly wrong, printing thousands of descriptors, | |
3218 | * because false references are followed due to the fact that the | 3221 | * because false references are followed due to the fact that the | |
3219 | * TD is gone. | 3222 | * TD is gone. | |
3220 | */ | 3223 | */ | |
3221 | if (ohcidebug > 5) { | 3224 | if (ohcidebug > 5) { | |
3222 | usb_delay_ms(&sc->sc_bus, 5); | 3225 | usb_delay_ms(&sc->sc_bus, 5); | |
3223 | DPRINTF(("ohci_device_intr_transfer: status=%x\n", | 3226 | DPRINTF(("ohci_device_intr_transfer: status=%x\n", | |
3224 | OREAD4(sc, OHCI_COMMAND_STATUS))); | 3227 | OREAD4(sc, OHCI_COMMAND_STATUS))); | |
3225 | ohci_dump_ed(sc, sed); | 3228 | ohci_dump_ed(sc, sed); | |
3226 | ohci_dump_tds(sc, data); | 3229 | ohci_dump_tds(sc, data); | |
3227 | } | 3230 | } | |
3228 | #endif | 3231 | #endif | |
3229 | mutex_exit(&sc->sc_lock); | 3232 | mutex_exit(&sc->sc_lock); | |
3230 | 3233 | |||
3231 | return (USBD_IN_PROGRESS); | 3234 | return (USBD_IN_PROGRESS); | |
3232 | } | 3235 | } | |
3233 | 3236 | |||
3234 | /* Abort a device control request. */ | 3237 | /* Abort a device control request. */ | |
3235 | Static void | 3238 | Static void | |
3236 | ohci_device_intr_abort(usbd_xfer_handle xfer) | 3239 | ohci_device_intr_abort(usbd_xfer_handle xfer) | |
3237 | { | 3240 | { | |
3238 | if (xfer->pipe->intrxfer == xfer) { | 3241 | if (xfer->pipe->intrxfer == xfer) { | |
3239 | DPRINTF(("ohci_device_intr_abort: remove\n")); | 3242 | DPRINTF(("ohci_device_intr_abort: remove\n")); | |
3240 | xfer->pipe->intrxfer = NULL; | 3243 | xfer->pipe->intrxfer = NULL; | |
3241 | } | 3244 | } | |
3242 | ohci_abort_xfer(xfer, USBD_CANCELLED); | 3245 | ohci_abort_xfer(xfer, USBD_CANCELLED); | |
3243 | } | 3246 | } | |
3244 | 3247 | |||
3245 | /* Close a device interrupt pipe. */ | 3248 | /* Close a device interrupt pipe. */ | |
3246 | Static void | 3249 | Static void | |
3247 | ohci_device_intr_close(usbd_pipe_handle pipe) | 3250 | ohci_device_intr_close(usbd_pipe_handle pipe) | |
3248 | { | 3251 | { | |
3249 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | 3252 | struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; | |
3250 | ohci_softc_t *sc = pipe->device->bus->hci_private; | 3253 | ohci_softc_t *sc = pipe->device->bus->hci_private; | |
3251 | int nslots = opipe->u.intr.nslots; | 3254 | int nslots = opipe->u.intr.nslots; | |
3252 | int pos = opipe->u.intr.pos; | 3255 | int pos = opipe->u.intr.pos; | |
3253 | int j; | 3256 | int j; | |
3254 | ohci_soft_ed_t *p, *sed = opipe->sed; | 3257 | ohci_soft_ed_t *p, *sed = opipe->sed; | |
3255 | 3258 | |||
3256 | DPRINTFN(1,("ohci_device_intr_close: pipe=%p nslots=%d pos=%d\n", | 3259 | DPRINTFN(1,("ohci_device_intr_close: pipe=%p nslots=%d pos=%d\n", | |
3257 | pipe, nslots, pos)); | 3260 | pipe, nslots, pos)); | |
3258 | mutex_enter(&sc->sc_lock); | 3261 | mutex_enter(&sc->sc_lock); | |
3259 | usb_syncmem(&sed->dma, sed->offs, | 3262 | usb_syncmem(&sed->dma, sed->offs, | |
3260 | sizeof(sed->ed), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 3263 | sizeof(sed->ed), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
3261 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | 3264 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | |
3262 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | 3265 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | |
3263 | sizeof(sed->ed.ed_flags), | 3266 | sizeof(sed->ed.ed_flags), | |
3264 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 3267 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
3265 | if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) != | 3268 | if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) != | |
3266 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) | 3269 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) | |
3267 | usb_delay_ms(&sc->sc_bus, 2); | 3270 | usb_delay_ms(&sc->sc_bus, 2); | |
3268 | 3271 | |||
3269 | for (p = sc->sc_eds[pos]; p && p->next != sed; p = p->next) | 3272 | for (p = sc->sc_eds[pos]; p && p->next != sed; p = p->next) | |
3270 | continue; | 3273 | continue; | |
3271 | #ifdef DIAGNOSTIC | 3274 | #ifdef DIAGNOSTIC | |
3272 | if (p == NULL) | 3275 | if (p == NULL) | |
3273 | panic("ohci_device_intr_close: ED not found"); | 3276 | panic("ohci_device_intr_close: ED not found"); |
--- src/sys/dev/usb/uhci.c 2011/12/06 05:40:02 1.240.6.4
+++ src/sys/dev/usb/uhci.c 2011/12/08 02:51:08 1.240.6.5
@@ -1,2257 +1,2257 @@ | @@ -1,2257 +1,2257 @@ | |||
1 | /* $NetBSD: uhci.c,v 1.240.6.4 2011/12/06 05:40:02 mrg Exp $ */ | 1 | /* $NetBSD: uhci.c,v 1.240.6.5 2011/12/08 02:51:08 mrg 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, 2011 The NetBSD Foundation, Inc. | 5 | * Copyright (c) 1998, 2004, 2011 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, Jared D. McNeill (jmcneill@invisible.ca) | 10 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) | |
11 | * and Matthew R. Green. | 11 | * and Matthew R. Green. | |
12 | * | 12 | * | |
13 | * Redistribution and use in source and binary forms, with or without | 13 | * Redistribution and use in source and binary forms, with or without | |
14 | * modification, are permitted provided that the following conditions | 14 | * modification, are permitted provided that the following conditions | |
15 | * are met: | 15 | * are met: | |
16 | * 1. Redistributions of source code must retain the above copyright | 16 | * 1. Redistributions of source code must retain the above copyright | |
17 | * notice, this list of conditions and the following disclaimer. | 17 | * notice, this list of conditions and the following disclaimer. | |
18 | * 2. Redistributions in binary form must reproduce the above copyright | 18 | * 2. Redistributions in binary form must reproduce the above copyright | |
19 | * notice, this list of conditions and the following disclaimer in the | 19 | * notice, this list of conditions and the following disclaimer in the | |
20 | * documentation and/or other materials provided with the distribution. | 20 | * documentation and/or other materials provided with the distribution. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 22 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
24 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 24 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
25 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 25 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
32 | * POSSIBILITY OF SUCH DAMAGE. | 32 | * POSSIBILITY OF SUCH DAMAGE. | |
33 | */ | 33 | */ | |
34 | 34 | |||
35 | /* | 35 | /* | |
36 | * USB Universal Host Controller driver. | 36 | * USB Universal Host Controller driver. | |
37 | * Handles e.g. PIIX3 and PIIX4. | 37 | * Handles e.g. PIIX3 and PIIX4. | |
38 | * | 38 | * | |
39 | * UHCI spec: http://www.intel.com/technology/usb/spec.htm | 39 | * UHCI spec: http://www.intel.com/technology/usb/spec.htm | |
40 | * USB spec: http://www.usb.org/developers/docs/ | 40 | * USB spec: http://www.usb.org/developers/docs/ | |
41 | * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf | 41 | * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf | |
42 | * ftp://download.intel.com/design/intarch/datashts/29056201.pdf | 42 | * ftp://download.intel.com/design/intarch/datashts/29056201.pdf | |
43 | */ | 43 | */ | |
44 | 44 | |||
45 | #include <sys/cdefs.h> | 45 | #include <sys/cdefs.h> | |
46 | __KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.240.6.4 2011/12/06 05:40:02 mrg Exp $"); | 46 | __KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.240.6.5 2011/12/08 02:51:08 mrg Exp $"); | |
47 | 47 | |||
48 | #include "opt_usb.h" | 48 | #include "opt_usb.h" | |
49 | 49 | |||
50 | #include <sys/param.h> | 50 | #include <sys/param.h> | |
51 | #include <sys/systm.h> | 51 | #include <sys/systm.h> | |
52 | #include <sys/kernel.h> | 52 | #include <sys/kernel.h> | |
53 | #include <sys/kmem.h> | 53 | #include <sys/kmem.h> | |
54 | #include <sys/device.h> | 54 | #include <sys/device.h> | |
55 | #include <sys/select.h> | 55 | #include <sys/select.h> | |
56 | #include <sys/extent.h> | 56 | #include <sys/extent.h> | |
57 | #include <sys/proc.h> | 57 | #include <sys/proc.h> | |
58 | #include <sys/queue.h> | 58 | #include <sys/queue.h> | |
59 | #include <sys/bus.h> | 59 | #include <sys/bus.h> | |
60 | 60 | |||
61 | #include <machine/endian.h> | 61 | #include <machine/endian.h> | |
62 | 62 | |||
63 | #include <dev/usb/usb.h> | 63 | #include <dev/usb/usb.h> | |
64 | #include <dev/usb/usbdi.h> | 64 | #include <dev/usb/usbdi.h> | |
65 | #include <dev/usb/usbdivar.h> | 65 | #include <dev/usb/usbdivar.h> | |
66 | #include <dev/usb/usb_mem.h> | 66 | #include <dev/usb/usb_mem.h> | |
67 | #include <dev/usb/usb_quirks.h> | 67 | #include <dev/usb/usb_quirks.h> | |
68 | 68 | |||
69 | #include <dev/usb/uhcireg.h> | 69 | #include <dev/usb/uhcireg.h> | |
70 | #include <dev/usb/uhcivar.h> | 70 | #include <dev/usb/uhcivar.h> | |
71 | #include <dev/usb/usbroothub_subr.h> | 71 | #include <dev/usb/usbroothub_subr.h> | |
72 | 72 | |||
73 | /* Use bandwidth reclamation for control transfers. Some devices choke on it. */ | 73 | /* Use bandwidth reclamation for control transfers. Some devices choke on it. */ | |
74 | /*#define UHCI_CTL_LOOP */ | 74 | /*#define UHCI_CTL_LOOP */ | |
75 | 75 | |||
76 | 76 | |||
77 | 77 | |||
78 | #ifdef UHCI_DEBUG | 78 | #ifdef UHCI_DEBUG | |
79 | uhci_softc_t *thesc; | 79 | uhci_softc_t *thesc; | |
80 | #define DPRINTF(x) if (uhcidebug) printf x | 80 | #define DPRINTF(x) if (uhcidebug) printf x | |
81 | #define DPRINTFN(n,x) if (uhcidebug>(n)) printf x | 81 | #define DPRINTFN(n,x) if (uhcidebug>(n)) printf x | |
82 | int uhcidebug = 0; | 82 | int uhcidebug = 0; | |
83 | int uhcinoloop = 0; | 83 | int uhcinoloop = 0; | |
84 | #else | 84 | #else | |
85 | #define DPRINTF(x) | 85 | #define DPRINTF(x) | |
86 | #define DPRINTFN(n,x) | 86 | #define DPRINTFN(n,x) | |
87 | #endif | 87 | #endif | |
88 | 88 | |||
89 | /* | 89 | /* | |
90 | * The UHCI controller is little endian, so on big endian machines | 90 | * The UHCI controller is little endian, so on big endian machines | |
91 | * the data stored in memory needs to be swapped. | 91 | * the data stored in memory needs to be swapped. | |
92 | */ | 92 | */ | |
93 | 93 | |||
94 | struct uhci_pipe { | 94 | struct uhci_pipe { | |
95 | struct usbd_pipe pipe; | 95 | struct usbd_pipe pipe; | |
96 | int nexttoggle; | 96 | int nexttoggle; | |
97 | 97 | |||
98 | u_char aborting; | 98 | u_char aborting; | |
99 | usbd_xfer_handle abortstart, abortend; | 99 | usbd_xfer_handle abortstart, abortend; | |
100 | 100 | |||
101 | /* Info needed for different pipe kinds. */ | 101 | /* Info needed for different pipe kinds. */ | |
102 | union { | 102 | union { | |
103 | /* Control pipe */ | 103 | /* Control pipe */ | |
104 | struct { | 104 | struct { | |
105 | uhci_soft_qh_t *sqh; | 105 | uhci_soft_qh_t *sqh; | |
106 | usb_dma_t reqdma; | 106 | usb_dma_t reqdma; | |
107 | uhci_soft_td_t *setup, *stat; | 107 | uhci_soft_td_t *setup, *stat; | |
108 | u_int length; | 108 | u_int length; | |
109 | } ctl; | 109 | } ctl; | |
110 | /* Interrupt pipe */ | 110 | /* Interrupt pipe */ | |
111 | struct { | 111 | struct { | |
112 | int npoll; | 112 | int npoll; | |
113 | int isread; | 113 | int isread; | |
114 | uhci_soft_qh_t **qhs; | 114 | uhci_soft_qh_t **qhs; | |
115 | } intr; | 115 | } intr; | |
116 | /* Bulk pipe */ | 116 | /* Bulk pipe */ | |
117 | struct { | 117 | struct { | |
118 | uhci_soft_qh_t *sqh; | 118 | uhci_soft_qh_t *sqh; | |
119 | u_int length; | 119 | u_int length; | |
120 | int isread; | 120 | int isread; | |
121 | } bulk; | 121 | } bulk; | |
122 | /* Iso pipe */ | 122 | /* Iso pipe */ | |
123 | struct iso { | 123 | struct iso { | |
124 | uhci_soft_td_t **stds; | 124 | uhci_soft_td_t **stds; | |
125 | int next, inuse; | 125 | int next, inuse; | |
126 | } iso; | 126 | } iso; | |
127 | } u; | 127 | } u; | |
128 | }; | 128 | }; | |
129 | 129 | |||
130 | Static void uhci_globalreset(uhci_softc_t *); | 130 | Static void uhci_globalreset(uhci_softc_t *); | |
131 | Static usbd_status uhci_portreset(uhci_softc_t*, int); | 131 | Static usbd_status uhci_portreset(uhci_softc_t*, int); | |
132 | Static void uhci_reset(uhci_softc_t *); | 132 | Static void uhci_reset(uhci_softc_t *); | |
133 | Static usbd_status uhci_run(uhci_softc_t *, int run); | 133 | Static usbd_status uhci_run(uhci_softc_t *, int run); | |
134 | Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *); | 134 | Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *); | |
135 | Static void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *); | 135 | Static void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *); | |
136 | Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *); | 136 | Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *); | |
137 | Static void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *); | 137 | Static void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *); | |
138 | #if 0 | 138 | #if 0 | |
139 | Static void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *, | 139 | Static void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *, | |
140 | uhci_intr_info_t *); | 140 | uhci_intr_info_t *); | |
141 | Static void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *); | 141 | Static void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *); | |
142 | #endif | 142 | #endif | |
143 | 143 | |||
144 | Static void uhci_free_std_chain(uhci_softc_t *, | 144 | Static void uhci_free_std_chain(uhci_softc_t *, | |
145 | uhci_soft_td_t *, uhci_soft_td_t *); | 145 | uhci_soft_td_t *, uhci_soft_td_t *); | |
146 | Static usbd_status uhci_alloc_std_chain(struct uhci_pipe *, | 146 | Static usbd_status uhci_alloc_std_chain(struct uhci_pipe *, | |
147 | uhci_softc_t *, int, int, u_int16_t, usb_dma_t *, | 147 | uhci_softc_t *, int, int, u_int16_t, usb_dma_t *, | |
148 | uhci_soft_td_t **, uhci_soft_td_t **); | 148 | uhci_soft_td_t **, uhci_soft_td_t **); | |
149 | Static void uhci_poll_hub(void *); | 149 | Static void uhci_poll_hub(void *); | |
150 | Static void uhci_waitintr(uhci_softc_t *, usbd_xfer_handle); | 150 | Static void uhci_waitintr(uhci_softc_t *, usbd_xfer_handle); | |
151 | Static void uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *); | 151 | Static void uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *); | |
152 | Static void uhci_idone(uhci_intr_info_t *); | 152 | Static void uhci_idone(uhci_intr_info_t *); | |
153 | 153 | |||
154 | Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status); | 154 | Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status); | |
155 | 155 | |||
156 | Static void uhci_timeout(void *); | 156 | Static void uhci_timeout(void *); | |
157 | Static void uhci_timeout_task(void *); | 157 | Static void uhci_timeout_task(void *); | |
158 | Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *); | 158 | Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *); | |
159 | Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *); | 159 | Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *); | |
160 | Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *); | 160 | Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *); | |
161 | Static void uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *); | 161 | Static void uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *); | |
162 | Static void uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *); | 162 | Static void uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *); | |
163 | Static void uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *); | 163 | Static void uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *); | |
164 | Static void uhci_add_loop(uhci_softc_t *sc); | 164 | Static void uhci_add_loop(uhci_softc_t *sc); | |
165 | Static void uhci_rem_loop(uhci_softc_t *sc); | 165 | Static void uhci_rem_loop(uhci_softc_t *sc); | |
166 | 166 | |||
167 | Static usbd_status uhci_setup_isoc(usbd_pipe_handle pipe); | 167 | Static usbd_status uhci_setup_isoc(usbd_pipe_handle pipe); | |
168 | Static void uhci_device_isoc_enter(usbd_xfer_handle); | 168 | Static void uhci_device_isoc_enter(usbd_xfer_handle); | |
169 | 169 | |||
170 | Static usbd_status uhci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); | 170 | Static usbd_status uhci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); | |
171 | Static void uhci_freem(struct usbd_bus *, usb_dma_t *); | 171 | Static void uhci_freem(struct usbd_bus *, usb_dma_t *); | |
172 | 172 | |||
173 | Static usbd_xfer_handle uhci_allocx(struct usbd_bus *); | 173 | Static usbd_xfer_handle uhci_allocx(struct usbd_bus *); | |
174 | Static void uhci_freex(struct usbd_bus *, usbd_xfer_handle); | 174 | Static void uhci_freex(struct usbd_bus *, usbd_xfer_handle); | |
175 | Static void uhci_get_locks(struct usbd_bus *, kmutex_t **, | 175 | Static void uhci_get_locks(struct usbd_bus *, kmutex_t **, | |
176 | kmutex_t **); | 176 | kmutex_t **); | |
177 | 177 | |||
178 | Static usbd_status uhci_device_ctrl_transfer(usbd_xfer_handle); | 178 | Static usbd_status uhci_device_ctrl_transfer(usbd_xfer_handle); | |
179 | Static usbd_status uhci_device_ctrl_start(usbd_xfer_handle); | 179 | Static usbd_status uhci_device_ctrl_start(usbd_xfer_handle); | |
180 | Static void uhci_device_ctrl_abort(usbd_xfer_handle); | 180 | Static void uhci_device_ctrl_abort(usbd_xfer_handle); | |
181 | Static void uhci_device_ctrl_close(usbd_pipe_handle); | 181 | Static void uhci_device_ctrl_close(usbd_pipe_handle); | |
182 | Static void uhci_device_ctrl_done(usbd_xfer_handle); | 182 | Static void uhci_device_ctrl_done(usbd_xfer_handle); | |
183 | 183 | |||
184 | Static usbd_status uhci_device_intr_transfer(usbd_xfer_handle); | 184 | Static usbd_status uhci_device_intr_transfer(usbd_xfer_handle); | |
185 | Static usbd_status uhci_device_intr_start(usbd_xfer_handle); | 185 | Static usbd_status uhci_device_intr_start(usbd_xfer_handle); | |
186 | Static void uhci_device_intr_abort(usbd_xfer_handle); | 186 | Static void uhci_device_intr_abort(usbd_xfer_handle); | |
187 | Static void uhci_device_intr_close(usbd_pipe_handle); | 187 | Static void uhci_device_intr_close(usbd_pipe_handle); | |
188 | Static void uhci_device_intr_done(usbd_xfer_handle); | 188 | Static void uhci_device_intr_done(usbd_xfer_handle); | |
189 | 189 | |||
190 | Static usbd_status uhci_device_bulk_transfer(usbd_xfer_handle); | 190 | Static usbd_status uhci_device_bulk_transfer(usbd_xfer_handle); | |
191 | Static usbd_status uhci_device_bulk_start(usbd_xfer_handle); | 191 | Static usbd_status uhci_device_bulk_start(usbd_xfer_handle); | |
192 | Static void uhci_device_bulk_abort(usbd_xfer_handle); | 192 | Static void uhci_device_bulk_abort(usbd_xfer_handle); | |
193 | Static void uhci_device_bulk_close(usbd_pipe_handle); | 193 | Static void uhci_device_bulk_close(usbd_pipe_handle); | |
194 | Static void uhci_device_bulk_done(usbd_xfer_handle); | 194 | Static void uhci_device_bulk_done(usbd_xfer_handle); | |
195 | 195 | |||
196 | Static usbd_status uhci_device_isoc_transfer(usbd_xfer_handle); | 196 | Static usbd_status uhci_device_isoc_transfer(usbd_xfer_handle); | |
197 | Static usbd_status uhci_device_isoc_start(usbd_xfer_handle); | 197 | Static usbd_status uhci_device_isoc_start(usbd_xfer_handle); | |
198 | Static void uhci_device_isoc_abort(usbd_xfer_handle); | 198 | Static void uhci_device_isoc_abort(usbd_xfer_handle); | |
199 | Static void uhci_device_isoc_close(usbd_pipe_handle); | 199 | Static void uhci_device_isoc_close(usbd_pipe_handle); | |
200 | Static void uhci_device_isoc_done(usbd_xfer_handle); | 200 | Static void uhci_device_isoc_done(usbd_xfer_handle); | |
201 | 201 | |||
202 | Static usbd_status uhci_root_ctrl_transfer(usbd_xfer_handle); | 202 | Static usbd_status uhci_root_ctrl_transfer(usbd_xfer_handle); | |
203 | Static usbd_status uhci_root_ctrl_start(usbd_xfer_handle); | 203 | Static usbd_status uhci_root_ctrl_start(usbd_xfer_handle); | |
204 | Static void uhci_root_ctrl_abort(usbd_xfer_handle); | 204 | Static void uhci_root_ctrl_abort(usbd_xfer_handle); | |
205 | Static void uhci_root_ctrl_close(usbd_pipe_handle); | 205 | Static void uhci_root_ctrl_close(usbd_pipe_handle); | |
206 | Static void uhci_root_ctrl_done(usbd_xfer_handle); | 206 | Static void uhci_root_ctrl_done(usbd_xfer_handle); | |
207 | 207 | |||
208 | Static usbd_status uhci_root_intr_transfer(usbd_xfer_handle); | 208 | Static usbd_status uhci_root_intr_transfer(usbd_xfer_handle); | |
209 | Static usbd_status uhci_root_intr_start(usbd_xfer_handle); | 209 | Static usbd_status uhci_root_intr_start(usbd_xfer_handle); | |
210 | Static void uhci_root_intr_abort(usbd_xfer_handle); | 210 | Static void uhci_root_intr_abort(usbd_xfer_handle); | |
211 | Static void uhci_root_intr_close(usbd_pipe_handle); | 211 | Static void uhci_root_intr_close(usbd_pipe_handle); | |
212 | Static void uhci_root_intr_done(usbd_xfer_handle); | 212 | Static void uhci_root_intr_done(usbd_xfer_handle); | |
213 | 213 | |||
214 | Static usbd_status uhci_open(usbd_pipe_handle); | 214 | Static usbd_status uhci_open(usbd_pipe_handle); | |
215 | Static void uhci_poll(struct usbd_bus *); | 215 | Static void uhci_poll(struct usbd_bus *); | |
216 | Static void uhci_softintr(void *); | 216 | Static void uhci_softintr(void *); | |
217 | 217 | |||
218 | Static usbd_status uhci_device_request(usbd_xfer_handle xfer); | 218 | Static usbd_status uhci_device_request(usbd_xfer_handle xfer); | |
219 | 219 | |||
220 | Static void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *); | 220 | Static void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *); | |
221 | Static void uhci_remove_intr(uhci_softc_t *, uhci_soft_qh_t *); | 221 | Static void uhci_remove_intr(uhci_softc_t *, uhci_soft_qh_t *); | |
222 | Static usbd_status uhci_device_setintr(uhci_softc_t *sc, | 222 | Static usbd_status uhci_device_setintr(uhci_softc_t *sc, | |
223 | struct uhci_pipe *pipe, int ival); | 223 | struct uhci_pipe *pipe, int ival); | |
224 | 224 | |||
225 | Static void uhci_device_clear_toggle(usbd_pipe_handle pipe); | 225 | Static void uhci_device_clear_toggle(usbd_pipe_handle pipe); | |
226 | Static void uhci_noop(usbd_pipe_handle pipe); | 226 | Static void uhci_noop(usbd_pipe_handle pipe); | |
227 | 227 | |||
228 | static inline uhci_soft_qh_t *uhci_find_prev_qh(uhci_soft_qh_t *, | 228 | static inline uhci_soft_qh_t *uhci_find_prev_qh(uhci_soft_qh_t *, | |
229 | uhci_soft_qh_t *); | 229 | uhci_soft_qh_t *); | |
230 | 230 | |||
231 | #ifdef UHCI_DEBUG | 231 | #ifdef UHCI_DEBUG | |
232 | Static void uhci_dump_all(uhci_softc_t *); | 232 | Static void uhci_dump_all(uhci_softc_t *); | |
233 | Static void uhci_dumpregs(uhci_softc_t *); | 233 | Static void uhci_dumpregs(uhci_softc_t *); | |
234 | Static void uhci_dump_qhs(uhci_soft_qh_t *); | 234 | Static void uhci_dump_qhs(uhci_soft_qh_t *); | |
235 | Static void uhci_dump_qh(uhci_soft_qh_t *); | 235 | Static void uhci_dump_qh(uhci_soft_qh_t *); | |
236 | Static void uhci_dump_tds(uhci_soft_td_t *); | 236 | Static void uhci_dump_tds(uhci_soft_td_t *); | |
237 | Static void uhci_dump_td(uhci_soft_td_t *); | 237 | Static void uhci_dump_td(uhci_soft_td_t *); | |
238 | Static void uhci_dump_ii(uhci_intr_info_t *ii); | 238 | Static void uhci_dump_ii(uhci_intr_info_t *ii); | |
239 | void uhci_dump(void); | 239 | void uhci_dump(void); | |
240 | #endif | 240 | #endif | |
241 | 241 | |||
242 | #define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ | 242 | #define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ | |
243 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) | 243 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) | |
244 | #define UWRITE1(sc, r, x) \ | 244 | #define UWRITE1(sc, r, x) \ | |
245 | do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \ | 245 | do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \ | |
246 | } while (/*CONSTCOND*/0) | 246 | } while (/*CONSTCOND*/0) | |
247 | #define UWRITE2(sc, r, x) \ | 247 | #define UWRITE2(sc, r, x) \ | |
248 | do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \ | 248 | do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \ | |
249 | } while (/*CONSTCOND*/0) | 249 | } while (/*CONSTCOND*/0) | |
250 | #define UWRITE4(sc, r, x) \ | 250 | #define UWRITE4(sc, r, x) \ | |
251 | do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \ | 251 | do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \ | |
252 | } while (/*CONSTCOND*/0) | 252 | } while (/*CONSTCOND*/0) | |
253 | static __inline uint8_t | 253 | static __inline uint8_t | |
254 | UREAD1(uhci_softc_t *sc, bus_size_t r) | 254 | UREAD1(uhci_softc_t *sc, bus_size_t r) | |
255 | { | 255 | { | |
256 | 256 | |||
257 | UBARR(sc); | 257 | UBARR(sc); | |
258 | return bus_space_read_1(sc->iot, sc->ioh, r); | 258 | return bus_space_read_1(sc->iot, sc->ioh, r); | |
259 | } | 259 | } | |
260 | 260 | |||
261 | static __inline uint16_t | 261 | static __inline uint16_t | |
262 | UREAD2(uhci_softc_t *sc, bus_size_t r) | 262 | UREAD2(uhci_softc_t *sc, bus_size_t r) | |
263 | { | 263 | { | |
264 | 264 | |||
265 | UBARR(sc); | 265 | UBARR(sc); | |
266 | return bus_space_read_2(sc->iot, sc->ioh, r); | 266 | return bus_space_read_2(sc->iot, sc->ioh, r); | |
267 | } | 267 | } | |
268 | 268 | |||
269 | static __inline uint32_t | 269 | static __inline uint32_t | |
270 | UREAD4(uhci_softc_t *sc, bus_size_t r) | 270 | UREAD4(uhci_softc_t *sc, bus_size_t r) | |
271 | { | 271 | { | |
272 | 272 | |||
273 | UBARR(sc); | 273 | UBARR(sc); | |
274 | return bus_space_read_4(sc->iot, sc->ioh, r); | 274 | return bus_space_read_4(sc->iot, sc->ioh, r); | |
275 | } | 275 | } | |
276 | 276 | |||
277 | #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd) | 277 | #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd) | |
278 | #define UHCISTS(sc) UREAD2(sc, UHCI_STS) | 278 | #define UHCISTS(sc) UREAD2(sc, UHCI_STS) | |
279 | 279 | |||
280 | #define UHCI_RESET_TIMEOUT 100 /* ms, reset timeout */ | 280 | #define UHCI_RESET_TIMEOUT 100 /* ms, reset timeout */ | |
281 | 281 | |||
282 | #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK) | 282 | #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK) | |
283 | 283 | |||
284 | #define UHCI_INTR_ENDPT 1 | 284 | #define UHCI_INTR_ENDPT 1 | |
285 | 285 | |||
286 | const struct usbd_bus_methods uhci_bus_methods = { | 286 | const struct usbd_bus_methods uhci_bus_methods = { | |
287 | uhci_open, | 287 | .open_pipe = uhci_open, | |
288 | uhci_softintr, | 288 | .soft_intr = uhci_softintr, | |
289 | uhci_poll, | 289 | .do_poll = uhci_poll, | |
290 | uhci_allocm, | 290 | .allocm = uhci_allocm, | |
291 | uhci_freem, | 291 | .freem = uhci_freem, | |
292 | uhci_allocx, | 292 | .allocx = uhci_allocx, | |
293 | uhci_freex, | 293 | .freex = uhci_freex, | |
294 | uhci_get_locks, | 294 | .get_locks = uhci_get_locks, | |
295 | }; | 295 | }; | |
296 | 296 | |||
297 | const struct usbd_pipe_methods uhci_root_ctrl_methods = { | 297 | const struct usbd_pipe_methods uhci_root_ctrl_methods = { | |
298 | uhci_root_ctrl_transfer, | 298 | .transfer = uhci_root_ctrl_transfer, | |
299 | uhci_root_ctrl_start, | 299 | .start = uhci_root_ctrl_start, | |
300 | uhci_root_ctrl_abort, | 300 | .abort = uhci_root_ctrl_abort, | |
301 | uhci_root_ctrl_close, | 301 | .close = uhci_root_ctrl_close, | |
302 | uhci_noop, | 302 | .cleartoggle = uhci_noop, | |
303 | uhci_root_ctrl_done, | 303 | .done = uhci_root_ctrl_done, | |
304 | }; | 304 | }; | |
305 | 305 | |||
306 | const struct usbd_pipe_methods uhci_root_intr_methods = { | 306 | const struct usbd_pipe_methods uhci_root_intr_methods = { | |
307 | uhci_root_intr_transfer, | 307 | .transfer = uhci_root_intr_transfer, | |
308 | uhci_root_intr_start, | 308 | .start = uhci_root_intr_start, | |
309 | uhci_root_intr_abort, | 309 | .abort = uhci_root_intr_abort, | |
310 | uhci_root_intr_close, | 310 | .close = uhci_root_intr_close, | |
311 | uhci_noop, | 311 | .cleartoggle = uhci_noop, | |
312 | uhci_root_intr_done, | 312 | .done = uhci_root_intr_done, | |
313 | }; | 313 | }; | |
314 | 314 | |||
315 | const struct usbd_pipe_methods uhci_device_ctrl_methods = { | 315 | const struct usbd_pipe_methods uhci_device_ctrl_methods = { | |
316 | uhci_device_ctrl_transfer, | 316 | .transfer = uhci_device_ctrl_transfer, | |
317 | uhci_device_ctrl_start, | 317 | .start = uhci_device_ctrl_start, | |
318 | uhci_device_ctrl_abort, | 318 | .abort = uhci_device_ctrl_abort, | |
319 | uhci_device_ctrl_close, | 319 | .close = uhci_device_ctrl_close, | |
320 | uhci_noop, | 320 | .cleartoggle = uhci_noop, | |
321 | uhci_device_ctrl_done, | 321 | .done = uhci_device_ctrl_done, | |
322 | }; | 322 | }; | |
323 | 323 | |||
324 | const struct usbd_pipe_methods uhci_device_intr_methods = { | 324 | const struct usbd_pipe_methods uhci_device_intr_methods = { | |
325 | uhci_device_intr_transfer, | 325 | .transfer = uhci_device_intr_transfer, | |
326 | uhci_device_intr_start, | 326 | .start = uhci_device_intr_start, | |
327 | uhci_device_intr_abort, | 327 | .abort = uhci_device_intr_abort, | |
328 | uhci_device_intr_close, | 328 | .close = uhci_device_intr_close, | |
329 | uhci_device_clear_toggle, | 329 | .cleartoggle = uhci_device_clear_toggle, | |
330 | uhci_device_intr_done, | 330 | .done = uhci_device_intr_done, | |
331 | }; | 331 | }; | |
332 | 332 | |||
333 | const struct usbd_pipe_methods uhci_device_bulk_methods = { | 333 | const struct usbd_pipe_methods uhci_device_bulk_methods = { | |
334 | uhci_device_bulk_transfer, | 334 | .transfer = uhci_device_bulk_transfer, | |
335 | uhci_device_bulk_start, | 335 | .start = uhci_device_bulk_start, | |
336 | uhci_device_bulk_abort, | 336 | .abort = uhci_device_bulk_abort, | |
337 | uhci_device_bulk_close, | 337 | .close = uhci_device_bulk_close, | |
338 | uhci_device_clear_toggle, | 338 | .cleartoggle = uhci_device_clear_toggle, | |
339 | uhci_device_bulk_done, | 339 | .done = uhci_device_bulk_done, | |
340 | }; | 340 | }; | |
341 | 341 | |||
342 | const struct usbd_pipe_methods uhci_device_isoc_methods = { | 342 | const struct usbd_pipe_methods uhci_device_isoc_methods = { | |
343 | uhci_device_isoc_transfer, | 343 | .transfer = uhci_device_isoc_transfer, | |
344 | uhci_device_isoc_start, | 344 | .start = uhci_device_isoc_start, | |
345 | uhci_device_isoc_abort, | 345 | .abort = uhci_device_isoc_abort, | |
346 | uhci_device_isoc_close, | 346 | .close = uhci_device_isoc_close, | |
347 | uhci_noop, | 347 | .cleartoggle = uhci_noop, | |
348 | uhci_device_isoc_done, | 348 | .done = uhci_device_isoc_done, | |
349 | }; | 349 | }; | |
350 | 350 | |||
351 | #define uhci_add_intr_info(sc, ii) \ | 351 | #define uhci_add_intr_info(sc, ii) \ | |
352 | LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list) | 352 | LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list) | |
353 | #define uhci_del_intr_info(ii) \ | 353 | #define uhci_del_intr_info(ii) \ | |
354 | do { \ | 354 | do { \ | |
355 | LIST_REMOVE((ii), list); \ | 355 | LIST_REMOVE((ii), list); \ | |
356 | (ii)->list.le_prev = NULL; \ | 356 | (ii)->list.le_prev = NULL; \ | |
357 | } while (0) | 357 | } while (0) | |
358 | #define uhci_active_intr_info(ii) ((ii)->list.le_prev != NULL) | 358 | #define uhci_active_intr_info(ii) ((ii)->list.le_prev != NULL) | |
359 | 359 | |||
360 | static inline uhci_soft_qh_t * | 360 | static inline uhci_soft_qh_t * | |
361 | uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh) | 361 | uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh) | |
362 | { | 362 | { | |
363 | DPRINTFN(15,("uhci_find_prev_qh: pqh=%p sqh=%p\n", pqh, sqh)); | 363 | DPRINTFN(15,("uhci_find_prev_qh: pqh=%p sqh=%p\n", pqh, sqh)); | |
364 | 364 | |||
365 | for (; pqh->hlink != sqh; pqh = pqh->hlink) { | 365 | for (; pqh->hlink != sqh; pqh = pqh->hlink) { | |
366 | #if defined(DIAGNOSTIC) || defined(UHCI_DEBUG) | 366 | #if defined(DIAGNOSTIC) || defined(UHCI_DEBUG) | |
367 | usb_syncmem(&pqh->dma, | 367 | usb_syncmem(&pqh->dma, | |
368 | pqh->offs + offsetof(uhci_qh_t, qh_hlink), | 368 | pqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
369 | sizeof(pqh->qh.qh_hlink), | 369 | sizeof(pqh->qh.qh_hlink), | |
370 | BUS_DMASYNC_POSTWRITE); | 370 | BUS_DMASYNC_POSTWRITE); | |
371 | if (le32toh(pqh->qh.qh_hlink) & UHCI_PTR_T) { | 371 | if (le32toh(pqh->qh.qh_hlink) & UHCI_PTR_T) { | |
372 | printf("uhci_find_prev_qh: QH not found\n"); | 372 | printf("uhci_find_prev_qh: QH not found\n"); | |
373 | return (NULL); | 373 | return (NULL); | |
374 | } | 374 | } | |
375 | #endif | 375 | #endif | |
376 | } | 376 | } | |
377 | return (pqh); | 377 | return (pqh); | |
378 | } | 378 | } | |
379 | 379 | |||
380 | void | 380 | void | |
381 | uhci_globalreset(uhci_softc_t *sc) | 381 | uhci_globalreset(uhci_softc_t *sc) | |
382 | { | 382 | { | |
383 | UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */ | 383 | UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */ | |
384 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */ | 384 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */ | |
385 | UHCICMD(sc, 0); /* do nothing */ | 385 | UHCICMD(sc, 0); /* do nothing */ | |
386 | } | 386 | } | |
387 | 387 | |||
388 | usbd_status | 388 | usbd_status | |
389 | uhci_init(uhci_softc_t *sc) | 389 | uhci_init(uhci_softc_t *sc) | |
390 | { | 390 | { | |
391 | usbd_status err; | 391 | usbd_status err; | |
392 | int i, j; | 392 | int i, j; | |
393 | uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh; | 393 | uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh; | |
394 | uhci_soft_td_t *std; | 394 | uhci_soft_td_t *std; | |
395 | 395 | |||
396 | DPRINTFN(1,("uhci_init: start\n")); | 396 | DPRINTFN(1,("uhci_init: start\n")); | |
397 | 397 | |||
398 | #ifdef UHCI_DEBUG | 398 | #ifdef UHCI_DEBUG | |
399 | thesc = sc; | 399 | thesc = sc; | |
400 | 400 | |||
401 | if (uhcidebug > 2) | 401 | if (uhcidebug > 2) | |
402 | uhci_dumpregs(sc); | 402 | uhci_dumpregs(sc); | |
403 | #endif | 403 | #endif | |
404 | 404 | |||
405 | sc->sc_suspend = PWR_RESUME; | 405 | sc->sc_suspend = PWR_RESUME; | |
406 | 406 | |||
407 | UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */ | 407 | UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */ | |
408 | uhci_globalreset(sc); /* reset the controller */ | 408 | uhci_globalreset(sc); /* reset the controller */ | |
409 | uhci_reset(sc); | 409 | uhci_reset(sc); | |
410 | 410 | |||
411 | usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag, | 411 | usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag, | |
412 | USB_MEM_RESERVE); | 412 | USB_MEM_RESERVE); | |
413 | 413 | |||
414 | /* Allocate and initialize real frame array. */ | 414 | /* Allocate and initialize real frame array. */ | |
415 | err = usb_allocmem(&sc->sc_bus, | 415 | err = usb_allocmem(&sc->sc_bus, | |
416 | UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), | 416 | UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), | |
417 | UHCI_FRAMELIST_ALIGN, &sc->sc_dma); | 417 | UHCI_FRAMELIST_ALIGN, &sc->sc_dma); | |
418 | if (err) | 418 | if (err) | |
419 | return (err); | 419 | return (err); | |
420 | sc->sc_pframes = KERNADDR(&sc->sc_dma, 0); | 420 | sc->sc_pframes = KERNADDR(&sc->sc_dma, 0); | |
421 | UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */ | 421 | UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */ | |
422 | UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/ | 422 | UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/ | |
423 | 423 | |||
424 | /* | 424 | /* | |
425 | * Allocate a TD, inactive, that hangs from the last QH. | 425 | * Allocate a TD, inactive, that hangs from the last QH. | |
426 | * This is to avoid a bug in the PIIX that makes it run berserk | 426 | * This is to avoid a bug in the PIIX that makes it run berserk | |
427 | * otherwise. | 427 | * otherwise. | |
428 | */ | 428 | */ | |
429 | std = uhci_alloc_std(sc); | 429 | std = uhci_alloc_std(sc); | |
430 | if (std == NULL) | 430 | if (std == NULL) | |
431 | return (USBD_NOMEM); | 431 | return (USBD_NOMEM); | |
432 | std->link.std = NULL; | 432 | std->link.std = NULL; | |
433 | std->td.td_link = htole32(UHCI_PTR_T); | 433 | std->td.td_link = htole32(UHCI_PTR_T); | |
434 | std->td.td_status = htole32(0); /* inactive */ | 434 | std->td.td_status = htole32(0); /* inactive */ | |
435 | std->td.td_token = htole32(0); | 435 | std->td.td_token = htole32(0); | |
436 | std->td.td_buffer = htole32(0); | 436 | std->td.td_buffer = htole32(0); | |
437 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | 437 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | |
438 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 438 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
439 | 439 | |||
440 | /* Allocate the dummy QH marking the end and used for looping the QHs.*/ | 440 | /* Allocate the dummy QH marking the end and used for looping the QHs.*/ | |
441 | lsqh = uhci_alloc_sqh(sc); | 441 | lsqh = uhci_alloc_sqh(sc); | |
442 | if (lsqh == NULL) | 442 | if (lsqh == NULL) | |
443 | return (USBD_NOMEM); | 443 | return (USBD_NOMEM); | |
444 | lsqh->hlink = NULL; | 444 | lsqh->hlink = NULL; | |
445 | lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */ | 445 | lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */ | |
446 | lsqh->elink = std; | 446 | lsqh->elink = std; | |
447 | lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD); | 447 | lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD); | |
448 | sc->sc_last_qh = lsqh; | 448 | sc->sc_last_qh = lsqh; | |
449 | usb_syncmem(&lsqh->dma, lsqh->offs, sizeof(lsqh->qh), | 449 | usb_syncmem(&lsqh->dma, lsqh->offs, sizeof(lsqh->qh), | |
450 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 450 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
451 | 451 | |||
452 | /* Allocate the dummy QH where bulk traffic will be queued. */ | 452 | /* Allocate the dummy QH where bulk traffic will be queued. */ | |
453 | bsqh = uhci_alloc_sqh(sc); | 453 | bsqh = uhci_alloc_sqh(sc); | |
454 | if (bsqh == NULL) | 454 | if (bsqh == NULL) | |
455 | return (USBD_NOMEM); | 455 | return (USBD_NOMEM); | |
456 | bsqh->hlink = lsqh; | 456 | bsqh->hlink = lsqh; | |
457 | bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH); | 457 | bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH); | |
458 | bsqh->elink = NULL; | 458 | bsqh->elink = NULL; | |
459 | bsqh->qh.qh_elink = htole32(UHCI_PTR_T); | 459 | bsqh->qh.qh_elink = htole32(UHCI_PTR_T); | |
460 | sc->sc_bulk_start = sc->sc_bulk_end = bsqh; | 460 | sc->sc_bulk_start = sc->sc_bulk_end = bsqh; | |
461 | usb_syncmem(&bsqh->dma, bsqh->offs, sizeof(bsqh->qh), | 461 | usb_syncmem(&bsqh->dma, bsqh->offs, sizeof(bsqh->qh), | |
462 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 462 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
463 | 463 | |||
464 | /* Allocate dummy QH where high speed control traffic will be queued. */ | 464 | /* Allocate dummy QH where high speed control traffic will be queued. */ | |
465 | chsqh = uhci_alloc_sqh(sc); | 465 | chsqh = uhci_alloc_sqh(sc); | |
466 | if (chsqh == NULL) | 466 | if (chsqh == NULL) | |
467 | return (USBD_NOMEM); | 467 | return (USBD_NOMEM); | |
468 | chsqh->hlink = bsqh; | 468 | chsqh->hlink = bsqh; | |
469 | chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH); | 469 | chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH); | |
470 | chsqh->elink = NULL; | 470 | chsqh->elink = NULL; | |
471 | chsqh->qh.qh_elink = htole32(UHCI_PTR_T); | 471 | chsqh->qh.qh_elink = htole32(UHCI_PTR_T); | |
472 | sc->sc_hctl_start = sc->sc_hctl_end = chsqh; | 472 | sc->sc_hctl_start = sc->sc_hctl_end = chsqh; | |
473 | usb_syncmem(&chsqh->dma, chsqh->offs, sizeof(chsqh->qh), | 473 | usb_syncmem(&chsqh->dma, chsqh->offs, sizeof(chsqh->qh), | |
474 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 474 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
475 | 475 | |||
476 | /* Allocate dummy QH where control traffic will be queued. */ | 476 | /* Allocate dummy QH where control traffic will be queued. */ | |
477 | clsqh = uhci_alloc_sqh(sc); | 477 | clsqh = uhci_alloc_sqh(sc); | |
478 | if (clsqh == NULL) | 478 | if (clsqh == NULL) | |
479 | return (USBD_NOMEM); | 479 | return (USBD_NOMEM); | |
480 | clsqh->hlink = chsqh; | 480 | clsqh->hlink = chsqh; | |
481 | clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH); | 481 | clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH); | |
482 | clsqh->elink = NULL; | 482 | clsqh->elink = NULL; | |
483 | clsqh->qh.qh_elink = htole32(UHCI_PTR_T); | 483 | clsqh->qh.qh_elink = htole32(UHCI_PTR_T); | |
484 | sc->sc_lctl_start = sc->sc_lctl_end = clsqh; | 484 | sc->sc_lctl_start = sc->sc_lctl_end = clsqh; | |
485 | usb_syncmem(&clsqh->dma, clsqh->offs, sizeof(clsqh->qh), | 485 | usb_syncmem(&clsqh->dma, clsqh->offs, sizeof(clsqh->qh), | |
486 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 486 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
487 | 487 | |||
488 | /* | 488 | /* | |
489 | * Make all (virtual) frame list pointers point to the interrupt | 489 | * Make all (virtual) frame list pointers point to the interrupt | |
490 | * queue heads and the interrupt queue heads at the control | 490 | * queue heads and the interrupt queue heads at the control | |
491 | * queue head and point the physical frame list to the virtual. | 491 | * queue head and point the physical frame list to the virtual. | |
492 | */ | 492 | */ | |
493 | for(i = 0; i < UHCI_VFRAMELIST_COUNT; i++) { | 493 | for(i = 0; i < UHCI_VFRAMELIST_COUNT; i++) { | |
494 | std = uhci_alloc_std(sc); | 494 | std = uhci_alloc_std(sc); | |
495 | sqh = uhci_alloc_sqh(sc); | 495 | sqh = uhci_alloc_sqh(sc); | |
496 | if (std == NULL || sqh == NULL) | 496 | if (std == NULL || sqh == NULL) | |
497 | return (USBD_NOMEM); | 497 | return (USBD_NOMEM); | |
498 | std->link.sqh = sqh; | 498 | std->link.sqh = sqh; | |
499 | std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH); | 499 | std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH); | |
500 | std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */ | 500 | std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */ | |
501 | std->td.td_token = htole32(0); | 501 | std->td.td_token = htole32(0); | |
502 | std->td.td_buffer = htole32(0); | 502 | std->td.td_buffer = htole32(0); | |
503 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | 503 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | |
504 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 504 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
505 | sqh->hlink = clsqh; | 505 | sqh->hlink = clsqh; | |
506 | sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH); | 506 | sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH); | |
507 | sqh->elink = NULL; | 507 | sqh->elink = NULL; | |
508 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | 508 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | |
509 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 509 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
510 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 510 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
511 | sc->sc_vframes[i].htd = std; | 511 | sc->sc_vframes[i].htd = std; | |
512 | sc->sc_vframes[i].etd = std; | 512 | sc->sc_vframes[i].etd = std; | |
513 | sc->sc_vframes[i].hqh = sqh; | 513 | sc->sc_vframes[i].hqh = sqh; | |
514 | sc->sc_vframes[i].eqh = sqh; | 514 | sc->sc_vframes[i].eqh = sqh; | |
515 | for (j = i; | 515 | for (j = i; | |
516 | j < UHCI_FRAMELIST_COUNT; | 516 | j < UHCI_FRAMELIST_COUNT; | |
517 | j += UHCI_VFRAMELIST_COUNT) | 517 | j += UHCI_VFRAMELIST_COUNT) | |
518 | sc->sc_pframes[j] = htole32(std->physaddr); | 518 | sc->sc_pframes[j] = htole32(std->physaddr); | |
519 | } | 519 | } | |
520 | usb_syncmem(&sc->sc_dma, 0, | 520 | usb_syncmem(&sc->sc_dma, 0, | |
521 | UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), | 521 | UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), | |
522 | BUS_DMASYNC_PREWRITE); | 522 | BUS_DMASYNC_PREWRITE); | |
523 | 523 | |||
524 | 524 | |||
525 | LIST_INIT(&sc->sc_intrhead); | 525 | LIST_INIT(&sc->sc_intrhead); | |
526 | 526 | |||
527 | SIMPLEQ_INIT(&sc->sc_free_xfers); | 527 | SIMPLEQ_INIT(&sc->sc_free_xfers); | |
528 | 528 | |||
529 | callout_init(&sc->sc_poll_handle, CALLOUT_MPSAFE); | 529 | callout_init(&sc->sc_poll_handle, CALLOUT_MPSAFE); | |
530 | 530 | |||
531 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | 531 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | |
532 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | 532 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | |
533 | cv_init(&sc->sc_softwake_cv, "uhciab"); | 533 | cv_init(&sc->sc_softwake_cv, "uhciab"); | |
534 | 534 | |||
535 | /* Set up the bus struct. */ | 535 | /* Set up the bus struct. */ | |
536 | sc->sc_bus.methods = &uhci_bus_methods; | 536 | sc->sc_bus.methods = &uhci_bus_methods; | |
537 | sc->sc_bus.pipe_size = sizeof(struct uhci_pipe); | 537 | sc->sc_bus.pipe_size = sizeof(struct uhci_pipe); | |
538 | 538 | |||
539 | UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */ | 539 | UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */ | |
540 | 540 | |||
541 | DPRINTFN(1,("uhci_init: enabling\n")); | 541 | DPRINTFN(1,("uhci_init: enabling\n")); | |
542 | 542 | |||
543 | err = uhci_run(sc, 1); /* and here we go... */ | 543 | err = uhci_run(sc, 1); /* and here we go... */ | |
544 | UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | | 544 | UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | | |
545 | UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */ | 545 | UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */ | |
546 | return err; | 546 | return err; | |
547 | } | 547 | } | |
548 | 548 | |||
549 | int | 549 | int | |
550 | uhci_activate(device_t self, enum devact act) | 550 | uhci_activate(device_t self, enum devact act) | |
551 | { | 551 | { | |
552 | struct uhci_softc *sc = device_private(self); | 552 | struct uhci_softc *sc = device_private(self); | |
553 | 553 | |||
554 | switch (act) { | 554 | switch (act) { | |
555 | case DVACT_DEACTIVATE: | 555 | case DVACT_DEACTIVATE: | |
556 | sc->sc_dying = 1; | 556 | sc->sc_dying = 1; | |
557 | return 0; | 557 | return 0; | |
558 | default: | 558 | default: | |
559 | return EOPNOTSUPP; | 559 | return EOPNOTSUPP; | |
560 | } | 560 | } | |
561 | } | 561 | } | |
562 | 562 | |||
563 | void | 563 | void | |
564 | uhci_childdet(device_t self, device_t child) | 564 | uhci_childdet(device_t self, device_t child) | |
565 | { | 565 | { | |
566 | struct uhci_softc *sc = device_private(self); | 566 | struct uhci_softc *sc = device_private(self); | |
567 | 567 | |||
568 | KASSERT(sc->sc_child == child); | 568 | KASSERT(sc->sc_child == child); | |
569 | sc->sc_child = NULL; | 569 | sc->sc_child = NULL; | |
570 | } | 570 | } | |
571 | 571 | |||
572 | int | 572 | int | |
573 | uhci_detach(struct uhci_softc *sc, int flags) | 573 | uhci_detach(struct uhci_softc *sc, int flags) | |
574 | { | 574 | { | |
575 | usbd_xfer_handle xfer; | 575 | usbd_xfer_handle xfer; | |
576 | int rv = 0; | 576 | int rv = 0; | |
577 | 577 | |||
578 | if (sc->sc_child != NULL) | 578 | if (sc->sc_child != NULL) | |
579 | rv = config_detach(sc->sc_child, flags); | 579 | rv = config_detach(sc->sc_child, flags); | |
580 | 580 | |||
581 | if (rv != 0) | 581 | if (rv != 0) | |
582 | return (rv); | 582 | return (rv); | |
583 | 583 | |||
584 | /* Free all xfers associated with this HC. */ | 584 | /* Free all xfers associated with this HC. */ | |
585 | for (;;) { | 585 | for (;;) { | |
586 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | 586 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | |
587 | if (xfer == NULL) | 587 | if (xfer == NULL) | |
588 | break; | 588 | break; | |
589 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | 589 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | |
590 | kmem_free(xfer, sizeof(struct uhci_xfer)); | 590 | kmem_free(xfer, sizeof(struct uhci_xfer)); | |
591 | } | 591 | } | |
592 | 592 | |||
593 | callout_halt(&sc->sc_poll_handle, NULL); | 593 | callout_halt(&sc->sc_poll_handle, NULL); | |
594 | callout_destroy(&sc->sc_poll_handle); | 594 | callout_destroy(&sc->sc_poll_handle); | |
595 | 595 | |||
596 | cv_destroy(&sc->sc_softwake_cv); | 596 | cv_destroy(&sc->sc_softwake_cv); | |
597 | 597 | |||
598 | mutex_destroy(&sc->sc_lock); | 598 | mutex_destroy(&sc->sc_lock); | |
599 | mutex_destroy(&sc->sc_intr_lock); | 599 | mutex_destroy(&sc->sc_intr_lock); | |
600 | 600 | |||
601 | /* XXX free other data structures XXX */ | 601 | /* XXX free other data structures XXX */ | |
602 | 602 | |||
603 | return (rv); | 603 | return (rv); | |
604 | } | 604 | } | |
605 | 605 | |||
606 | usbd_status | 606 | usbd_status | |
607 | uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) | 607 | uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) | |
608 | { | 608 | { | |
609 | struct uhci_softc *sc = bus->hci_private; | 609 | struct uhci_softc *sc = bus->hci_private; | |
610 | usbd_status status; | 610 | usbd_status status; | |
611 | u_int32_t n; | 611 | u_int32_t n; | |
612 | 612 | |||
613 | /* | 613 | /* | |
614 | * XXX | 614 | * XXX | |
615 | * Since we are allocating a buffer we can assume that we will | 615 | * Since we are allocating a buffer we can assume that we will | |
616 | * need TDs for it. Since we don't want to allocate those from | 616 | * need TDs for it. Since we don't want to allocate those from | |
617 | * an interrupt context, we allocate them here and free them again. | 617 | * an interrupt context, we allocate them here and free them again. | |
618 | * This is no guarantee that we'll get the TDs next time... | 618 | * This is no guarantee that we'll get the TDs next time... | |
619 | */ | 619 | */ | |
620 | n = size / 8; | 620 | n = size / 8; | |
621 | if (n > 16) { | 621 | if (n > 16) { | |
622 | u_int32_t i; | 622 | u_int32_t i; | |
623 | uhci_soft_td_t **stds; | 623 | uhci_soft_td_t **stds; | |
624 | 624 | |||
625 | DPRINTF(("uhci_allocm: get %d TDs\n", n)); | 625 | DPRINTF(("uhci_allocm: get %d TDs\n", n)); | |
626 | stds = kmem_alloc(sizeof(uhci_soft_td_t *) * n, KM_SLEEP); | 626 | stds = kmem_alloc(sizeof(uhci_soft_td_t *) * n, KM_SLEEP); | |
627 | if (!stds) | 627 | if (!stds) | |
628 | return USBD_NOMEM; | 628 | return USBD_NOMEM; | |
629 | for(i = 0; i < n; i++) | 629 | for(i = 0; i < n; i++) | |
630 | stds[i] = uhci_alloc_std(sc); | 630 | stds[i] = uhci_alloc_std(sc); | |
631 | for(i = 0; i < n; i++) | 631 | for(i = 0; i < n; i++) | |
632 | if (stds[i] != NULL) | 632 | if (stds[i] != NULL) | |
633 | uhci_free_std(sc, stds[i]); | 633 | uhci_free_std(sc, stds[i]); | |
634 | kmem_free(stds, sizeof(uhci_soft_td_t *) * n); | 634 | kmem_free(stds, sizeof(uhci_soft_td_t *) * n); | |
635 | } | 635 | } | |
636 | 636 | |||
637 | status = usb_allocmem(&sc->sc_bus, size, 0, dma); | 637 | status = usb_allocmem(&sc->sc_bus, size, 0, dma); | |
638 | if (status == USBD_NOMEM) | 638 | if (status == USBD_NOMEM) | |
639 | status = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size); | 639 | status = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size); | |
640 | return status; | 640 | return status; | |
641 | } | 641 | } | |
642 | 642 | |||
643 | void | 643 | void | |
644 | uhci_freem(struct usbd_bus *bus, usb_dma_t *dma) | 644 | uhci_freem(struct usbd_bus *bus, usb_dma_t *dma) | |
645 | { | 645 | { | |
646 | if (dma->block->flags & USB_DMA_RESERVE) { | 646 | if (dma->block->flags & USB_DMA_RESERVE) { | |
647 | usb_reserve_freem(&((struct uhci_softc *)bus)->sc_dma_reserve, | 647 | usb_reserve_freem(&((struct uhci_softc *)bus)->sc_dma_reserve, | |
648 | dma); | 648 | dma); | |
649 | return; | 649 | return; | |
650 | } | 650 | } | |
651 | usb_freemem(&((struct uhci_softc *)bus)->sc_bus, dma); | 651 | usb_freemem(&((struct uhci_softc *)bus)->sc_bus, dma); | |
652 | } | 652 | } | |
653 | 653 | |||
654 | usbd_xfer_handle | 654 | usbd_xfer_handle | |
655 | uhci_allocx(struct usbd_bus *bus) | 655 | uhci_allocx(struct usbd_bus *bus) | |
656 | { | 656 | { | |
657 | struct uhci_softc *sc = bus->hci_private; | 657 | struct uhci_softc *sc = bus->hci_private; | |
658 | usbd_xfer_handle xfer; | 658 | usbd_xfer_handle xfer; | |
659 | 659 | |||
660 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | 660 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | |
661 | if (xfer != NULL) { | 661 | if (xfer != NULL) { | |
662 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | 662 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); | |
663 | #ifdef DIAGNOSTIC | 663 | #ifdef DIAGNOSTIC | |
664 | if (xfer->busy_free != XFER_FREE) { | 664 | if (xfer->busy_free != XFER_FREE) { | |
665 | printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer, | 665 | printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer, | |
666 | xfer->busy_free); | 666 | xfer->busy_free); | |
667 | } | 667 | } | |
668 | #endif | 668 | #endif | |
669 | } else { | 669 | } else { | |
670 | xfer = kmem_alloc(sizeof(struct uhci_xfer), KM_SLEEP); | 670 | xfer = kmem_alloc(sizeof(struct uhci_xfer), KM_SLEEP); | |
671 | } | 671 | } | |
672 | if (xfer != NULL) { | 672 | if (xfer != NULL) { | |
673 | memset(xfer, 0, sizeof (struct uhci_xfer)); | 673 | memset(xfer, 0, sizeof (struct uhci_xfer)); | |
674 | UXFER(xfer)->iinfo.sc = sc; | 674 | UXFER(xfer)->iinfo.sc = sc; | |
675 | #ifdef DIAGNOSTIC | 675 | #ifdef DIAGNOSTIC | |
676 | UXFER(xfer)->iinfo.isdone = 1; | 676 | UXFER(xfer)->iinfo.isdone = 1; | |
677 | xfer->busy_free = XFER_BUSY; | 677 | xfer->busy_free = XFER_BUSY; | |
678 | #endif | 678 | #endif | |
679 | } | 679 | } | |
680 | return (xfer); | 680 | return (xfer); | |
681 | } | 681 | } | |
682 | 682 | |||
683 | void | 683 | void | |
684 | uhci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) | 684 | uhci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) | |
685 | { | 685 | { | |
686 | struct uhci_softc *sc = bus->hci_private; | 686 | struct uhci_softc *sc = bus->hci_private; | |
687 | 687 | |||
688 | #ifdef DIAGNOSTIC | 688 | #ifdef DIAGNOSTIC | |
689 | if (xfer->busy_free != XFER_BUSY) { | 689 | if (xfer->busy_free != XFER_BUSY) { | |
690 | printf("uhci_freex: xfer=%p not busy, 0x%08x\n", xfer, | 690 | printf("uhci_freex: xfer=%p not busy, 0x%08x\n", xfer, | |
691 | xfer->busy_free); | 691 | xfer->busy_free); | |
692 | } | 692 | } | |
693 | xfer->busy_free = XFER_FREE; | 693 | xfer->busy_free = XFER_FREE; | |
694 | if (!UXFER(xfer)->iinfo.isdone) { | 694 | if (!UXFER(xfer)->iinfo.isdone) { | |
695 | printf("uhci_freex: !isdone\n"); | 695 | printf("uhci_freex: !isdone\n"); | |
696 | } | 696 | } | |
697 | #endif | 697 | #endif | |
698 | SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next); | 698 | SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next); | |
699 | } | 699 | } | |
700 | 700 | |||
701 | Static void | 701 | Static void | |
702 | uhci_get_locks(struct usbd_bus *bus, kmutex_t **intr, kmutex_t **thread) | 702 | uhci_get_locks(struct usbd_bus *bus, kmutex_t **intr, kmutex_t **thread) | |
703 | { | 703 | { | |
704 | struct uhci_softc *sc = bus->hci_private; | 704 | struct uhci_softc *sc = bus->hci_private; | |
705 | 705 | |||
706 | *intr = &sc->sc_intr_lock; | 706 | *intr = &sc->sc_intr_lock; | |
707 | *thread = &sc->sc_lock; | 707 | *thread = &sc->sc_lock; | |
708 | } | 708 | } | |
709 | 709 | |||
710 | 710 | |||
711 | /* | 711 | /* | |
712 | * Handle suspend/resume. | 712 | * Handle suspend/resume. | |
713 | * | 713 | * | |
714 | * We need to switch to polling mode here, because this routine is | 714 | * We need to switch to polling mode here, because this routine is | |
715 | * called from an interrupt context. This is all right since we | 715 | * called from an interrupt context. This is all right since we | |
716 | * are almost suspended anyway. | 716 | * are almost suspended anyway. | |
717 | */ | 717 | */ | |
718 | bool | 718 | bool | |
719 | uhci_resume(device_t dv, const pmf_qual_t *qual) | 719 | uhci_resume(device_t dv, const pmf_qual_t *qual) | |
720 | { | 720 | { | |
721 | uhci_softc_t *sc = device_private(dv); | 721 | uhci_softc_t *sc = device_private(dv); | |
722 | int cmd; | 722 | int cmd; | |
723 | 723 | |||
724 | mutex_spin_enter(&sc->sc_intr_lock); | 724 | mutex_spin_enter(&sc->sc_intr_lock); | |
725 | 725 | |||
726 | cmd = UREAD2(sc, UHCI_CMD); | 726 | cmd = UREAD2(sc, UHCI_CMD); | |
727 | sc->sc_bus.use_polling++; | 727 | sc->sc_bus.use_polling++; | |
728 | UWRITE2(sc, UHCI_INTR, 0); | 728 | UWRITE2(sc, UHCI_INTR, 0); | |
729 | uhci_globalreset(sc); | 729 | uhci_globalreset(sc); | |
730 | uhci_reset(sc); | 730 | uhci_reset(sc); | |
731 | if (cmd & UHCI_CMD_RS) | 731 | if (cmd & UHCI_CMD_RS) | |
732 | uhci_run(sc, 0); | 732 | uhci_run(sc, 0); | |
733 | 733 | |||
734 | /* restore saved state */ | 734 | /* restore saved state */ | |
735 | UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); | 735 | UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); | |
736 | UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum); | 736 | UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum); | |
737 | UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof); | 737 | UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof); | |
738 | 738 | |||
739 | UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force resume */ | 739 | UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force resume */ | |
740 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | 740 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | |
741 | UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */ | 741 | UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */ | |
742 | UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | | 742 | UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | | |
743 | UHCI_INTR_RIE | UHCI_INTR_IOCE | UHCI_INTR_SPIE); | 743 | UHCI_INTR_RIE | UHCI_INTR_IOCE | UHCI_INTR_SPIE); | |
744 | UHCICMD(sc, UHCI_CMD_MAXP); | 744 | UHCICMD(sc, UHCI_CMD_MAXP); | |
745 | uhci_run(sc, 1); /* and start traffic again */ | 745 | uhci_run(sc, 1); /* and start traffic again */ | |
746 | usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); | 746 | usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); | |
747 | sc->sc_bus.use_polling--; | 747 | sc->sc_bus.use_polling--; | |
748 | if (sc->sc_intr_xfer != NULL) | 748 | if (sc->sc_intr_xfer != NULL) | |
749 | callout_reset(&sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, | 749 | callout_reset(&sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, | |
750 | sc->sc_intr_xfer); | 750 | sc->sc_intr_xfer); | |
751 | #ifdef UHCI_DEBUG | 751 | #ifdef UHCI_DEBUG | |
752 | if (uhcidebug > 2) | 752 | if (uhcidebug > 2) | |
753 | uhci_dumpregs(sc); | 753 | uhci_dumpregs(sc); | |
754 | #endif | 754 | #endif | |
755 | 755 | |||
756 | sc->sc_suspend = PWR_RESUME; | 756 | sc->sc_suspend = PWR_RESUME; | |
757 | mutex_spin_exit(&sc->sc_intr_lock); | 757 | mutex_spin_exit(&sc->sc_intr_lock); | |
758 | 758 | |||
759 | return true; | 759 | return true; | |
760 | } | 760 | } | |
761 | 761 | |||
762 | bool | 762 | bool | |
763 | uhci_suspend(device_t dv, const pmf_qual_t *qual) | 763 | uhci_suspend(device_t dv, const pmf_qual_t *qual) | |
764 | { | 764 | { | |
765 | uhci_softc_t *sc = device_private(dv); | 765 | uhci_softc_t *sc = device_private(dv); | |
766 | int cmd; | 766 | int cmd; | |
767 | 767 | |||
768 | mutex_spin_enter(&sc->sc_intr_lock); | 768 | mutex_spin_enter(&sc->sc_intr_lock); | |
769 | 769 | |||
770 | cmd = UREAD2(sc, UHCI_CMD); | 770 | cmd = UREAD2(sc, UHCI_CMD); | |
771 | 771 | |||
772 | #ifdef UHCI_DEBUG | 772 | #ifdef UHCI_DEBUG | |
773 | if (uhcidebug > 2) | 773 | if (uhcidebug > 2) | |
774 | uhci_dumpregs(sc); | 774 | uhci_dumpregs(sc); | |
775 | #endif | 775 | #endif | |
776 | if (sc->sc_intr_xfer != NULL) | 776 | if (sc->sc_intr_xfer != NULL) | |
777 | callout_stop(&sc->sc_poll_handle); | 777 | callout_stop(&sc->sc_poll_handle); | |
778 | sc->sc_suspend = PWR_SUSPEND; | 778 | sc->sc_suspend = PWR_SUSPEND; | |
779 | sc->sc_bus.use_polling++; | 779 | sc->sc_bus.use_polling++; | |
780 | 780 | |||
781 | uhci_run(sc, 0); /* stop the controller */ | 781 | uhci_run(sc, 0); /* stop the controller */ | |
782 | cmd &= ~UHCI_CMD_RS; | 782 | cmd &= ~UHCI_CMD_RS; | |
783 | 783 | |||
784 | /* save some state if BIOS doesn't */ | 784 | /* save some state if BIOS doesn't */ | |
785 | sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM); | 785 | sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM); | |
786 | sc->sc_saved_sof = UREAD1(sc, UHCI_SOF); | 786 | sc->sc_saved_sof = UREAD1(sc, UHCI_SOF); | |
787 | 787 | |||
788 | UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */ | 788 | UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */ | |
789 | 789 | |||
790 | UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter suspend */ | 790 | UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter suspend */ | |
791 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); | 791 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); | |
792 | sc->sc_bus.use_polling--; | 792 | sc->sc_bus.use_polling--; | |
793 | 793 | |||
794 | mutex_spin_exit(&sc->sc_intr_lock); | 794 | mutex_spin_exit(&sc->sc_intr_lock); | |
795 | 795 | |||
796 | return true; | 796 | return true; | |
797 | } | 797 | } | |
798 | 798 | |||
799 | #ifdef UHCI_DEBUG | 799 | #ifdef UHCI_DEBUG | |
800 | Static void | 800 | Static void | |
801 | uhci_dumpregs(uhci_softc_t *sc) | 801 | uhci_dumpregs(uhci_softc_t *sc) | |
802 | { | 802 | { | |
803 | DPRINTFN(-1,("%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, " | 803 | DPRINTFN(-1,("%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, " | |
804 | "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n", | 804 | "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n", | |
805 | device_xname(sc->sc_dev), | 805 | device_xname(sc->sc_dev), | |
806 | UREAD2(sc, UHCI_CMD), | 806 | UREAD2(sc, UHCI_CMD), | |
807 | UREAD2(sc, UHCI_STS), | 807 | UREAD2(sc, UHCI_STS), | |
808 | UREAD2(sc, UHCI_INTR), | 808 | UREAD2(sc, UHCI_INTR), | |
809 | UREAD2(sc, UHCI_FRNUM), | 809 | UREAD2(sc, UHCI_FRNUM), | |
810 | UREAD4(sc, UHCI_FLBASEADDR), | 810 | UREAD4(sc, UHCI_FLBASEADDR), | |
811 | UREAD1(sc, UHCI_SOF), | 811 | UREAD1(sc, UHCI_SOF), | |
812 | UREAD2(sc, UHCI_PORTSC1), | 812 | UREAD2(sc, UHCI_PORTSC1), | |
813 | UREAD2(sc, UHCI_PORTSC2))); | 813 | UREAD2(sc, UHCI_PORTSC2))); | |
814 | } | 814 | } | |
815 | 815 | |||
816 | void | 816 | void | |
817 | uhci_dump_td(uhci_soft_td_t *p) | 817 | uhci_dump_td(uhci_soft_td_t *p) | |
818 | { | 818 | { | |
819 | char sbuf[128], sbuf2[128]; | 819 | char sbuf[128], sbuf2[128]; | |
820 | 820 | |||
821 | 821 | |||
822 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), | 822 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), | |
823 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 823 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
824 | DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx " | 824 | DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx " | |
825 | "token=0x%08lx buffer=0x%08lx\n", | 825 | "token=0x%08lx buffer=0x%08lx\n", | |
826 | p, (long)p->physaddr, | 826 | p, (long)p->physaddr, | |
827 | (long)le32toh(p->td.td_link), | 827 | (long)le32toh(p->td.td_link), | |
828 | (long)le32toh(p->td.td_status), | 828 | (long)le32toh(p->td.td_status), | |
829 | (long)le32toh(p->td.td_token), | 829 | (long)le32toh(p->td.td_token), | |
830 | (long)le32toh(p->td.td_buffer))); | 830 | (long)le32toh(p->td.td_buffer))); | |
831 | 831 | |||
832 | snprintb(sbuf, sizeof(sbuf), "\20\1T\2Q\3VF", | 832 | snprintb(sbuf, sizeof(sbuf), "\20\1T\2Q\3VF", | |
833 | (u_int32_t)le32toh(p->td.td_link)); | 833 | (u_int32_t)le32toh(p->td.td_link)); | |
834 | snprintb(sbuf2, sizeof(sbuf2), | 834 | snprintb(sbuf2, sizeof(sbuf2), | |
835 | "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27" | 835 | "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27" | |
836 | "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD", | 836 | "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD", | |
837 | (u_int32_t)le32toh(p->td.td_status)); | 837 | (u_int32_t)le32toh(p->td.td_status)); | |
838 | 838 | |||
839 | DPRINTFN(-1,(" %s %s,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d," | 839 | DPRINTFN(-1,(" %s %s,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d," | |
840 | "D=%d,maxlen=%d\n", sbuf, sbuf2, | 840 | "D=%d,maxlen=%d\n", sbuf, sbuf2, | |
841 | UHCI_TD_GET_ERRCNT(le32toh(p->td.td_status)), | 841 | UHCI_TD_GET_ERRCNT(le32toh(p->td.td_status)), | |
842 | UHCI_TD_GET_ACTLEN(le32toh(p->td.td_status)), | 842 | UHCI_TD_GET_ACTLEN(le32toh(p->td.td_status)), | |
843 | UHCI_TD_GET_PID(le32toh(p->td.td_token)), | 843 | UHCI_TD_GET_PID(le32toh(p->td.td_token)), | |
844 | UHCI_TD_GET_DEVADDR(le32toh(p->td.td_token)), | 844 | UHCI_TD_GET_DEVADDR(le32toh(p->td.td_token)), | |
845 | UHCI_TD_GET_ENDPT(le32toh(p->td.td_token)), | 845 | UHCI_TD_GET_ENDPT(le32toh(p->td.td_token)), | |
846 | UHCI_TD_GET_DT(le32toh(p->td.td_token)), | 846 | UHCI_TD_GET_DT(le32toh(p->td.td_token)), | |
847 | UHCI_TD_GET_MAXLEN(le32toh(p->td.td_token)))); | 847 | UHCI_TD_GET_MAXLEN(le32toh(p->td.td_token)))); | |
848 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), | 848 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), | |
849 | BUS_DMASYNC_PREREAD); | 849 | BUS_DMASYNC_PREREAD); | |
850 | } | 850 | } | |
851 | 851 | |||
852 | void | 852 | void | |
853 | uhci_dump_qh(uhci_soft_qh_t *sqh) | 853 | uhci_dump_qh(uhci_soft_qh_t *sqh) | |
854 | { | 854 | { | |
855 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 855 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
856 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 856 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
857 | DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh, | 857 | DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh, | |
858 | (int)sqh->physaddr, le32toh(sqh->qh.qh_hlink), | 858 | (int)sqh->physaddr, le32toh(sqh->qh.qh_hlink), | |
859 | le32toh(sqh->qh.qh_elink))); | 859 | le32toh(sqh->qh.qh_elink))); | |
860 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), BUS_DMASYNC_PREREAD); | 860 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), BUS_DMASYNC_PREREAD); | |
861 | } | 861 | } | |
862 | 862 | |||
863 | 863 | |||
864 | #if 1 | 864 | #if 1 | |
865 | void | 865 | void | |
866 | uhci_dump(void) | 866 | uhci_dump(void) | |
867 | { | 867 | { | |
868 | uhci_dump_all(thesc); | 868 | uhci_dump_all(thesc); | |
869 | } | 869 | } | |
870 | #endif | 870 | #endif | |
871 | 871 | |||
872 | void | 872 | void | |
873 | uhci_dump_all(uhci_softc_t *sc) | 873 | uhci_dump_all(uhci_softc_t *sc) | |
874 | { | 874 | { | |
875 | uhci_dumpregs(sc); | 875 | uhci_dumpregs(sc); | |
876 | printf("intrs=%d\n", sc->sc_bus.no_intrs); | 876 | printf("intrs=%d\n", sc->sc_bus.no_intrs); | |
877 | /*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/ | 877 | /*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/ | |
878 | uhci_dump_qh(sc->sc_lctl_start); | 878 | uhci_dump_qh(sc->sc_lctl_start); | |
879 | } | 879 | } | |
880 | 880 | |||
881 | 881 | |||
882 | void | 882 | void | |
883 | uhci_dump_qhs(uhci_soft_qh_t *sqh) | 883 | uhci_dump_qhs(uhci_soft_qh_t *sqh) | |
884 | { | 884 | { | |
885 | uhci_dump_qh(sqh); | 885 | uhci_dump_qh(sqh); | |
886 | 886 | |||
887 | /* uhci_dump_qhs displays all the QHs and TDs from the given QH onwards | 887 | /* uhci_dump_qhs displays all the QHs and TDs from the given QH onwards | |
888 | * Traverses sideways first, then down. | 888 | * Traverses sideways first, then down. | |
889 | * | 889 | * | |
890 | * QH1 | 890 | * QH1 | |
891 | * QH2 | 891 | * QH2 | |
892 | * No QH | 892 | * No QH | |
893 | * TD2.1 | 893 | * TD2.1 | |
894 | * TD2.2 | 894 | * TD2.2 | |
895 | * TD1.1 | 895 | * TD1.1 | |
896 | * etc. | 896 | * etc. | |
897 | * | 897 | * | |
898 | * TD2.x being the TDs queued at QH2 and QH1 being referenced from QH1. | 898 | * TD2.x being the TDs queued at QH2 and QH1 being referenced from QH1. | |
899 | */ | 899 | */ | |
900 | 900 | |||
901 | 901 | |||
902 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 902 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
903 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 903 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
904 | if (sqh->hlink != NULL && !(le32toh(sqh->qh.qh_hlink) & UHCI_PTR_T)) | 904 | if (sqh->hlink != NULL && !(le32toh(sqh->qh.qh_hlink) & UHCI_PTR_T)) | |
905 | uhci_dump_qhs(sqh->hlink); | 905 | uhci_dump_qhs(sqh->hlink); | |
906 | else | 906 | else | |
907 | DPRINTF(("No QH\n")); | 907 | DPRINTF(("No QH\n")); | |
908 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), BUS_DMASYNC_PREREAD); | 908 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), BUS_DMASYNC_PREREAD); | |
909 | 909 | |||
910 | if (sqh->elink != NULL && !(le32toh(sqh->qh.qh_elink) & UHCI_PTR_T)) | 910 | if (sqh->elink != NULL && !(le32toh(sqh->qh.qh_elink) & UHCI_PTR_T)) | |
911 | uhci_dump_tds(sqh->elink); | 911 | uhci_dump_tds(sqh->elink); | |
912 | else | 912 | else | |
913 | DPRINTF(("No TD\n")); | 913 | DPRINTF(("No TD\n")); | |
914 | } | 914 | } | |
915 | 915 | |||
916 | void | 916 | void | |
917 | uhci_dump_tds(uhci_soft_td_t *std) | 917 | uhci_dump_tds(uhci_soft_td_t *std) | |
918 | { | 918 | { | |
919 | uhci_soft_td_t *td; | 919 | uhci_soft_td_t *td; | |
920 | int stop; | 920 | int stop; | |
921 | 921 | |||
922 | for(td = std; td != NULL; td = td->link.std) { | 922 | for(td = std; td != NULL; td = td->link.std) { | |
923 | uhci_dump_td(td); | 923 | uhci_dump_td(td); | |
924 | 924 | |||
925 | /* Check whether the link pointer in this TD marks | 925 | /* Check whether the link pointer in this TD marks | |
926 | * the link pointer as end of queue. This avoids | 926 | * the link pointer as end of queue. This avoids | |
927 | * printing the free list in case the queue/TD has | 927 | * printing the free list in case the queue/TD has | |
928 | * already been moved there (seatbelt). | 928 | * already been moved there (seatbelt). | |
929 | */ | 929 | */ | |
930 | usb_syncmem(&td->dma, td->offs + offsetof(uhci_td_t, td_link), | 930 | usb_syncmem(&td->dma, td->offs + offsetof(uhci_td_t, td_link), | |
931 | sizeof(td->td.td_link), | 931 | sizeof(td->td.td_link), | |
932 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 932 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
933 | stop = (le32toh(td->td.td_link) & UHCI_PTR_T || | 933 | stop = (le32toh(td->td.td_link) & UHCI_PTR_T || | |
934 | le32toh(td->td.td_link) == 0); | 934 | le32toh(td->td.td_link) == 0); | |
935 | usb_syncmem(&td->dma, td->offs + offsetof(uhci_td_t, td_link), | 935 | usb_syncmem(&td->dma, td->offs + offsetof(uhci_td_t, td_link), | |
936 | sizeof(td->td.td_link), BUS_DMASYNC_PREREAD); | 936 | sizeof(td->td.td_link), BUS_DMASYNC_PREREAD); | |
937 | if (stop) | 937 | if (stop) | |
938 | break; | 938 | break; | |
939 | } | 939 | } | |
940 | } | 940 | } | |
941 | 941 | |||
942 | Static void | 942 | Static void | |
943 | uhci_dump_ii(uhci_intr_info_t *ii) | 943 | uhci_dump_ii(uhci_intr_info_t *ii) | |
944 | { | 944 | { | |
945 | usbd_pipe_handle pipe; | 945 | usbd_pipe_handle pipe; | |
946 | usb_endpoint_descriptor_t *ed; | 946 | usb_endpoint_descriptor_t *ed; | |
947 | usbd_device_handle dev; | 947 | usbd_device_handle dev; | |
948 | 948 | |||
949 | #ifdef DIAGNOSTIC | 949 | #ifdef DIAGNOSTIC | |
950 | #define DONE ii->isdone | 950 | #define DONE ii->isdone | |
951 | #else | 951 | #else | |
952 | #define DONE 0 | 952 | #define DONE 0 | |
953 | #endif | 953 | #endif | |
954 | if (ii == NULL) { | 954 | if (ii == NULL) { | |
955 | printf("ii NULL\n"); | 955 | printf("ii NULL\n"); | |
956 | return; | 956 | return; | |
957 | } | 957 | } | |
958 | if (ii->xfer == NULL) { | 958 | if (ii->xfer == NULL) { | |
959 | printf("ii %p: done=%d xfer=NULL\n", | 959 | printf("ii %p: done=%d xfer=NULL\n", | |
960 | ii, DONE); | 960 | ii, DONE); | |
961 | return; | 961 | return; | |
962 | } | 962 | } | |
963 | pipe = ii->xfer->pipe; | 963 | pipe = ii->xfer->pipe; | |
964 | if (pipe == NULL) { | 964 | if (pipe == NULL) { | |
965 | printf("ii %p: done=%d xfer=%p pipe=NULL\n", | 965 | printf("ii %p: done=%d xfer=%p pipe=NULL\n", | |
966 | ii, DONE, ii->xfer); | 966 | ii, DONE, ii->xfer); | |
967 | return; | 967 | return; | |
968 | } | 968 | } | |
969 | if (pipe->endpoint == NULL) { | 969 | if (pipe->endpoint == NULL) { | |
970 | printf("ii %p: done=%d xfer=%p pipe=%p pipe->endpoint=NULL\n", | 970 | printf("ii %p: done=%d xfer=%p pipe=%p pipe->endpoint=NULL\n", | |
971 | ii, DONE, ii->xfer, pipe); | 971 | ii, DONE, ii->xfer, pipe); | |
972 | return; | 972 | return; | |
973 | } | 973 | } | |
974 | if (pipe->device == NULL) { | 974 | if (pipe->device == NULL) { | |
975 | printf("ii %p: done=%d xfer=%p pipe=%p pipe->device=NULL\n", | 975 | printf("ii %p: done=%d xfer=%p pipe=%p pipe->device=NULL\n", | |
976 | ii, DONE, ii->xfer, pipe); | 976 | ii, DONE, ii->xfer, pipe); | |
977 | return; | 977 | return; | |
978 | } | 978 | } | |
979 | ed = pipe->endpoint->edesc; | 979 | ed = pipe->endpoint->edesc; | |
980 | dev = pipe->device; | 980 | dev = pipe->device; | |
981 | 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", | 981 | 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", | |
982 | ii, DONE, ii->xfer, dev, | 982 | ii, DONE, ii->xfer, dev, | |
983 | UGETW(dev->ddesc.idVendor), | 983 | UGETW(dev->ddesc.idVendor), | |
984 | UGETW(dev->ddesc.idProduct), | 984 | UGETW(dev->ddesc.idProduct), | |
985 | dev->address, pipe, | 985 | dev->address, pipe, | |
986 | ed->bEndpointAddress, ed->bmAttributes); | 986 | ed->bEndpointAddress, ed->bmAttributes); | |
987 | #undef DONE | 987 | #undef DONE | |
988 | } | 988 | } | |
989 | 989 | |||
990 | void uhci_dump_iis(struct uhci_softc *sc); | 990 | void uhci_dump_iis(struct uhci_softc *sc); | |
991 | void | 991 | void | |
992 | uhci_dump_iis(struct uhci_softc *sc) | 992 | uhci_dump_iis(struct uhci_softc *sc) | |
993 | { | 993 | { | |
994 | uhci_intr_info_t *ii; | 994 | uhci_intr_info_t *ii; | |
995 | 995 | |||
996 | printf("intr_info list:\n"); | 996 | printf("intr_info list:\n"); | |
997 | for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list)) | 997 | for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list)) | |
998 | uhci_dump_ii(ii); | 998 | uhci_dump_ii(ii); | |
999 | } | 999 | } | |
1000 | 1000 | |||
1001 | void iidump(void); | 1001 | void iidump(void); | |
1002 | void iidump(void) { uhci_dump_iis(thesc); } | 1002 | void iidump(void) { uhci_dump_iis(thesc); } | |
1003 | 1003 | |||
1004 | #endif | 1004 | #endif | |
1005 | 1005 | |||
1006 | /* | 1006 | /* | |
1007 | * This routine is executed periodically and simulates interrupts | 1007 | * This routine is executed periodically and simulates interrupts | |
1008 | * from the root controller interrupt pipe for port status change. | 1008 | * from the root controller interrupt pipe for port status change. | |
1009 | */ | 1009 | */ | |
1010 | void | 1010 | void | |
1011 | uhci_poll_hub(void *addr) | 1011 | uhci_poll_hub(void *addr) | |
1012 | { | 1012 | { | |
1013 | usbd_xfer_handle xfer = addr; | 1013 | usbd_xfer_handle xfer = addr; | |
1014 | usbd_pipe_handle pipe = xfer->pipe; | 1014 | usbd_pipe_handle pipe = xfer->pipe; | |
1015 | uhci_softc_t *sc; | 1015 | uhci_softc_t *sc; | |
1016 | u_char *p; | 1016 | u_char *p; | |
1017 | 1017 | |||
1018 | DPRINTFN(20, ("uhci_poll_hub\n")); | 1018 | DPRINTFN(20, ("uhci_poll_hub\n")); | |
1019 | 1019 | |||
1020 | if (__predict_false(pipe->device == NULL || pipe->device->bus == NULL)) | 1020 | if (__predict_false(pipe->device == NULL || pipe->device->bus == NULL)) | |
1021 | return; /* device has detached */ | 1021 | return; /* device has detached */ | |
1022 | sc = pipe->device->bus->hci_private; | 1022 | sc = pipe->device->bus->hci_private; | |
1023 | callout_reset(&sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer); | 1023 | callout_reset(&sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer); | |
1024 | 1024 | |||
1025 | p = KERNADDR(&xfer->dmabuf, 0); | 1025 | p = KERNADDR(&xfer->dmabuf, 0); | |
1026 | p[0] = 0; | 1026 | p[0] = 0; | |
1027 | if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC)) | 1027 | if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC)) | |
1028 | p[0] |= 1<<1; | 1028 | p[0] |= 1<<1; | |
1029 | if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC)) | 1029 | if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC)) | |
1030 | p[0] |= 1<<2; | 1030 | p[0] |= 1<<2; | |
1031 | if (p[0] == 0) | 1031 | if (p[0] == 0) | |
1032 | /* No change, try again in a while */ | 1032 | /* No change, try again in a while */ | |
1033 | return; | 1033 | return; | |
1034 | 1034 | |||
1035 | xfer->actlen = 1; | 1035 | xfer->actlen = 1; | |
1036 | xfer->status = USBD_NORMAL_COMPLETION; | 1036 | xfer->status = USBD_NORMAL_COMPLETION; | |
1037 | mutex_enter(&sc->sc_lock); | 1037 | mutex_enter(&sc->sc_lock); | |
1038 | xfer->device->bus->intr_context++; | 1038 | xfer->device->bus->intr_context++; | |
1039 | usb_transfer_complete(xfer); | 1039 | usb_transfer_complete(xfer); | |
1040 | xfer->device->bus->intr_context--; | 1040 | xfer->device->bus->intr_context--; | |
1041 | mutex_exit(&sc->sc_lock); | 1041 | mutex_exit(&sc->sc_lock); | |
1042 | } | 1042 | } | |
1043 | 1043 | |||
1044 | void | 1044 | void | |
1045 | uhci_root_intr_done(usbd_xfer_handle xfer) | 1045 | uhci_root_intr_done(usbd_xfer_handle xfer) | |
1046 | { | 1046 | { | |
1047 | } | 1047 | } | |
1048 | 1048 | |||
1049 | void | 1049 | void | |
1050 | uhci_root_ctrl_done(usbd_xfer_handle xfer) | 1050 | uhci_root_ctrl_done(usbd_xfer_handle xfer) | |
1051 | { | 1051 | { | |
1052 | } | 1052 | } | |
1053 | 1053 | |||
1054 | /* | 1054 | /* | |
1055 | * Let the last QH loop back to the high speed control transfer QH. | 1055 | * Let the last QH loop back to the high speed control transfer QH. | |
1056 | * This is what intel calls "bandwidth reclamation" and improves | 1056 | * This is what intel calls "bandwidth reclamation" and improves | |
1057 | * USB performance a lot for some devices. | 1057 | * USB performance a lot for some devices. | |
1058 | * If we are already looping, just count it. | 1058 | * If we are already looping, just count it. | |
1059 | */ | 1059 | */ | |
1060 | void | 1060 | void | |
1061 | uhci_add_loop(uhci_softc_t *sc) { | 1061 | uhci_add_loop(uhci_softc_t *sc) { | |
1062 | #ifdef UHCI_DEBUG | 1062 | #ifdef UHCI_DEBUG | |
1063 | if (uhcinoloop) | 1063 | if (uhcinoloop) | |
1064 | return; | 1064 | return; | |
1065 | #endif | 1065 | #endif | |
1066 | if (++sc->sc_loops == 1) { | 1066 | if (++sc->sc_loops == 1) { | |
1067 | DPRINTFN(5,("uhci_start_loop: add\n")); | 1067 | DPRINTFN(5,("uhci_start_loop: add\n")); | |
1068 | /* Note, we don't loop back the soft pointer. */ | 1068 | /* Note, we don't loop back the soft pointer. */ | |
1069 | sc->sc_last_qh->qh.qh_hlink = | 1069 | sc->sc_last_qh->qh.qh_hlink = | |
1070 | htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH); | 1070 | htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH); | |
1071 | usb_syncmem(&sc->sc_last_qh->dma, | 1071 | usb_syncmem(&sc->sc_last_qh->dma, | |
1072 | sc->sc_last_qh->offs + offsetof(uhci_qh_t, qh_hlink), | 1072 | sc->sc_last_qh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1073 | sizeof(sc->sc_last_qh->qh.qh_hlink), | 1073 | sizeof(sc->sc_last_qh->qh.qh_hlink), | |
1074 | BUS_DMASYNC_PREWRITE); | 1074 | BUS_DMASYNC_PREWRITE); | |
1075 | } | 1075 | } | |
1076 | } | 1076 | } | |
1077 | 1077 | |||
1078 | void | 1078 | void | |
1079 | uhci_rem_loop(uhci_softc_t *sc) { | 1079 | uhci_rem_loop(uhci_softc_t *sc) { | |
1080 | #ifdef UHCI_DEBUG | 1080 | #ifdef UHCI_DEBUG | |
1081 | if (uhcinoloop) | 1081 | if (uhcinoloop) | |
1082 | return; | 1082 | return; | |
1083 | #endif | 1083 | #endif | |
1084 | if (--sc->sc_loops == 0) { | 1084 | if (--sc->sc_loops == 0) { | |
1085 | DPRINTFN(5,("uhci_end_loop: remove\n")); | 1085 | DPRINTFN(5,("uhci_end_loop: remove\n")); | |
1086 | sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T); | 1086 | sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T); | |
1087 | usb_syncmem(&sc->sc_last_qh->dma, | 1087 | usb_syncmem(&sc->sc_last_qh->dma, | |
1088 | sc->sc_last_qh->offs + offsetof(uhci_qh_t, qh_hlink), | 1088 | sc->sc_last_qh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1089 | sizeof(sc->sc_last_qh->qh.qh_hlink), | 1089 | sizeof(sc->sc_last_qh->qh.qh_hlink), | |
1090 | BUS_DMASYNC_PREWRITE); | 1090 | BUS_DMASYNC_PREWRITE); | |
1091 | } | 1091 | } | |
1092 | } | 1092 | } | |
1093 | 1093 | |||
1094 | /* Add high speed control QH, called at splusb(). */ | 1094 | /* Add high speed control QH, called at splusb(). */ | |
1095 | void | 1095 | void | |
1096 | uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | 1096 | uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | |
1097 | { | 1097 | { | |
1098 | uhci_soft_qh_t *eqh; | 1098 | uhci_soft_qh_t *eqh; | |
1099 | 1099 | |||
1100 | SPLUSBCHECK; | 1100 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1101 | 1101 | |||
1102 | DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh)); | 1102 | DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh)); | |
1103 | eqh = sc->sc_hctl_end; | 1103 | eqh = sc->sc_hctl_end; | |
1104 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1104 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1105 | sizeof(eqh->qh.qh_hlink), | 1105 | sizeof(eqh->qh.qh_hlink), | |
1106 | BUS_DMASYNC_POSTWRITE); | 1106 | BUS_DMASYNC_POSTWRITE); | |
1107 | sqh->hlink = eqh->hlink; | 1107 | sqh->hlink = eqh->hlink; | |
1108 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; | 1108 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; | |
1109 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 1109 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
1110 | BUS_DMASYNC_PREWRITE); | 1110 | BUS_DMASYNC_PREWRITE); | |
1111 | eqh->hlink = sqh; | 1111 | eqh->hlink = sqh; | |
1112 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); | 1112 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); | |
1113 | sc->sc_hctl_end = sqh; | 1113 | sc->sc_hctl_end = sqh; | |
1114 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1114 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1115 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | 1115 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | |
1116 | #ifdef UHCI_CTL_LOOP | 1116 | #ifdef UHCI_CTL_LOOP | |
1117 | uhci_add_loop(sc); | 1117 | uhci_add_loop(sc); | |
1118 | #endif | 1118 | #endif | |
1119 | } | 1119 | } | |
1120 | 1120 | |||
1121 | /* Remove high speed control QH, called at splusb(). */ | 1121 | /* Remove high speed control QH, called at splusb(). */ | |
1122 | void | 1122 | void | |
1123 | uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | 1123 | uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | |
1124 | { | 1124 | { | |
1125 | uhci_soft_qh_t *pqh; | 1125 | uhci_soft_qh_t *pqh; | |
1126 | 1126 | |||
1127 | SPLUSBCHECK; | 1127 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1128 | 1128 | |||
1129 | DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh)); | 1129 | DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh)); | |
1130 | #ifdef UHCI_CTL_LOOP | 1130 | #ifdef UHCI_CTL_LOOP | |
1131 | uhci_rem_loop(sc); | 1131 | uhci_rem_loop(sc); | |
1132 | #endif | 1132 | #endif | |
1133 | /* | 1133 | /* | |
1134 | * The T bit should be set in the elink of the QH so that the HC | 1134 | * The T bit should be set in the elink of the QH so that the HC | |
1135 | * doesn't follow the pointer. This condition may fail if the | 1135 | * doesn't follow the pointer. This condition may fail if the | |
1136 | * the transferred packet was short so that the QH still points | 1136 | * the transferred packet was short so that the QH still points | |
1137 | * at the last used TD. | 1137 | * at the last used TD. | |
1138 | * In this case we set the T bit and wait a little for the HC | 1138 | * In this case we set the T bit and wait a little for the HC | |
1139 | * to stop looking at the TD. | 1139 | * to stop looking at the TD. | |
1140 | * Note that if the TD chain is large enough, the controller | 1140 | * Note that if the TD chain is large enough, the controller | |
1141 | * may still be looking at the chain at the end of this function. | 1141 | * may still be looking at the chain at the end of this function. | |
1142 | * uhci_free_std_chain() will make sure the controller stops | 1142 | * uhci_free_std_chain() will make sure the controller stops | |
1143 | * looking at it quickly, but until then we should not change | 1143 | * looking at it quickly, but until then we should not change | |
1144 | * sqh->hlink. | 1144 | * sqh->hlink. | |
1145 | */ | 1145 | */ | |
1146 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), | 1146 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), | |
1147 | sizeof(sqh->qh.qh_elink), | 1147 | sizeof(sqh->qh.qh_elink), | |
1148 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1148 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1149 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { | 1149 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { | |
1150 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | 1150 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | |
1151 | usb_syncmem(&sqh->dma, | 1151 | usb_syncmem(&sqh->dma, | |
1152 | sqh->offs + offsetof(uhci_qh_t, qh_elink), | 1152 | sqh->offs + offsetof(uhci_qh_t, qh_elink), | |
1153 | sizeof(sqh->qh.qh_elink), | 1153 | sizeof(sqh->qh.qh_elink), | |
1154 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1154 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1155 | delay(UHCI_QH_REMOVE_DELAY); | 1155 | delay(UHCI_QH_REMOVE_DELAY); | |
1156 | } | 1156 | } | |
1157 | 1157 | |||
1158 | pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh); | 1158 | pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh); | |
1159 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1159 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1160 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | 1160 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | |
1161 | pqh->hlink = sqh->hlink; | 1161 | pqh->hlink = sqh->hlink; | |
1162 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; | 1162 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; | |
1163 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1163 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1164 | sizeof(pqh->qh.qh_hlink), | 1164 | sizeof(pqh->qh.qh_hlink), | |
1165 | BUS_DMASYNC_PREWRITE); | 1165 | BUS_DMASYNC_PREWRITE); | |
1166 | delay(UHCI_QH_REMOVE_DELAY); | 1166 | delay(UHCI_QH_REMOVE_DELAY); | |
1167 | if (sc->sc_hctl_end == sqh) | 1167 | if (sc->sc_hctl_end == sqh) | |
1168 | sc->sc_hctl_end = pqh; | 1168 | sc->sc_hctl_end = pqh; | |
1169 | } | 1169 | } | |
1170 | 1170 | |||
1171 | /* Add low speed control QH, called at splusb(). */ | 1171 | /* Add low speed control QH, called at splusb(). */ | |
1172 | void | 1172 | void | |
1173 | uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | 1173 | uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | |
1174 | { | 1174 | { | |
1175 | uhci_soft_qh_t *eqh; | 1175 | uhci_soft_qh_t *eqh; | |
1176 | 1176 | |||
1177 | SPLUSBCHECK; | 1177 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1178 | 1178 | |||
1179 | DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh)); | 1179 | DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh)); | |
1180 | eqh = sc->sc_lctl_end; | 1180 | eqh = sc->sc_lctl_end; | |
1181 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1181 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1182 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | 1182 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | |
1183 | sqh->hlink = eqh->hlink; | 1183 | sqh->hlink = eqh->hlink; | |
1184 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; | 1184 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; | |
1185 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 1185 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
1186 | BUS_DMASYNC_PREWRITE); | 1186 | BUS_DMASYNC_PREWRITE); | |
1187 | eqh->hlink = sqh; | 1187 | eqh->hlink = sqh; | |
1188 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); | 1188 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); | |
1189 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1189 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1190 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | 1190 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | |
1191 | sc->sc_lctl_end = sqh; | 1191 | sc->sc_lctl_end = sqh; | |
1192 | } | 1192 | } | |
1193 | 1193 | |||
1194 | /* Remove low speed control QH, called at splusb(). */ | 1194 | /* Remove low speed control QH, called at splusb(). */ | |
1195 | void | 1195 | void | |
1196 | uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | 1196 | uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | |
1197 | { | 1197 | { | |
1198 | uhci_soft_qh_t *pqh; | 1198 | uhci_soft_qh_t *pqh; | |
1199 | 1199 | |||
1200 | SPLUSBCHECK; | 1200 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1201 | 1201 | |||
1202 | DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh)); | 1202 | DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh)); | |
1203 | /* See comment in uhci_remove_hs_ctrl() */ | 1203 | /* See comment in uhci_remove_hs_ctrl() */ | |
1204 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), | 1204 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), | |
1205 | sizeof(sqh->qh.qh_elink), | 1205 | sizeof(sqh->qh.qh_elink), | |
1206 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1206 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1207 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { | 1207 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { | |
1208 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | 1208 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | |
1209 | usb_syncmem(&sqh->dma, | 1209 | usb_syncmem(&sqh->dma, | |
1210 | sqh->offs + offsetof(uhci_qh_t, qh_elink), | 1210 | sqh->offs + offsetof(uhci_qh_t, qh_elink), | |
1211 | sizeof(sqh->qh.qh_elink), | 1211 | sizeof(sqh->qh.qh_elink), | |
1212 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1212 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1213 | delay(UHCI_QH_REMOVE_DELAY); | 1213 | delay(UHCI_QH_REMOVE_DELAY); | |
1214 | } | 1214 | } | |
1215 | pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh); | 1215 | pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh); | |
1216 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1216 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1217 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | 1217 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | |
1218 | pqh->hlink = sqh->hlink; | 1218 | pqh->hlink = sqh->hlink; | |
1219 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; | 1219 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; | |
1220 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1220 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1221 | sizeof(pqh->qh.qh_hlink), | 1221 | sizeof(pqh->qh.qh_hlink), | |
1222 | BUS_DMASYNC_PREWRITE); | 1222 | BUS_DMASYNC_PREWRITE); | |
1223 | delay(UHCI_QH_REMOVE_DELAY); | 1223 | delay(UHCI_QH_REMOVE_DELAY); | |
1224 | if (sc->sc_lctl_end == sqh) | 1224 | if (sc->sc_lctl_end == sqh) | |
1225 | sc->sc_lctl_end = pqh; | 1225 | sc->sc_lctl_end = pqh; | |
1226 | } | 1226 | } | |
1227 | 1227 | |||
1228 | /* Add bulk QH, called at splusb(). */ | 1228 | /* Add bulk QH, called at splusb(). */ | |
1229 | void | 1229 | void | |
1230 | uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | 1230 | uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | |
1231 | { | 1231 | { | |
1232 | uhci_soft_qh_t *eqh; | 1232 | uhci_soft_qh_t *eqh; | |
1233 | 1233 | |||
1234 | SPLUSBCHECK; | 1234 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1235 | 1235 | |||
1236 | DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh)); | 1236 | DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh)); | |
1237 | eqh = sc->sc_bulk_end; | 1237 | eqh = sc->sc_bulk_end; | |
1238 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1238 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1239 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | 1239 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | |
1240 | sqh->hlink = eqh->hlink; | 1240 | sqh->hlink = eqh->hlink; | |
1241 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; | 1241 | sqh->qh.qh_hlink = eqh->qh.qh_hlink; | |
1242 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | 1242 | usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh), | |
1243 | BUS_DMASYNC_PREWRITE); | 1243 | BUS_DMASYNC_PREWRITE); | |
1244 | eqh->hlink = sqh; | 1244 | eqh->hlink = sqh; | |
1245 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); | 1245 | eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); | |
1246 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1246 | usb_syncmem(&eqh->dma, eqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1247 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | 1247 | sizeof(eqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | |
1248 | sc->sc_bulk_end = sqh; | 1248 | sc->sc_bulk_end = sqh; | |
1249 | uhci_add_loop(sc); | 1249 | uhci_add_loop(sc); | |
1250 | } | 1250 | } | |
1251 | 1251 | |||
1252 | /* Remove bulk QH, called at splusb(). */ | 1252 | /* Remove bulk QH, called at splusb(). */ | |
1253 | void | 1253 | void | |
1254 | uhci_remove_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | 1254 | uhci_remove_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | |
1255 | { | 1255 | { | |
1256 | uhci_soft_qh_t *pqh; | 1256 | uhci_soft_qh_t *pqh; | |
1257 | 1257 | |||
1258 | SPLUSBCHECK; | 1258 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1259 | 1259 | |||
1260 | DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh)); | 1260 | DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh)); | |
1261 | uhci_rem_loop(sc); | 1261 | uhci_rem_loop(sc); | |
1262 | /* See comment in uhci_remove_hs_ctrl() */ | 1262 | /* See comment in uhci_remove_hs_ctrl() */ | |
1263 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), | 1263 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_elink), | |
1264 | sizeof(sqh->qh.qh_elink), | 1264 | sizeof(sqh->qh.qh_elink), | |
1265 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1265 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1266 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { | 1266 | if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { | |
1267 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | 1267 | sqh->qh.qh_elink = htole32(UHCI_PTR_T); | |
1268 | usb_syncmem(&sqh->dma, | 1268 | usb_syncmem(&sqh->dma, | |
1269 | sqh->offs + offsetof(uhci_qh_t, qh_elink), | 1269 | sqh->offs + offsetof(uhci_qh_t, qh_elink), | |
1270 | sizeof(sqh->qh.qh_elink), | 1270 | sizeof(sqh->qh.qh_elink), | |
1271 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1271 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1272 | delay(UHCI_QH_REMOVE_DELAY); | 1272 | delay(UHCI_QH_REMOVE_DELAY); | |
1273 | } | 1273 | } | |
1274 | pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh); | 1274 | pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh); | |
1275 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1275 | usb_syncmem(&sqh->dma, sqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1276 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | 1276 | sizeof(sqh->qh.qh_hlink), BUS_DMASYNC_POSTWRITE); | |
1277 | pqh->hlink = sqh->hlink; | 1277 | pqh->hlink = sqh->hlink; | |
1278 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; | 1278 | pqh->qh.qh_hlink = sqh->qh.qh_hlink; | |
1279 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), | 1279 | usb_syncmem(&pqh->dma, pqh->offs + offsetof(uhci_qh_t, qh_hlink), | |
1280 | sizeof(pqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | 1280 | sizeof(pqh->qh.qh_hlink), BUS_DMASYNC_PREWRITE); | |
1281 | delay(UHCI_QH_REMOVE_DELAY); | 1281 | delay(UHCI_QH_REMOVE_DELAY); | |
1282 | if (sc->sc_bulk_end == sqh) | 1282 | if (sc->sc_bulk_end == sqh) | |
1283 | sc->sc_bulk_end = pqh; | 1283 | sc->sc_bulk_end = pqh; | |
1284 | } | 1284 | } | |
1285 | 1285 | |||
1286 | Static int uhci_intr1(uhci_softc_t *); | 1286 | Static int uhci_intr1(uhci_softc_t *); | |
1287 | 1287 | |||
1288 | int | 1288 | int | |
1289 | uhci_intr(void *arg) | 1289 | uhci_intr(void *arg) | |
1290 | { | 1290 | { | |
1291 | uhci_softc_t *sc = arg; | 1291 | uhci_softc_t *sc = arg; | |
1292 | int ret = 0; | 1292 | int ret = 0; | |
1293 | 1293 | |||
1294 | mutex_spin_enter(&sc->sc_intr_lock); | 1294 | mutex_spin_enter(&sc->sc_intr_lock); | |
1295 | 1295 | |||
1296 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) | 1296 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) | |
1297 | goto done; | 1297 | goto done; | |
1298 | 1298 | |||
1299 | if (sc->sc_bus.use_polling || UREAD2(sc, UHCI_INTR) == 0) { | 1299 | if (sc->sc_bus.use_polling || UREAD2(sc, UHCI_INTR) == 0) { | |
1300 | #ifdef DIAGNOSTIC | 1300 | #ifdef DIAGNOSTIC | |
1301 | DPRINTFN(16, ("uhci_intr: ignored interrupt while polling\n")); | 1301 | DPRINTFN(16, ("uhci_intr: ignored interrupt while polling\n")); | |
1302 | #endif | 1302 | #endif | |
1303 | goto done; | 1303 | goto done; | |
1304 | } | 1304 | } | |
1305 | 1305 | |||
1306 | ret = uhci_intr1(sc); | 1306 | ret = uhci_intr1(sc); | |
1307 | 1307 | |||
1308 | done: | 1308 | done: | |
1309 | mutex_spin_exit(&sc->sc_intr_lock); | 1309 | mutex_spin_exit(&sc->sc_intr_lock); | |
1310 | return ret; | 1310 | return ret; | |
1311 | } | 1311 | } | |
1312 | 1312 | |||
1313 | int | 1313 | int | |
1314 | uhci_intr1(uhci_softc_t *sc) | 1314 | uhci_intr1(uhci_softc_t *sc) | |
1315 | { | 1315 | { | |
1316 | int status; | 1316 | int status; | |
1317 | int ack; | 1317 | int ack; | |
1318 | 1318 | |||
1319 | #ifdef UHCI_DEBUG | 1319 | #ifdef UHCI_DEBUG | |
1320 | if (uhcidebug > 15) { | 1320 | if (uhcidebug > 15) { | |
1321 | DPRINTF(("%s: uhci_intr1\n", device_xname(sc->sc_dev))); | 1321 | DPRINTF(("%s: uhci_intr1\n", device_xname(sc->sc_dev))); | |
1322 | uhci_dumpregs(sc); | 1322 | uhci_dumpregs(sc); | |
1323 | } | 1323 | } | |
1324 | #endif | 1324 | #endif | |
1325 | 1325 | |||
1326 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | 1326 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | |
1327 | 1327 | |||
1328 | status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS; | 1328 | status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS; | |
1329 | if (status == 0) /* The interrupt was not for us. */ | 1329 | if (status == 0) /* The interrupt was not for us. */ | |
1330 | return (0); | 1330 | return (0); | |
1331 | 1331 | |||
1332 | if (sc->sc_suspend != PWR_RESUME) { | 1332 | if (sc->sc_suspend != PWR_RESUME) { | |
1333 | #ifdef DIAGNOSTIC | 1333 | #ifdef DIAGNOSTIC | |
1334 | printf("%s: interrupt while not operating ignored\n", | 1334 | printf("%s: interrupt while not operating ignored\n", | |
1335 | device_xname(sc->sc_dev)); | 1335 | device_xname(sc->sc_dev)); | |
1336 | #endif | 1336 | #endif | |
1337 | UWRITE2(sc, UHCI_STS, status); /* acknowledge the ints */ | 1337 | UWRITE2(sc, UHCI_STS, status); /* acknowledge the ints */ | |
1338 | return (0); | 1338 | return (0); | |
1339 | } | 1339 | } | |
1340 | 1340 | |||
1341 | ack = 0; | 1341 | ack = 0; | |
1342 | if (status & UHCI_STS_USBINT) | 1342 | if (status & UHCI_STS_USBINT) | |
1343 | ack |= UHCI_STS_USBINT; | 1343 | ack |= UHCI_STS_USBINT; | |
1344 | if (status & UHCI_STS_USBEI) | 1344 | if (status & UHCI_STS_USBEI) | |
1345 | ack |= UHCI_STS_USBEI; | 1345 | ack |= UHCI_STS_USBEI; | |
1346 | if (status & UHCI_STS_RD) { | 1346 | if (status & UHCI_STS_RD) { | |
1347 | ack |= UHCI_STS_RD; | 1347 | ack |= UHCI_STS_RD; | |
1348 | #ifdef UHCI_DEBUG | 1348 | #ifdef UHCI_DEBUG | |
1349 | printf("%s: resume detect\n", device_xname(sc->sc_dev)); | 1349 | printf("%s: resume detect\n", device_xname(sc->sc_dev)); | |
1350 | #endif | 1350 | #endif | |
1351 | } | 1351 | } | |
1352 | if (status & UHCI_STS_HSE) { | 1352 | if (status & UHCI_STS_HSE) { | |
1353 | ack |= UHCI_STS_HSE; | 1353 | ack |= UHCI_STS_HSE; | |
1354 | printf("%s: host system error\n", device_xname(sc->sc_dev)); | 1354 | printf("%s: host system error\n", device_xname(sc->sc_dev)); | |
1355 | } | 1355 | } | |
1356 | if (status & UHCI_STS_HCPE) { | 1356 | if (status & UHCI_STS_HCPE) { | |
1357 | ack |= UHCI_STS_HCPE; | 1357 | ack |= UHCI_STS_HCPE; | |
1358 | printf("%s: host controller process error\n", | 1358 | printf("%s: host controller process error\n", | |
1359 | device_xname(sc->sc_dev)); | 1359 | device_xname(sc->sc_dev)); | |
1360 | } | 1360 | } | |
1361 | 1361 | |||
1362 | /* When HCHalted=1 and Run/Stop=0 , it is normal */ | 1362 | /* When HCHalted=1 and Run/Stop=0 , it is normal */ | |
1363 | if ((status & UHCI_STS_HCH) && (UREAD2(sc, UHCI_CMD) & UHCI_CMD_RS)) { | 1363 | if ((status & UHCI_STS_HCH) && (UREAD2(sc, UHCI_CMD) & UHCI_CMD_RS)) { | |
1364 | /* no acknowledge needed */ | 1364 | /* no acknowledge needed */ | |
1365 | if (!sc->sc_dying) { | 1365 | if (!sc->sc_dying) { | |
1366 | printf("%s: host controller halted\n", | 1366 | printf("%s: host controller halted\n", | |
1367 | device_xname(sc->sc_dev)); | 1367 | device_xname(sc->sc_dev)); | |
1368 | #ifdef UHCI_DEBUG | 1368 | #ifdef UHCI_DEBUG | |
1369 | uhci_dump_all(sc); | 1369 | uhci_dump_all(sc); | |
1370 | #endif | 1370 | #endif | |
1371 | } | 1371 | } | |
1372 | sc->sc_dying = 1; | 1372 | sc->sc_dying = 1; | |
1373 | } | 1373 | } | |
1374 | 1374 | |||
1375 | if (!ack) | 1375 | if (!ack) | |
1376 | return (0); /* nothing to acknowledge */ | 1376 | return (0); /* nothing to acknowledge */ | |
1377 | UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */ | 1377 | UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */ | |
1378 | 1378 | |||
1379 | sc->sc_bus.no_intrs++; | 1379 | sc->sc_bus.no_intrs++; | |
1380 | usb_schedsoftintr(&sc->sc_bus); | 1380 | usb_schedsoftintr(&sc->sc_bus); | |
1381 | 1381 | |||
1382 | DPRINTFN(15, ("%s: uhci_intr: exit\n", device_xname(sc->sc_dev))); | 1382 | DPRINTFN(15, ("%s: uhci_intr: exit\n", device_xname(sc->sc_dev))); | |
1383 | 1383 | |||
1384 | return (1); | 1384 | return (1); | |
1385 | } | 1385 | } | |
1386 | 1386 | |||
1387 | void | 1387 | void | |
1388 | uhci_softintr(void *v) | 1388 | uhci_softintr(void *v) | |
1389 | { | 1389 | { | |
1390 | struct usbd_bus *bus = v; | 1390 | struct usbd_bus *bus = v; | |
1391 | uhci_softc_t *sc = bus->hci_private; | 1391 | uhci_softc_t *sc = bus->hci_private; | |
1392 | uhci_intr_info_t *ii, *nextii; | 1392 | uhci_intr_info_t *ii, *nextii; | |
1393 | 1393 | |||
1394 | DPRINTFN(10,("%s: uhci_softintr (%d)\n", device_xname(sc->sc_dev), | 1394 | DPRINTFN(10,("%s: uhci_softintr (%d)\n", device_xname(sc->sc_dev), | |
1395 | sc->sc_bus.intr_context)); | 1395 | sc->sc_bus.intr_context)); | |
1396 | 1396 | |||
1397 | mutex_enter(&sc->sc_lock); | 1397 | mutex_enter(&sc->sc_lock); | |
1398 | 1398 | |||
1399 | sc->sc_bus.intr_context++; | 1399 | sc->sc_bus.intr_context++; | |
1400 | 1400 | |||
1401 | /* | 1401 | /* | |
1402 | * Interrupts on UHCI really suck. When the host controller | 1402 | * Interrupts on UHCI really suck. When the host controller | |
1403 | * interrupts because a transfer is completed there is no | 1403 | * interrupts because a transfer is completed there is no | |
1404 | * way of knowing which transfer it was. You can scan down | 1404 | * way of knowing which transfer it was. You can scan down | |
1405 | * the TDs and QHs of the previous frame to limit the search, | 1405 | * the TDs and QHs of the previous frame to limit the search, | |
1406 | * but that assumes that the interrupt was not delayed by more | 1406 | * but that assumes that the interrupt was not delayed by more | |
1407 | * than 1 ms, which may not always be true (e.g. after debug | 1407 | * than 1 ms, which may not always be true (e.g. after debug | |
1408 | * output on a slow console). | 1408 | * output on a slow console). | |
1409 | * We scan all interrupt descriptors to see if any have | 1409 | * We scan all interrupt descriptors to see if any have | |
1410 | * completed. | 1410 | * completed. | |
1411 | */ | 1411 | */ | |
1412 | for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = nextii) { | 1412 | for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = nextii) { | |
1413 | nextii = LIST_NEXT(ii, list); | 1413 | nextii = LIST_NEXT(ii, list); | |
1414 | uhci_check_intr(sc, ii); | 1414 | uhci_check_intr(sc, ii); | |
1415 | } | 1415 | } | |
1416 | 1416 | |||
1417 | if (sc->sc_softwake) { | 1417 | if (sc->sc_softwake) { | |
1418 | sc->sc_softwake = 0; | 1418 | sc->sc_softwake = 0; | |
1419 | cv_broadcast(&sc->sc_softwake_cv); | 1419 | cv_broadcast(&sc->sc_softwake_cv); | |
1420 | } | 1420 | } | |
1421 | 1421 | |||
1422 | sc->sc_bus.intr_context--; | 1422 | sc->sc_bus.intr_context--; | |
1423 | 1423 | |||
1424 | mutex_exit(&sc->sc_lock); | 1424 | mutex_exit(&sc->sc_lock); | |
1425 | } | 1425 | } | |
1426 | 1426 | |||
1427 | /* Check for an interrupt. */ | 1427 | /* Check for an interrupt. */ | |
1428 | void | 1428 | void | |
1429 | uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii) | 1429 | uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii) | |
1430 | { | 1430 | { | |
1431 | uhci_soft_td_t *std, *lstd; | 1431 | uhci_soft_td_t *std, *lstd; | |
1432 | u_int32_t status; | 1432 | u_int32_t status; | |
1433 | 1433 | |||
1434 | DPRINTFN(15, ("uhci_check_intr: ii=%p\n", ii)); | 1434 | DPRINTFN(15, ("uhci_check_intr: ii=%p\n", ii)); | |
1435 | #ifdef DIAGNOSTIC | 1435 | #ifdef DIAGNOSTIC | |
1436 | if (ii == NULL) { | 1436 | if (ii == NULL) { | |
1437 | printf("uhci_check_intr: no ii? %p\n", ii); | 1437 | printf("uhci_check_intr: no ii? %p\n", ii); | |
1438 | return; | 1438 | return; | |
1439 | } | 1439 | } | |
1440 | #endif | 1440 | #endif | |
1441 | if (ii->xfer->status == USBD_CANCELLED || | 1441 | if (ii->xfer->status == USBD_CANCELLED || | |
1442 | ii->xfer->status == USBD_TIMEOUT) { | 1442 | ii->xfer->status == USBD_TIMEOUT) { | |
1443 | DPRINTF(("uhci_check_intr: aborted xfer=%p\n", ii->xfer)); | 1443 | DPRINTF(("uhci_check_intr: aborted xfer=%p\n", ii->xfer)); | |
1444 | return; | 1444 | return; | |
1445 | } | 1445 | } | |
1446 | 1446 | |||
1447 | if (ii->stdstart == NULL) | 1447 | if (ii->stdstart == NULL) | |
1448 | return; | 1448 | return; | |
1449 | lstd = ii->stdend; | 1449 | lstd = ii->stdend; | |
1450 | #ifdef DIAGNOSTIC | 1450 | #ifdef DIAGNOSTIC | |
1451 | if (lstd == NULL) { | 1451 | if (lstd == NULL) { | |
1452 | printf("uhci_check_intr: std==0\n"); | 1452 | printf("uhci_check_intr: std==0\n"); | |
1453 | return; | 1453 | return; | |
1454 | } | 1454 | } | |
1455 | #endif | 1455 | #endif | |
1456 | /* | 1456 | /* | |
1457 | * If the last TD is still active we need to check whether there | 1457 | * If the last TD is still active we need to check whether there | |
1458 | * is an error somewhere in the middle, or whether there was a | 1458 | * is an error somewhere in the middle, or whether there was a | |
1459 | * short packet (SPD and not ACTIVE). | 1459 | * short packet (SPD and not ACTIVE). | |
1460 | */ | 1460 | */ | |
1461 | usb_syncmem(&lstd->dma, | 1461 | usb_syncmem(&lstd->dma, | |
1462 | lstd->offs + offsetof(uhci_td_t, td_status), | 1462 | lstd->offs + offsetof(uhci_td_t, td_status), | |
1463 | sizeof(lstd->td.td_status), | 1463 | sizeof(lstd->td.td_status), | |
1464 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1464 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1465 | if (le32toh(lstd->td.td_status) & UHCI_TD_ACTIVE) { | 1465 | if (le32toh(lstd->td.td_status) & UHCI_TD_ACTIVE) { | |
1466 | DPRINTFN(12, ("uhci_check_intr: active ii=%p\n", ii)); | 1466 | DPRINTFN(12, ("uhci_check_intr: active ii=%p\n", ii)); | |
1467 | for (std = ii->stdstart; std != lstd; std = std->link.std) { | 1467 | for (std = ii->stdstart; std != lstd; std = std->link.std) { | |
1468 | usb_syncmem(&std->dma, | 1468 | usb_syncmem(&std->dma, | |
1469 | std->offs + offsetof(uhci_td_t, td_status), | 1469 | std->offs + offsetof(uhci_td_t, td_status), | |
1470 | sizeof(std->td.td_status), | 1470 | sizeof(std->td.td_status), | |
1471 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1471 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1472 | status = le32toh(std->td.td_status); | 1472 | status = le32toh(std->td.td_status); | |
1473 | usb_syncmem(&std->dma, | 1473 | usb_syncmem(&std->dma, | |
1474 | std->offs + offsetof(uhci_td_t, td_status), | 1474 | std->offs + offsetof(uhci_td_t, td_status), | |
1475 | sizeof(std->td.td_status), BUS_DMASYNC_PREREAD); | 1475 | sizeof(std->td.td_status), BUS_DMASYNC_PREREAD); | |
1476 | /* If there's an active TD the xfer isn't done. */ | 1476 | /* If there's an active TD the xfer isn't done. */ | |
1477 | if (status & UHCI_TD_ACTIVE) | 1477 | if (status & UHCI_TD_ACTIVE) | |
1478 | break; | 1478 | break; | |
1479 | /* Any kind of error makes the xfer done. */ | 1479 | /* Any kind of error makes the xfer done. */ | |
1480 | if (status & UHCI_TD_STALLED) | 1480 | if (status & UHCI_TD_STALLED) | |
1481 | goto done; | 1481 | goto done; | |
1482 | /* We want short packets, and it is short: it's done */ | 1482 | /* We want short packets, and it is short: it's done */ | |
1483 | usb_syncmem(&std->dma, | 1483 | usb_syncmem(&std->dma, | |
1484 | std->offs + offsetof(uhci_td_t, td_token), | 1484 | std->offs + offsetof(uhci_td_t, td_token), | |
1485 | sizeof(std->td.td_token), | 1485 | sizeof(std->td.td_token), | |
1486 | BUS_DMASYNC_POSTWRITE); | 1486 | BUS_DMASYNC_POSTWRITE); | |
1487 | if ((status & UHCI_TD_SPD) && | 1487 | if ((status & UHCI_TD_SPD) && | |
1488 | UHCI_TD_GET_ACTLEN(status) < | 1488 | UHCI_TD_GET_ACTLEN(status) < | |
1489 | UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token))) | 1489 | UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token))) | |
1490 | goto done; | 1490 | goto done; | |
1491 | } | 1491 | } | |
1492 | DPRINTFN(12, ("uhci_check_intr: ii=%p std=%p still active\n", | 1492 | DPRINTFN(12, ("uhci_check_intr: ii=%p std=%p still active\n", | |
1493 | ii, ii->stdstart)); | 1493 | ii, ii->stdstart)); | |
1494 | usb_syncmem(&lstd->dma, | 1494 | usb_syncmem(&lstd->dma, | |
1495 | lstd->offs + offsetof(uhci_td_t, td_status), | 1495 | lstd->offs + offsetof(uhci_td_t, td_status), | |
1496 | sizeof(lstd->td.td_status), | 1496 | sizeof(lstd->td.td_status), | |
1497 | BUS_DMASYNC_PREREAD); | 1497 | BUS_DMASYNC_PREREAD); | |
1498 | return; | 1498 | return; | |
1499 | } | 1499 | } | |
1500 | done: | 1500 | done: | |
1501 | DPRINTFN(12, ("uhci_check_intr: ii=%p done\n", ii)); | 1501 | DPRINTFN(12, ("uhci_check_intr: ii=%p done\n", ii)); | |
1502 | callout_stop(&ii->xfer->timeout_handle); | 1502 | callout_stop(&ii->xfer->timeout_handle); | |
1503 | uhci_idone(ii); | 1503 | uhci_idone(ii); | |
1504 | } | 1504 | } | |
1505 | 1505 | |||
1506 | /* Called at splusb() */ | 1506 | /* Called at splusb() */ | |
1507 | void | 1507 | void | |
1508 | uhci_idone(uhci_intr_info_t *ii) | 1508 | uhci_idone(uhci_intr_info_t *ii) | |
1509 | { | 1509 | { | |
1510 | usbd_xfer_handle xfer = ii->xfer; | 1510 | usbd_xfer_handle xfer = ii->xfer; | |
1511 | struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; | 1511 | struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; | |
1512 | uhci_soft_td_t *std; | 1512 | uhci_soft_td_t *std; | |
1513 | u_int32_t status = 0, nstatus; | 1513 | u_int32_t status = 0, nstatus; | |
1514 | int actlen; | 1514 | int actlen; | |
1515 | 1515 | |||
1516 | DPRINTFN(12, ("uhci_idone: ii=%p\n", ii)); | 1516 | DPRINTFN(12, ("uhci_idone: ii=%p\n", ii)); | |
1517 | #ifdef DIAGNOSTIC | 1517 | #ifdef DIAGNOSTIC | |
1518 | { | 1518 | { | |
1519 | /* XXX SMP? */ | 1519 | /* XXX SMP? */ | |
1520 | int s = splhigh(); | 1520 | int s = splhigh(); | |
1521 | if (ii->isdone) { | 1521 | if (ii->isdone) { | |
1522 | splx(s); | 1522 | splx(s); | |
1523 | #ifdef UHCI_DEBUG | 1523 | #ifdef UHCI_DEBUG | |
1524 | printf("uhci_idone: ii is done!\n "); | 1524 | printf("uhci_idone: ii is done!\n "); | |
1525 | uhci_dump_ii(ii); | 1525 | uhci_dump_ii(ii); | |
1526 | #else | 1526 | #else | |
1527 | printf("uhci_idone: ii=%p is done!\n", ii); | 1527 | printf("uhci_idone: ii=%p is done!\n", ii); | |
1528 | #endif | 1528 | #endif | |
1529 | return; | 1529 | return; | |
1530 | } | 1530 | } | |
1531 | ii->isdone = 1; | 1531 | ii->isdone = 1; | |
1532 | splx(s); | 1532 | splx(s); | |
1533 | } | 1533 | } | |
1534 | #endif | 1534 | #endif | |
1535 | 1535 | |||
1536 | if (xfer->nframes != 0) { | 1536 | if (xfer->nframes != 0) { | |
1537 | /* Isoc transfer, do things differently. */ | 1537 | /* Isoc transfer, do things differently. */ | |
1538 | uhci_soft_td_t **stds = upipe->u.iso.stds; | 1538 | uhci_soft_td_t **stds = upipe->u.iso.stds; | |
1539 | int i, n, nframes, len; | 1539 | int i, n, nframes, len; | |
1540 | 1540 | |||
1541 | DPRINTFN(5,("uhci_idone: ii=%p isoc ready\n", ii)); | 1541 | DPRINTFN(5,("uhci_idone: ii=%p isoc ready\n", ii)); | |
1542 | 1542 | |||
1543 | nframes = xfer->nframes; | 1543 | nframes = xfer->nframes; | |
1544 | actlen = 0; | 1544 | actlen = 0; | |
1545 | n = UXFER(xfer)->curframe; | 1545 | n = UXFER(xfer)->curframe; | |
1546 | for (i = 0; i < nframes; i++) { | 1546 | for (i = 0; i < nframes; i++) { | |
1547 | std = stds[n]; | 1547 | std = stds[n]; | |
1548 | #ifdef UHCI_DEBUG | 1548 | #ifdef UHCI_DEBUG | |
1549 | if (uhcidebug > 5) { | 1549 | if (uhcidebug > 5) { | |
1550 | DPRINTFN(-1,("uhci_idone: isoc TD %d\n", i)); | 1550 | DPRINTFN(-1,("uhci_idone: isoc TD %d\n", i)); | |
1551 | uhci_dump_td(std); | 1551 | uhci_dump_td(std); | |
1552 | } | 1552 | } | |
1553 | #endif | 1553 | #endif | |
1554 | if (++n >= UHCI_VFRAMELIST_COUNT) | 1554 | if (++n >= UHCI_VFRAMELIST_COUNT) | |
1555 | n = 0; | 1555 | n = 0; | |
1556 | usb_syncmem(&std->dma, | 1556 | usb_syncmem(&std->dma, | |
1557 | std->offs + offsetof(uhci_td_t, td_status), | 1557 | std->offs + offsetof(uhci_td_t, td_status), | |
1558 | sizeof(std->td.td_status), | 1558 | sizeof(std->td.td_status), | |
1559 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1559 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1560 | status = le32toh(std->td.td_status); | 1560 | status = le32toh(std->td.td_status); | |
1561 | len = UHCI_TD_GET_ACTLEN(status); | 1561 | len = UHCI_TD_GET_ACTLEN(status); | |
1562 | xfer->frlengths[i] = len; | 1562 | xfer->frlengths[i] = len; | |
1563 | actlen += len; | 1563 | actlen += len; | |
1564 | } | 1564 | } | |
1565 | upipe->u.iso.inuse -= nframes; | 1565 | upipe->u.iso.inuse -= nframes; | |
1566 | xfer->actlen = actlen; | 1566 | xfer->actlen = actlen; | |
1567 | xfer->status = USBD_NORMAL_COMPLETION; | 1567 | xfer->status = USBD_NORMAL_COMPLETION; | |
1568 | goto end; | 1568 | goto end; | |
1569 | } | 1569 | } | |
1570 | 1570 | |||
1571 | #ifdef UHCI_DEBUG | 1571 | #ifdef UHCI_DEBUG | |
1572 | DPRINTFN(10, ("uhci_idone: ii=%p, xfer=%p, pipe=%p ready\n", | 1572 | DPRINTFN(10, ("uhci_idone: ii=%p, xfer=%p, pipe=%p ready\n", | |
1573 | ii, xfer, upipe)); | 1573 | ii, xfer, upipe)); | |
1574 | if (uhcidebug > 10) | 1574 | if (uhcidebug > 10) | |
1575 | uhci_dump_tds(ii->stdstart); | 1575 | uhci_dump_tds(ii->stdstart); | |
1576 | #endif | 1576 | #endif | |
1577 | 1577 | |||
1578 | /* The transfer is done, compute actual length and status. */ | 1578 | /* The transfer is done, compute actual length and status. */ | |
1579 | actlen = 0; | 1579 | actlen = 0; | |
1580 | for (std = ii->stdstart; std != NULL; std = std->link.std) { | 1580 | for (std = ii->stdstart; std != NULL; std = std->link.std) { | |
1581 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | 1581 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | |
1582 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1582 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1583 | nstatus = le32toh(std->td.td_status); | 1583 | nstatus = le32toh(std->td.td_status); | |
1584 | if (nstatus & UHCI_TD_ACTIVE) | 1584 | if (nstatus & UHCI_TD_ACTIVE) | |
1585 | break; | 1585 | break; | |
1586 | 1586 | |||
1587 | status = nstatus; | 1587 | status = nstatus; | |
1588 | if (UHCI_TD_GET_PID(le32toh(std->td.td_token)) != | 1588 | if (UHCI_TD_GET_PID(le32toh(std->td.td_token)) != | |
1589 | UHCI_TD_PID_SETUP) | 1589 | UHCI_TD_PID_SETUP) | |
1590 | actlen += UHCI_TD_GET_ACTLEN(status); | 1590 | actlen += UHCI_TD_GET_ACTLEN(status); | |
1591 | else { | 1591 | else { | |
1592 | /* | 1592 | /* | |
1593 | * UHCI will report CRCTO in addition to a STALL or NAK | 1593 | * UHCI will report CRCTO in addition to a STALL or NAK | |
1594 | * for a SETUP transaction. See section 3.2.2, "TD | 1594 | * for a SETUP transaction. See section 3.2.2, "TD | |
1595 | * CONTROL AND STATUS". | 1595 | * CONTROL AND STATUS". | |
1596 | */ | 1596 | */ | |
1597 | if (status & (UHCI_TD_STALLED | UHCI_TD_NAK)) | 1597 | if (status & (UHCI_TD_STALLED | UHCI_TD_NAK)) | |
1598 | status &= ~UHCI_TD_CRCTO; | 1598 | status &= ~UHCI_TD_CRCTO; | |
1599 | } | 1599 | } | |
1600 | } | 1600 | } | |
1601 | /* If there are left over TDs we need to update the toggle. */ | 1601 | /* If there are left over TDs we need to update the toggle. */ | |
1602 | if (std != NULL) | 1602 | if (std != NULL) | |
1603 | upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token)); | 1603 | upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token)); | |
1604 | 1604 | |||
1605 | status &= UHCI_TD_ERROR; | 1605 | status &= UHCI_TD_ERROR; | |
1606 | DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n", | 1606 | DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n", | |
1607 | actlen, status)); | 1607 | actlen, status)); | |
1608 | xfer->actlen = actlen; | 1608 | xfer->actlen = actlen; | |
1609 | if (status != 0) { | 1609 | if (status != 0) { | |
1610 | #ifdef UHCI_DEBUG | 1610 | #ifdef UHCI_DEBUG | |
1611 | char sbuf[128]; | 1611 | char sbuf[128]; | |
1612 | 1612 | |||
1613 | snprintb(sbuf, sizeof(sbuf), | 1613 | snprintb(sbuf, sizeof(sbuf), | |
1614 | "\20\22BITSTUFF\23CRCTO\24NAK\25" | 1614 | "\20\22BITSTUFF\23CRCTO\24NAK\25" | |
1615 | "BABBLE\26DBUFFER\27STALLED\30ACTIVE",(u_int32_t)status); | 1615 | "BABBLE\26DBUFFER\27STALLED\30ACTIVE",(u_int32_t)status); | |
1616 | 1616 | |||
1617 | DPRINTFN((status == UHCI_TD_STALLED)*10, | 1617 | DPRINTFN((status == UHCI_TD_STALLED)*10, | |
1618 | ("uhci_idone: error, addr=%d, endpt=0x%02x, " | 1618 | ("uhci_idone: error, addr=%d, endpt=0x%02x, " | |
1619 | "status 0x%s\n", | 1619 | "status 0x%s\n", | |
1620 | xfer->pipe->device->address, | 1620 | xfer->pipe->device->address, | |
1621 | xfer->pipe->endpoint->edesc->bEndpointAddress, | 1621 | xfer->pipe->endpoint->edesc->bEndpointAddress, | |
1622 | sbuf)); | 1622 | sbuf)); | |
1623 | #endif | 1623 | #endif | |
1624 | 1624 | |||
1625 | if (status == UHCI_TD_STALLED) | 1625 | if (status == UHCI_TD_STALLED) | |
1626 | xfer->status = USBD_STALLED; | 1626 | xfer->status = USBD_STALLED; | |
1627 | else | 1627 | else | |
1628 | xfer->status = USBD_IOERROR; /* more info XXX */ | 1628 | xfer->status = USBD_IOERROR; /* more info XXX */ | |
1629 | } else { | 1629 | } else { | |
1630 | xfer->status = USBD_NORMAL_COMPLETION; | 1630 | xfer->status = USBD_NORMAL_COMPLETION; | |
1631 | } | 1631 | } | |
1632 | 1632 | |||
1633 | end: | 1633 | end: | |
1634 | usb_transfer_complete(xfer); | 1634 | usb_transfer_complete(xfer); | |
1635 | DPRINTFN(12, ("uhci_idone: ii=%p done\n", ii)); | 1635 | DPRINTFN(12, ("uhci_idone: ii=%p done\n", ii)); | |
1636 | } | 1636 | } | |
1637 | 1637 | |||
1638 | /* | 1638 | /* | |
1639 | * Called when a request does not complete. | 1639 | * Called when a request does not complete. | |
1640 | */ | 1640 | */ | |
1641 | void | 1641 | void | |
1642 | uhci_timeout(void *addr) | 1642 | uhci_timeout(void *addr) | |
1643 | { | 1643 | { | |
1644 | uhci_intr_info_t *ii = addr; | 1644 | uhci_intr_info_t *ii = addr; | |
1645 | struct uhci_xfer *uxfer = UXFER(ii->xfer); | 1645 | struct uhci_xfer *uxfer = UXFER(ii->xfer); | |
1646 | struct uhci_pipe *upipe = (struct uhci_pipe *)uxfer->xfer.pipe; | 1646 | struct uhci_pipe *upipe = (struct uhci_pipe *)uxfer->xfer.pipe; | |
1647 | uhci_softc_t *sc = upipe->pipe.device->bus->hci_private; | 1647 | uhci_softc_t *sc = upipe->pipe.device->bus->hci_private; | |
1648 | 1648 | |||
1649 | DPRINTF(("uhci_timeout: uxfer=%p\n", uxfer)); | 1649 | DPRINTF(("uhci_timeout: uxfer=%p\n", uxfer)); | |
1650 | 1650 | |||
1651 | if (sc->sc_dying) { | 1651 | if (sc->sc_dying) { | |
1652 | uhci_abort_xfer(&uxfer->xfer, USBD_TIMEOUT); | 1652 | uhci_abort_xfer(&uxfer->xfer, USBD_TIMEOUT); | |
1653 | return; | 1653 | return; | |
1654 | } | 1654 | } | |
1655 | 1655 | |||
1656 | /* Execute the abort in a process context. */ | 1656 | /* Execute the abort in a process context. */ | |
1657 | usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer); | 1657 | usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer); | |
1658 | usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task, | 1658 | usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task, | |
1659 | USB_TASKQ_HC); | 1659 | USB_TASKQ_HC); | |
1660 | } | 1660 | } | |
1661 | 1661 | |||
1662 | void | 1662 | void | |
1663 | uhci_timeout_task(void *addr) | 1663 | uhci_timeout_task(void *addr) | |
1664 | { | 1664 | { | |
1665 | usbd_xfer_handle xfer = addr; | 1665 | usbd_xfer_handle xfer = addr; | |
1666 | 1666 | |||
1667 | DPRINTF(("uhci_timeout_task: xfer=%p\n", xfer)); | 1667 | DPRINTF(("uhci_timeout_task: xfer=%p\n", xfer)); | |
1668 | 1668 | |||
1669 | uhci_abort_xfer(xfer, USBD_TIMEOUT); | 1669 | uhci_abort_xfer(xfer, USBD_TIMEOUT); | |
1670 | } | 1670 | } | |
1671 | 1671 | |||
1672 | /* | 1672 | /* | |
1673 | * Wait here until controller claims to have an interrupt. | 1673 | * Wait here until controller claims to have an interrupt. | |
1674 | * Then call uhci_intr and return. Use timeout to avoid waiting | 1674 | * Then call uhci_intr and return. Use timeout to avoid waiting | |
1675 | * too long. | 1675 | * too long. | |
1676 | * Only used during boot when interrupts are not enabled yet. | 1676 | * Only used during boot when interrupts are not enabled yet. | |
1677 | */ | 1677 | */ | |
1678 | void | 1678 | void | |
1679 | uhci_waitintr(uhci_softc_t *sc, usbd_xfer_handle xfer) | 1679 | uhci_waitintr(uhci_softc_t *sc, usbd_xfer_handle xfer) | |
1680 | { | 1680 | { | |
1681 | int timo = xfer->timeout; | 1681 | int timo = xfer->timeout; | |
1682 | uhci_intr_info_t *ii; | 1682 | uhci_intr_info_t *ii; | |
1683 | 1683 | |||
1684 | mutex_enter(&sc->sc_lock); | 1684 | mutex_enter(&sc->sc_lock); | |
1685 | 1685 | |||
1686 | DPRINTFN(10,("uhci_waitintr: timeout = %dms\n", timo)); | 1686 | DPRINTFN(10,("uhci_waitintr: timeout = %dms\n", timo)); | |
1687 | 1687 | |||
1688 | xfer->status = USBD_IN_PROGRESS; | 1688 | xfer->status = USBD_IN_PROGRESS; | |
1689 | for (; timo >= 0; timo--) { | 1689 | for (; timo >= 0; timo--) { | |
1690 | usb_delay_ms(&sc->sc_bus, 1); | 1690 | usb_delay_ms(&sc->sc_bus, 1); | |
1691 | DPRINTFN(20,("uhci_waitintr: 0x%04x\n", UREAD2(sc, UHCI_STS))); | 1691 | DPRINTFN(20,("uhci_waitintr: 0x%04x\n", UREAD2(sc, UHCI_STS))); | |
1692 | if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) { | 1692 | if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) { | |
1693 | mutex_spin_enter(&sc->sc_intr_lock); | 1693 | mutex_spin_enter(&sc->sc_intr_lock); | |
1694 | uhci_intr1(sc); | 1694 | uhci_intr1(sc); | |
1695 | mutex_spin_exit(&sc->sc_intr_lock); | 1695 | mutex_spin_exit(&sc->sc_intr_lock); | |
1696 | if (xfer->status != USBD_IN_PROGRESS) | 1696 | if (xfer->status != USBD_IN_PROGRESS) | |
1697 | goto done; | 1697 | goto done; | |
1698 | } | 1698 | } | |
1699 | } | 1699 | } | |
1700 | 1700 | |||
1701 | /* Timeout */ | 1701 | /* Timeout */ | |
1702 | DPRINTF(("uhci_waitintr: timeout\n")); | 1702 | DPRINTF(("uhci_waitintr: timeout\n")); | |
1703 | for (ii = LIST_FIRST(&sc->sc_intrhead); | 1703 | for (ii = LIST_FIRST(&sc->sc_intrhead); | |
1704 | ii != NULL && ii->xfer != xfer; | 1704 | ii != NULL && ii->xfer != xfer; | |
1705 | ii = LIST_NEXT(ii, list)) | 1705 | ii = LIST_NEXT(ii, list)) | |
1706 | ; | 1706 | ; | |
1707 | #ifdef DIAGNOSTIC | 1707 | #ifdef DIAGNOSTIC | |
1708 | if (ii == NULL) | 1708 | if (ii == NULL) | |
1709 | panic("uhci_waitintr: lost intr_info"); | 1709 | panic("uhci_waitintr: lost intr_info"); | |
1710 | #endif | 1710 | #endif | |
1711 | uhci_idone(ii); | 1711 | uhci_idone(ii); | |
1712 | 1712 | |||
1713 | done: | 1713 | done: | |
1714 | mutex_exit(&sc->sc_lock); | 1714 | mutex_exit(&sc->sc_lock); | |
1715 | } | 1715 | } | |
1716 | 1716 | |||
1717 | void | 1717 | void | |
1718 | uhci_poll(struct usbd_bus *bus) | 1718 | uhci_poll(struct usbd_bus *bus) | |
1719 | { | 1719 | { | |
1720 | uhci_softc_t *sc = bus->hci_private; | 1720 | uhci_softc_t *sc = bus->hci_private; | |
1721 | 1721 | |||
1722 | if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) { | 1722 | if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) { | |
1723 | mutex_spin_enter(&sc->sc_intr_lock); | 1723 | mutex_spin_enter(&sc->sc_intr_lock); | |
1724 | uhci_intr1(sc); | 1724 | uhci_intr1(sc); | |
1725 | mutex_spin_exit(&sc->sc_intr_lock); | 1725 | mutex_spin_exit(&sc->sc_intr_lock); | |
1726 | } | 1726 | } | |
1727 | } | 1727 | } | |
1728 | 1728 | |||
1729 | void | 1729 | void | |
1730 | uhci_reset(uhci_softc_t *sc) | 1730 | uhci_reset(uhci_softc_t *sc) | |
1731 | { | 1731 | { | |
1732 | int n; | 1732 | int n; | |
1733 | 1733 | |||
1734 | UHCICMD(sc, UHCI_CMD_HCRESET); | 1734 | UHCICMD(sc, UHCI_CMD_HCRESET); | |
1735 | /* The reset bit goes low when the controller is done. */ | 1735 | /* The reset bit goes low when the controller is done. */ | |
1736 | for (n = 0; n < UHCI_RESET_TIMEOUT && | 1736 | for (n = 0; n < UHCI_RESET_TIMEOUT && | |
1737 | (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++) | 1737 | (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++) | |
1738 | usb_delay_ms(&sc->sc_bus, 1); | 1738 | usb_delay_ms(&sc->sc_bus, 1); | |
1739 | if (n >= UHCI_RESET_TIMEOUT) | 1739 | if (n >= UHCI_RESET_TIMEOUT) | |
1740 | printf("%s: controller did not reset\n", | 1740 | printf("%s: controller did not reset\n", | |
1741 | device_xname(sc->sc_dev)); | 1741 | device_xname(sc->sc_dev)); | |
1742 | } | 1742 | } | |
1743 | 1743 | |||
1744 | usbd_status | 1744 | usbd_status | |
1745 | uhci_run(uhci_softc_t *sc, int run) | 1745 | uhci_run(uhci_softc_t *sc, int run) | |
1746 | { | 1746 | { | |
1747 | int n, running; | 1747 | int n, running; | |
1748 | u_int16_t cmd; | 1748 | u_int16_t cmd; | |
1749 | 1749 | |||
1750 | run = run != 0; | 1750 | run = run != 0; | |
1751 | mutex_spin_enter(&sc->sc_intr_lock); | 1751 | mutex_spin_enter(&sc->sc_intr_lock); | |
1752 | DPRINTF(("uhci_run: setting run=%d\n", run)); | 1752 | DPRINTF(("uhci_run: setting run=%d\n", run)); | |
1753 | cmd = UREAD2(sc, UHCI_CMD); | 1753 | cmd = UREAD2(sc, UHCI_CMD); | |
1754 | if (run) | 1754 | if (run) | |
1755 | cmd |= UHCI_CMD_RS; | 1755 | cmd |= UHCI_CMD_RS; | |
1756 | else | 1756 | else | |
1757 | cmd &= ~UHCI_CMD_RS; | 1757 | cmd &= ~UHCI_CMD_RS; | |
1758 | UHCICMD(sc, cmd); | 1758 | UHCICMD(sc, cmd); | |
1759 | for(n = 0; n < 10; n++) { | 1759 | for(n = 0; n < 10; n++) { | |
1760 | running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH); | 1760 | running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH); | |
1761 | /* return when we've entered the state we want */ | 1761 | /* return when we've entered the state we want */ | |
1762 | if (run == running) { | 1762 | if (run == running) { | |
1763 | mutex_spin_exit(&sc->sc_intr_lock); | 1763 | mutex_spin_exit(&sc->sc_intr_lock); | |
1764 | DPRINTF(("uhci_run: done cmd=0x%x sts=0x%x\n", | 1764 | DPRINTF(("uhci_run: done cmd=0x%x sts=0x%x\n", | |
1765 | UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS))); | 1765 | UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS))); | |
1766 | return (USBD_NORMAL_COMPLETION); | 1766 | return (USBD_NORMAL_COMPLETION); | |
1767 | } | 1767 | } | |
1768 | usb_delay_ms(&sc->sc_bus, 1); | 1768 | usb_delay_ms(&sc->sc_bus, 1); | |
1769 | } | 1769 | } | |
1770 | mutex_spin_exit(&sc->sc_intr_lock); | 1770 | mutex_spin_exit(&sc->sc_intr_lock); | |
1771 | printf("%s: cannot %s\n", device_xname(sc->sc_dev), | 1771 | printf("%s: cannot %s\n", device_xname(sc->sc_dev), | |
1772 | run ? "start" : "stop"); | 1772 | run ? "start" : "stop"); | |
1773 | return (USBD_IOERROR); | 1773 | return (USBD_IOERROR); | |
1774 | } | 1774 | } | |
1775 | 1775 | |||
1776 | /* | 1776 | /* | |
1777 | * Memory management routines. | 1777 | * Memory management routines. | |
1778 | * uhci_alloc_std allocates TDs | 1778 | * uhci_alloc_std allocates TDs | |
1779 | * uhci_alloc_sqh allocates QHs | 1779 | * uhci_alloc_sqh allocates QHs | |
1780 | * These two routines do their own free list management, | 1780 | * These two routines do their own free list management, | |
1781 | * partly for speed, partly because allocating DMAable memory | 1781 | * partly for speed, partly because allocating DMAable memory | |
1782 | * has page size granularaity so much memory would be wasted if | 1782 | * has page size granularaity so much memory would be wasted if | |
1783 | * only one TD/QH (32 bytes) was placed in each allocated chunk. | 1783 | * only one TD/QH (32 bytes) was placed in each allocated chunk. | |
1784 | */ | 1784 | */ | |
1785 | 1785 | |||
1786 | uhci_soft_td_t * | 1786 | uhci_soft_td_t * | |
1787 | uhci_alloc_std(uhci_softc_t *sc) | 1787 | uhci_alloc_std(uhci_softc_t *sc) | |
1788 | { | 1788 | { | |
1789 | uhci_soft_td_t *std; | 1789 | uhci_soft_td_t *std; | |
1790 | usbd_status err; | 1790 | usbd_status err; | |
1791 | int i, offs; | 1791 | int i, offs; | |
1792 | usb_dma_t dma; | 1792 | usb_dma_t dma; | |
1793 | 1793 | |||
1794 | if (sc->sc_freetds == NULL) { | 1794 | if (sc->sc_freetds == NULL) { | |
1795 | DPRINTFN(2,("uhci_alloc_std: allocating chunk\n")); | 1795 | DPRINTFN(2,("uhci_alloc_std: allocating chunk\n")); | |
1796 | err = usb_allocmem(&sc->sc_bus, UHCI_STD_SIZE * UHCI_STD_CHUNK, | 1796 | err = usb_allocmem(&sc->sc_bus, UHCI_STD_SIZE * UHCI_STD_CHUNK, | |
1797 | UHCI_TD_ALIGN, &dma); | 1797 | UHCI_TD_ALIGN, &dma); | |
1798 | if (err) | 1798 | if (err) | |
1799 | return (0); | 1799 | return (0); | |
1800 | for (i = 0; i < UHCI_STD_CHUNK; i++) { | 1800 | for (i = 0; i < UHCI_STD_CHUNK; i++) { | |
1801 | offs = i * UHCI_STD_SIZE; | 1801 | offs = i * UHCI_STD_SIZE; | |
1802 | std = KERNADDR(&dma, offs); | 1802 | std = KERNADDR(&dma, offs); | |
1803 | std->physaddr = DMAADDR(&dma, offs); | 1803 | std->physaddr = DMAADDR(&dma, offs); | |
1804 | std->dma = dma; | 1804 | std->dma = dma; | |
1805 | std->offs = offs; | 1805 | std->offs = offs; | |
1806 | std->link.std = sc->sc_freetds; | 1806 | std->link.std = sc->sc_freetds; | |
1807 | sc->sc_freetds = std; | 1807 | sc->sc_freetds = std; | |
1808 | } | 1808 | } | |
1809 | } | 1809 | } | |
1810 | std = sc->sc_freetds; | 1810 | std = sc->sc_freetds; | |
1811 | sc->sc_freetds = std->link.std; | 1811 | sc->sc_freetds = std->link.std; | |
1812 | memset(&std->td, 0, sizeof(uhci_td_t)); | 1812 | memset(&std->td, 0, sizeof(uhci_td_t)); | |
1813 | return std; | 1813 | return std; | |
1814 | } | 1814 | } | |
1815 | 1815 | |||
1816 | void | 1816 | void | |
1817 | uhci_free_std(uhci_softc_t *sc, uhci_soft_td_t *std) | 1817 | uhci_free_std(uhci_softc_t *sc, uhci_soft_td_t *std) | |
1818 | { | 1818 | { | |
1819 | #ifdef DIAGNOSTIC | 1819 | #ifdef DIAGNOSTIC | |
1820 | #define TD_IS_FREE 0x12345678 | 1820 | #define TD_IS_FREE 0x12345678 | |
1821 | if (le32toh(std->td.td_token) == TD_IS_FREE) { | 1821 | if (le32toh(std->td.td_token) == TD_IS_FREE) { | |
1822 | printf("uhci_free_std: freeing free TD %p\n", std); | 1822 | printf("uhci_free_std: freeing free TD %p\n", std); | |
1823 | return; | 1823 | return; | |
1824 | } | 1824 | } | |
1825 | std->td.td_token = htole32(TD_IS_FREE); | 1825 | std->td.td_token = htole32(TD_IS_FREE); | |
1826 | #endif | 1826 | #endif | |
1827 | std->link.std = sc->sc_freetds; | 1827 | std->link.std = sc->sc_freetds; | |
1828 | sc->sc_freetds = std; | 1828 | sc->sc_freetds = std; | |
1829 | } | 1829 | } | |
1830 | 1830 | |||
1831 | uhci_soft_qh_t * | 1831 | uhci_soft_qh_t * | |
1832 | uhci_alloc_sqh(uhci_softc_t *sc) | 1832 | uhci_alloc_sqh(uhci_softc_t *sc) | |
1833 | { | 1833 | { | |
1834 | uhci_soft_qh_t *sqh; | 1834 | uhci_soft_qh_t *sqh; | |
1835 | usbd_status err; | 1835 | usbd_status err; | |
1836 | int i, offs; | 1836 | int i, offs; | |
1837 | usb_dma_t dma; | 1837 | usb_dma_t dma; | |
1838 | 1838 | |||
1839 | if (sc->sc_freeqhs == NULL) { | 1839 | if (sc->sc_freeqhs == NULL) { | |
1840 | DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n")); | 1840 | DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n")); | |
1841 | err = usb_allocmem(&sc->sc_bus, UHCI_SQH_SIZE * UHCI_SQH_CHUNK, | 1841 | err = usb_allocmem(&sc->sc_bus, UHCI_SQH_SIZE * UHCI_SQH_CHUNK, | |
1842 | UHCI_QH_ALIGN, &dma); | 1842 | UHCI_QH_ALIGN, &dma); | |
1843 | if (err) | 1843 | if (err) | |
1844 | return (0); | 1844 | return (0); | |
1845 | for(i = 0; i < UHCI_SQH_CHUNK; i++) { | 1845 | for(i = 0; i < UHCI_SQH_CHUNK; i++) { | |
1846 | offs = i * UHCI_SQH_SIZE; | 1846 | offs = i * UHCI_SQH_SIZE; | |
1847 | sqh = KERNADDR(&dma, offs); | 1847 | sqh = KERNADDR(&dma, offs); | |
1848 | sqh->physaddr = DMAADDR(&dma, offs); | 1848 | sqh->physaddr = DMAADDR(&dma, offs); | |
1849 | sqh->dma = dma; | 1849 | sqh->dma = dma; | |
1850 | sqh->offs = offs; | 1850 | sqh->offs = offs; | |
1851 | sqh->hlink = sc->sc_freeqhs; | 1851 | sqh->hlink = sc->sc_freeqhs; | |
1852 | sc->sc_freeqhs = sqh; | 1852 | sc->sc_freeqhs = sqh; | |
1853 | } | 1853 | } | |
1854 | } | 1854 | } | |
1855 | sqh = sc->sc_freeqhs; | 1855 | sqh = sc->sc_freeqhs; | |
1856 | sc->sc_freeqhs = sqh->hlink; | 1856 | sc->sc_freeqhs = sqh->hlink; | |
1857 | memset(&sqh->qh, 0, sizeof(uhci_qh_t)); | 1857 | memset(&sqh->qh, 0, sizeof(uhci_qh_t)); | |
1858 | return (sqh); | 1858 | return (sqh); | |
1859 | } | 1859 | } | |
1860 | 1860 | |||
1861 | void | 1861 | void | |
1862 | uhci_free_sqh(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | 1862 | uhci_free_sqh(uhci_softc_t *sc, uhci_soft_qh_t *sqh) | |
1863 | { | 1863 | { | |
1864 | sqh->hlink = sc->sc_freeqhs; | 1864 | sqh->hlink = sc->sc_freeqhs; | |
1865 | sc->sc_freeqhs = sqh; | 1865 | sc->sc_freeqhs = sqh; | |
1866 | } | 1866 | } | |
1867 | 1867 | |||
1868 | void | 1868 | void | |
1869 | uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std, | 1869 | uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std, | |
1870 | uhci_soft_td_t *stdend) | 1870 | uhci_soft_td_t *stdend) | |
1871 | { | 1871 | { | |
1872 | uhci_soft_td_t *p; | 1872 | uhci_soft_td_t *p; | |
1873 | 1873 | |||
1874 | /* | 1874 | /* | |
1875 | * to avoid race condition with the controller which may be looking | 1875 | * to avoid race condition with the controller which may be looking | |
1876 | * at this chain, we need to first invalidate all links, and | 1876 | * at this chain, we need to first invalidate all links, and | |
1877 | * then wait for the controller to move to another queue | 1877 | * then wait for the controller to move to another queue | |
1878 | */ | 1878 | */ | |
1879 | for (p = std; p != stdend; p = p->link.std) { | 1879 | for (p = std; p != stdend; p = p->link.std) { | |
1880 | usb_syncmem(&p->dma, | 1880 | usb_syncmem(&p->dma, | |
1881 | p->offs + offsetof(uhci_td_t, td_link), | 1881 | p->offs + offsetof(uhci_td_t, td_link), | |
1882 | sizeof(p->td.td_link), | 1882 | sizeof(p->td.td_link), | |
1883 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 1883 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
1884 | if ((p->td.td_link & UHCI_PTR_T) == 0) { | 1884 | if ((p->td.td_link & UHCI_PTR_T) == 0) { | |
1885 | p->td.td_link = UHCI_PTR_T; | 1885 | p->td.td_link = UHCI_PTR_T; | |
1886 | usb_syncmem(&p->dma, | 1886 | usb_syncmem(&p->dma, | |
1887 | p->offs + offsetof(uhci_td_t, td_link), | 1887 | p->offs + offsetof(uhci_td_t, td_link), | |
1888 | sizeof(p->td.td_link), | 1888 | sizeof(p->td.td_link), | |
1889 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1889 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1890 | } | 1890 | } | |
1891 | } | 1891 | } | |
1892 | delay(UHCI_QH_REMOVE_DELAY); | 1892 | delay(UHCI_QH_REMOVE_DELAY); | |
1893 | 1893 | |||
1894 | for (; std != stdend; std = p) { | 1894 | for (; std != stdend; std = p) { | |
1895 | p = std->link.std; | 1895 | p = std->link.std; | |
1896 | uhci_free_std(sc, std); | 1896 | uhci_free_std(sc, std); | |
1897 | } | 1897 | } | |
1898 | } | 1898 | } | |
1899 | 1899 | |||
1900 | usbd_status | 1900 | usbd_status | |
1901 | uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len, | 1901 | uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len, | |
1902 | int rd, u_int16_t flags, usb_dma_t *dma, | 1902 | int rd, u_int16_t flags, usb_dma_t *dma, | |
1903 | uhci_soft_td_t **sp, uhci_soft_td_t **ep) | 1903 | uhci_soft_td_t **sp, uhci_soft_td_t **ep) | |
1904 | { | 1904 | { | |
1905 | uhci_soft_td_t *p, *lastp; | 1905 | uhci_soft_td_t *p, *lastp; | |
1906 | uhci_physaddr_t lastlink; | 1906 | uhci_physaddr_t lastlink; | |
1907 | int i, ntd, l, tog, maxp; | 1907 | int i, ntd, l, tog, maxp; | |
1908 | u_int32_t status; | 1908 | u_int32_t status; | |
1909 | int addr = upipe->pipe.device->address; | 1909 | int addr = upipe->pipe.device->address; | |
1910 | int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; | 1910 | int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; | |
1911 | 1911 | |||
1912 | DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d speed=%d " | 1912 | DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d speed=%d " | |
1913 | "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len, | 1913 | "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len, | |
1914 | upipe->pipe.device->speed, flags)); | 1914 | upipe->pipe.device->speed, flags)); | |
1915 | 1915 | |||
1916 | KASSERT(mutex_owned(&sc->sc_lock)); | 1916 | KASSERT(mutex_owned(&sc->sc_lock)); | |
1917 | 1917 | |||
1918 | maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize); | 1918 | maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize); | |
1919 | if (maxp == 0) { | 1919 | if (maxp == 0) { | |
1920 | printf("uhci_alloc_std_chain: maxp=0\n"); | 1920 | printf("uhci_alloc_std_chain: maxp=0\n"); | |
1921 | return (USBD_INVAL); | 1921 | return (USBD_INVAL); | |
1922 | } | 1922 | } | |
1923 | ntd = (len + maxp - 1) / maxp; | 1923 | ntd = (len + maxp - 1) / maxp; | |
1924 | if ((flags & USBD_FORCE_SHORT_XFER) && len % maxp == 0) | 1924 | if ((flags & USBD_FORCE_SHORT_XFER) && len % maxp == 0) | |
1925 | ntd++; | 1925 | ntd++; | |
1926 | DPRINTFN(10, ("uhci_alloc_std_chain: maxp=%d ntd=%d\n", maxp, ntd)); | 1926 | DPRINTFN(10, ("uhci_alloc_std_chain: maxp=%d ntd=%d\n", maxp, ntd)); | |
1927 | if (ntd == 0) { | 1927 | if (ntd == 0) { | |
1928 | *sp = *ep = 0; | 1928 | *sp = *ep = 0; | |
1929 | DPRINTFN(-1,("uhci_alloc_std_chain: ntd=0\n")); | 1929 | DPRINTFN(-1,("uhci_alloc_std_chain: ntd=0\n")); | |
1930 | return (USBD_NORMAL_COMPLETION); | 1930 | return (USBD_NORMAL_COMPLETION); | |
1931 | } | 1931 | } | |
1932 | tog = upipe->nexttoggle; | 1932 | tog = upipe->nexttoggle; | |
1933 | if (ntd % 2 == 0) | 1933 | if (ntd % 2 == 0) | |
1934 | tog ^= 1; | 1934 | tog ^= 1; | |
1935 | upipe->nexttoggle = tog ^ 1; | 1935 | upipe->nexttoggle = tog ^ 1; | |
1936 | lastp = NULL; | 1936 | lastp = NULL; | |
1937 | lastlink = UHCI_PTR_T; | 1937 | lastlink = UHCI_PTR_T; | |
1938 | ntd--; | 1938 | ntd--; | |
1939 | status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE); | 1939 | status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE); | |
1940 | if (upipe->pipe.device->speed == USB_SPEED_LOW) | 1940 | if (upipe->pipe.device->speed == USB_SPEED_LOW) | |
1941 | status |= UHCI_TD_LS; | 1941 | status |= UHCI_TD_LS; | |
1942 | if (flags & USBD_SHORT_XFER_OK) | 1942 | if (flags & USBD_SHORT_XFER_OK) | |
1943 | status |= UHCI_TD_SPD; | 1943 | status |= UHCI_TD_SPD; | |
1944 | usb_syncmem(dma, 0, len, | 1944 | usb_syncmem(dma, 0, len, | |
1945 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | 1945 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | |
1946 | for (i = ntd; i >= 0; i--) { | 1946 | for (i = ntd; i >= 0; i--) { | |
1947 | p = uhci_alloc_std(sc); | 1947 | p = uhci_alloc_std(sc); | |
1948 | if (p == NULL) { | 1948 | if (p == NULL) { | |
1949 | KASSERT(lastp != NULL); | 1949 | KASSERT(lastp != NULL); | |
1950 | uhci_free_std_chain(sc, lastp, NULL); | 1950 | uhci_free_std_chain(sc, lastp, NULL); | |
1951 | return (USBD_NOMEM); | 1951 | return (USBD_NOMEM); | |
1952 | } | 1952 | } | |
1953 | p->link.std = lastp; | 1953 | p->link.std = lastp; | |
1954 | p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD); | 1954 | p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD); | |
1955 | lastp = p; | 1955 | lastp = p; | |
1956 | lastlink = p->physaddr; | 1956 | lastlink = p->physaddr; | |
1957 | p->td.td_status = htole32(status); | 1957 | p->td.td_status = htole32(status); | |
1958 | if (i == ntd) { | 1958 | if (i == ntd) { | |
1959 | /* last TD */ | 1959 | /* last TD */ | |
1960 | l = len % maxp; | 1960 | l = len % maxp; | |
1961 | if (l == 0 && !(flags & USBD_FORCE_SHORT_XFER)) | 1961 | if (l == 0 && !(flags & USBD_FORCE_SHORT_XFER)) | |
1962 | l = maxp; | 1962 | l = maxp; | |
1963 | *ep = p; | 1963 | *ep = p; | |
1964 | } else | 1964 | } else | |
1965 | l = maxp; | 1965 | l = maxp; | |
1966 | p->td.td_token = | 1966 | p->td.td_token = | |
1967 | htole32(rd ? UHCI_TD_IN (l, endpt, addr, tog) : | 1967 | htole32(rd ? UHCI_TD_IN (l, endpt, addr, tog) : | |
1968 | UHCI_TD_OUT(l, endpt, addr, tog)); | 1968 | UHCI_TD_OUT(l, endpt, addr, tog)); | |
1969 | p->td.td_buffer = htole32(DMAADDR(dma, i * maxp)); | 1969 | p->td.td_buffer = htole32(DMAADDR(dma, i * maxp)); | |
1970 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), | 1970 | usb_syncmem(&p->dma, p->offs, sizeof(p->td), | |
1971 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 1971 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
1972 | tog ^= 1; | 1972 | tog ^= 1; | |
1973 | } | 1973 | } | |
1974 | *sp = lastp; | 1974 | *sp = lastp; | |
1975 | DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n", | 1975 | DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n", | |
1976 | upipe->nexttoggle)); | 1976 | upipe->nexttoggle)); | |
1977 | return (USBD_NORMAL_COMPLETION); | 1977 | return (USBD_NORMAL_COMPLETION); | |
1978 | } | 1978 | } | |
1979 | 1979 | |||
1980 | void | 1980 | void | |
1981 | uhci_device_clear_toggle(usbd_pipe_handle pipe) | 1981 | uhci_device_clear_toggle(usbd_pipe_handle pipe) | |
1982 | { | 1982 | { | |
1983 | struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; | 1983 | struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; | |
1984 | upipe->nexttoggle = 0; | 1984 | upipe->nexttoggle = 0; | |
1985 | } | 1985 | } | |
1986 | 1986 | |||
1987 | void | 1987 | void | |
1988 | uhci_noop(usbd_pipe_handle pipe) | 1988 | uhci_noop(usbd_pipe_handle pipe) | |
1989 | { | 1989 | { | |
1990 | } | 1990 | } | |
1991 | 1991 | |||
1992 | usbd_status | 1992 | usbd_status | |
1993 | uhci_device_bulk_transfer(usbd_xfer_handle xfer) | 1993 | uhci_device_bulk_transfer(usbd_xfer_handle xfer) | |
1994 | { | 1994 | { | |
1995 | uhci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 1995 | uhci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
1996 | usbd_status err; | 1996 | usbd_status err; | |
1997 | 1997 | |||
1998 | /* Insert last in queue. */ | 1998 | /* Insert last in queue. */ | |
1999 | mutex_enter(&sc->sc_lock); | 1999 | mutex_enter(&sc->sc_lock); | |
2000 | err = usb_insert_transfer(xfer); | 2000 | err = usb_insert_transfer(xfer); | |
2001 | mutex_exit(&sc->sc_lock); | 2001 | mutex_exit(&sc->sc_lock); | |
2002 | if (err) | 2002 | if (err) | |
2003 | return (err); | 2003 | return (err); | |
2004 | 2004 | |||
2005 | /* | 2005 | /* | |
2006 | * Pipe isn't running (otherwise err would be USBD_INPROG), | 2006 | * Pipe isn't running (otherwise err would be USBD_INPROG), | |
2007 | * so start it first. | 2007 | * so start it first. | |
2008 | */ | 2008 | */ | |
2009 | return (uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 2009 | return (uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
2010 | } | 2010 | } | |
2011 | 2011 | |||
2012 | usbd_status | 2012 | usbd_status | |
2013 | uhci_device_bulk_start(usbd_xfer_handle xfer) | 2013 | uhci_device_bulk_start(usbd_xfer_handle xfer) | |
2014 | { | 2014 | { | |
2015 | struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; | 2015 | struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; | |
2016 | usbd_device_handle dev = upipe->pipe.device; | 2016 | usbd_device_handle dev = upipe->pipe.device; | |
2017 | uhci_softc_t *sc = dev->bus->hci_private; | 2017 | uhci_softc_t *sc = dev->bus->hci_private; | |
2018 | uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; | 2018 | uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; | |
2019 | uhci_soft_td_t *data, *dataend; | 2019 | uhci_soft_td_t *data, *dataend; | |
2020 | uhci_soft_qh_t *sqh; | 2020 | uhci_soft_qh_t *sqh; | |
2021 | usbd_status err; | 2021 | usbd_status err; | |
2022 | int len, isread, endpt; | 2022 | int len, isread, endpt; | |
2023 | 2023 | |||
2024 | DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%d flags=%d ii=%p\n", | 2024 | DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%d flags=%d ii=%p\n", | |
2025 | xfer, xfer->length, xfer->flags, ii)); | 2025 | xfer, xfer->length, xfer->flags, ii)); | |
2026 | 2026 | |||
2027 | if (sc->sc_dying) | 2027 | if (sc->sc_dying) | |
2028 | return (USBD_IOERROR); | 2028 | return (USBD_IOERROR); | |
2029 | 2029 | |||
2030 | #ifdef DIAGNOSTIC | 2030 | #ifdef DIAGNOSTIC | |
2031 | if (xfer->rqflags & URQ_REQUEST) | 2031 | if (xfer->rqflags & URQ_REQUEST) | |
2032 | panic("uhci_device_bulk_transfer: a request"); | 2032 | panic("uhci_device_bulk_transfer: a request"); | |
2033 | #endif | 2033 | #endif | |
2034 | 2034 | |||
2035 | mutex_enter(&sc->sc_lock); | 2035 | mutex_enter(&sc->sc_lock); | |
2036 | 2036 | |||
2037 | len = xfer->length; | 2037 | len = xfer->length; | |
2038 | endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; | 2038 | endpt = upipe->pipe.endpoint->edesc->bEndpointAddress; | |
2039 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | 2039 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | |
2040 | sqh = upipe->u.bulk.sqh; | 2040 | sqh = upipe->u.bulk.sqh; | |
2041 | 2041 | |||
2042 | upipe->u.bulk.isread = isread; | 2042 | upipe->u.bulk.isread = isread; | |
2043 | upipe->u.bulk.length = len; | 2043 | upipe->u.bulk.length = len; | |
2044 | 2044 | |||
2045 | err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags, | 2045 | err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags, | |
2046 | &xfer->dmabuf, &data, &dataend); | 2046 | &xfer->dmabuf, &data, &dataend); | |
2047 | if (err) { | 2047 | if (err) { | |
2048 | mutex_exit(&sc->sc_lock); | 2048 | mutex_exit(&sc->sc_lock); | |
2049 | return (err); | 2049 | return (err); | |
2050 | } | 2050 | } | |
2051 | dataend->td.td_status |= htole32(UHCI_TD_IOC); | 2051 | dataend->td.td_status |= htole32(UHCI_TD_IOC); | |
2052 | usb_syncmem(&dataend->dma, | 2052 | usb_syncmem(&dataend->dma, | |
2053 | dataend->offs + offsetof(uhci_td_t, td_status), | 2053 | dataend->offs + offsetof(uhci_td_t, td_status), | |
2054 | sizeof(dataend->td.td_status), | 2054 | sizeof(dataend->td.td_status), | |
2055 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2055 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2056 | 2056 | |||
2057 | 2057 | |||
2058 | #ifdef UHCI_DEBUG | 2058 | #ifdef UHCI_DEBUG | |
2059 | if (uhcidebug > 8) { | 2059 | if (uhcidebug > 8) { | |
2060 | DPRINTF(("uhci_device_bulk_transfer: data(1)\n")); | 2060 | DPRINTF(("uhci_device_bulk_transfer: data(1)\n")); | |
2061 | uhci_dump_tds(data); | 2061 | uhci_dump_tds(data); | |
2062 | } | 2062 | } | |
2063 | #endif | 2063 | #endif | |
2064 | 2064 | |||
2065 | /* Set up interrupt info. */ | 2065 | /* Set up interrupt info. */ | |
2066 | ii->xfer = xfer; | 2066 | ii->xfer = xfer; | |
2067 | ii->stdstart = data; | 2067 | ii->stdstart = data; | |
2068 | ii->stdend = dataend; | 2068 | ii->stdend = dataend; | |
2069 | #ifdef DIAGNOSTIC | 2069 | #ifdef DIAGNOSTIC | |
2070 | if (!ii->isdone) { | 2070 | if (!ii->isdone) { | |
2071 | printf("uhci_device_bulk_transfer: not done, ii=%p\n", ii); | 2071 | printf("uhci_device_bulk_transfer: not done, ii=%p\n", ii); | |
2072 | } | 2072 | } | |
2073 | ii->isdone = 0; | 2073 | ii->isdone = 0; | |
2074 | #endif | 2074 | #endif | |
2075 | 2075 | |||
2076 | sqh->elink = data; | 2076 | sqh->elink = data; | |
2077 | sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD); | 2077 | sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD); | |
2078 | /* uhci_add_bulk() will do usb_syncmem(sqh) */ | 2078 | /* uhci_add_bulk() will do usb_syncmem(sqh) */ | |
2079 | 2079 | |||
2080 | uhci_add_bulk(sc, sqh); | 2080 | uhci_add_bulk(sc, sqh); | |
2081 | uhci_add_intr_info(sc, ii); | 2081 | uhci_add_intr_info(sc, ii); | |
2082 | 2082 | |||
2083 | if (xfer->timeout && !sc->sc_bus.use_polling) { | 2083 | if (xfer->timeout && !sc->sc_bus.use_polling) { | |
2084 | callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout), | 2084 | callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout), | |
2085 | uhci_timeout, ii); | 2085 | uhci_timeout, ii); | |
2086 | } | 2086 | } | |
2087 | xfer->status = USBD_IN_PROGRESS; | 2087 | xfer->status = USBD_IN_PROGRESS; | |
2088 | 2088 | |||
2089 | #ifdef UHCI_DEBUG | 2089 | #ifdef UHCI_DEBUG | |
2090 | if (uhcidebug > 10) { | 2090 | if (uhcidebug > 10) { | |
2091 | DPRINTF(("uhci_device_bulk_transfer: data(2)\n")); | 2091 | DPRINTF(("uhci_device_bulk_transfer: data(2)\n")); | |
2092 | uhci_dump_tds(data); | 2092 | uhci_dump_tds(data); | |
2093 | } | 2093 | } | |
2094 | #endif | 2094 | #endif | |
2095 | 2095 | |||
2096 | if (sc->sc_bus.use_polling) | 2096 | if (sc->sc_bus.use_polling) | |
2097 | uhci_waitintr(sc, xfer); | 2097 | uhci_waitintr(sc, xfer); | |
2098 | 2098 | |||
2099 | mutex_exit(&sc->sc_lock); | 2099 | mutex_exit(&sc->sc_lock); | |
2100 | return (USBD_IN_PROGRESS); | 2100 | return (USBD_IN_PROGRESS); | |
2101 | } | 2101 | } | |
2102 | 2102 | |||
2103 | /* Abort a device bulk request. */ | 2103 | /* Abort a device bulk request. */ | |
2104 | void | 2104 | void | |
2105 | uhci_device_bulk_abort(usbd_xfer_handle xfer) | 2105 | uhci_device_bulk_abort(usbd_xfer_handle xfer) | |
2106 | { | 2106 | { | |
2107 | DPRINTF(("uhci_device_bulk_abort:\n")); | 2107 | DPRINTF(("uhci_device_bulk_abort:\n")); | |
2108 | uhci_abort_xfer(xfer, USBD_CANCELLED); | 2108 | uhci_abort_xfer(xfer, USBD_CANCELLED); | |
2109 | } | 2109 | } | |
2110 | 2110 | |||
2111 | /* | 2111 | /* | |
2112 | * Abort a device request. | 2112 | * Abort a device request. | |
2113 | * If this routine is called at splusb() it guarantees that the request | 2113 | * If this routine is called at splusb() it guarantees that the request | |
2114 | * will be removed from the hardware scheduling and that the callback | 2114 | * will be removed from the hardware scheduling and that the callback | |
2115 | * for it will be called with USBD_CANCELLED status. | 2115 | * for it will be called with USBD_CANCELLED status. | |
2116 | * It's impossible to guarantee that the requested transfer will not | 2116 | * It's impossible to guarantee that the requested transfer will not | |
2117 | * have happened since the hardware runs concurrently. | 2117 | * have happened since the hardware runs concurrently. | |
2118 | * If the transaction has already happened we rely on the ordinary | 2118 | * If the transaction has already happened we rely on the ordinary | |
2119 | * interrupt processing to process it. | 2119 | * interrupt processing to process it. | |
2120 | */ | 2120 | */ | |
2121 | void | 2121 | void | |
2122 | uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) | 2122 | uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) | |
2123 | { | 2123 | { | |
2124 | uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; | 2124 | uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; | |
2125 | struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; | 2125 | struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; | |
2126 | uhci_softc_t *sc = upipe->pipe.device->bus->hci_private; | 2126 | uhci_softc_t *sc = upipe->pipe.device->bus->hci_private; | |
2127 | uhci_soft_td_t *std; | 2127 | uhci_soft_td_t *std; | |
2128 | int wake; | 2128 | int wake; | |
2129 | 2129 | |||
2130 | DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status)); | 2130 | DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status)); | |
2131 | 2131 | |||
2132 | if (sc->sc_dying) { | 2132 | if (sc->sc_dying) { | |
2133 | /* If we're dying, just do the software part. */ | 2133 | /* If we're dying, just do the software part. */ | |
2134 | mutex_enter(&sc->sc_lock); | 2134 | mutex_enter(&sc->sc_lock); | |
2135 | xfer->status = status; /* make software ignore it */ | 2135 | xfer->status = status; /* make software ignore it */ | |
2136 | callout_stop(&xfer->timeout_handle); | 2136 | callout_stop(&xfer->timeout_handle); | |
2137 | usb_transfer_complete(xfer); | 2137 | usb_transfer_complete(xfer); | |
2138 | mutex_exit(&sc->sc_lock); | 2138 | mutex_exit(&sc->sc_lock); | |
2139 | return; | 2139 | return; | |
2140 | } | 2140 | } | |
2141 | 2141 | |||
2142 | if (xfer->device->bus->intr_context || !curproc) | 2142 | if (xfer->device->bus->intr_context || !curproc) | |
2143 | panic("uhci_abort_xfer: not in process context"); | 2143 | panic("uhci_abort_xfer: not in process context"); | |
2144 | 2144 | |||
2145 | mutex_enter(&sc->sc_lock); | 2145 | mutex_enter(&sc->sc_lock); | |
2146 | 2146 | |||
2147 | /* | 2147 | /* | |
2148 | * If an abort is already in progress then just wait for it to | 2148 | * If an abort is already in progress then just wait for it to | |
2149 | * complete and return. | 2149 | * complete and return. | |
2150 | */ | 2150 | */ | |
2151 | if (xfer->hcflags & UXFER_ABORTING) { | 2151 | if (xfer->hcflags & UXFER_ABORTING) { | |
2152 | DPRINTFN(2, ("uhci_abort_xfer: already aborting\n")); | 2152 | DPRINTFN(2, ("uhci_abort_xfer: already aborting\n")); | |
2153 | #ifdef DIAGNOSTIC | 2153 | #ifdef DIAGNOSTIC | |
2154 | if (status == USBD_TIMEOUT) | 2154 | if (status == USBD_TIMEOUT) | |
2155 | printf("uhci_abort_xfer: TIMEOUT while aborting\n"); | 2155 | printf("uhci_abort_xfer: TIMEOUT while aborting\n"); | |
2156 | #endif | 2156 | #endif | |
2157 | /* Override the status which might be USBD_TIMEOUT. */ | 2157 | /* Override the status which might be USBD_TIMEOUT. */ | |
2158 | xfer->status = status; | 2158 | xfer->status = status; | |
2159 | DPRINTFN(2, ("uhci_abort_xfer: waiting for abort to finish\n")); | 2159 | DPRINTFN(2, ("uhci_abort_xfer: waiting for abort to finish\n")); | |
2160 | xfer->hcflags |= UXFER_ABORTWAIT; | 2160 | xfer->hcflags |= UXFER_ABORTWAIT; | |
2161 | while (xfer->hcflags & UXFER_ABORTING) | 2161 | while (xfer->hcflags & UXFER_ABORTING) | |
2162 | cv_wait(&xfer->hccv, &sc->sc_lock); | 2162 | cv_wait(&xfer->hccv, &sc->sc_lock); | |
2163 | goto done; | 2163 | goto done; | |
2164 | } | 2164 | } | |
2165 | xfer->hcflags |= UXFER_ABORTING; | 2165 | xfer->hcflags |= UXFER_ABORTING; | |
2166 | 2166 | |||
2167 | /* | 2167 | /* | |
2168 | * Step 1: Make interrupt routine and hardware ignore xfer. | 2168 | * Step 1: Make interrupt routine and hardware ignore xfer. | |
2169 | */ | 2169 | */ | |
2170 | xfer->status = status; /* make software ignore it */ | 2170 | xfer->status = status; /* make software ignore it */ | |
2171 | callout_stop(&xfer->timeout_handle); | 2171 | callout_stop(&xfer->timeout_handle); | |
2172 | DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii)); | 2172 | DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii)); | |
2173 | for (std = ii->stdstart; std != NULL; std = std->link.std) { | 2173 | for (std = ii->stdstart; std != NULL; std = std->link.std) { | |
2174 | usb_syncmem(&std->dma, | 2174 | usb_syncmem(&std->dma, | |
2175 | std->offs + offsetof(uhci_td_t, td_status), | 2175 | std->offs + offsetof(uhci_td_t, td_status), | |
2176 | sizeof(std->td.td_status), | 2176 | sizeof(std->td.td_status), | |
2177 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | 2177 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | |
2178 | std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC)); | 2178 | std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC)); | |
2179 | usb_syncmem(&std->dma, | 2179 | usb_syncmem(&std->dma, | |
2180 | std->offs + offsetof(uhci_td_t, td_status), | 2180 | std->offs + offsetof(uhci_td_t, td_status), | |
2181 | sizeof(std->td.td_status), | 2181 | sizeof(std->td.td_status), | |
2182 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 2182 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
2183 | } | 2183 | } | |
2184 | 2184 | |||
2185 | /* | 2185 | /* | |
2186 | * Step 2: Wait until we know hardware has finished any possible | 2186 | * Step 2: Wait until we know hardware has finished any possible | |
2187 | * use of the xfer. Also make sure the soft interrupt routine | 2187 | * use of the xfer. Also make sure the soft interrupt routine | |
2188 | * has run. | 2188 | * has run. | |
2189 | */ | 2189 | */ | |
2190 | usb_delay_ms(upipe->pipe.device->bus, 2); /* Hardware finishes in 1ms */ | 2190 | usb_delay_ms(upipe->pipe.device->bus, 2); /* Hardware finishes in 1ms */ | |
2191 | sc->sc_softwake = 1; | 2191 | sc->sc_softwake = 1; | |
2192 | usb_schedsoftintr(&sc->sc_bus); | 2192 | usb_schedsoftintr(&sc->sc_bus); | |
2193 | DPRINTFN(1,("uhci_abort_xfer: cv_wait\n")); | 2193 | DPRINTFN(1,("uhci_abort_xfer: cv_wait\n")); | |
2194 | cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); | 2194 | cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); | |
2195 | 2195 | |||
2196 | /* | 2196 | /* | |
2197 | * Step 3: Execute callback. | 2197 | * Step 3: Execute callback. | |
2198 | */ | 2198 | */ | |
2199 | DPRINTFN(1,("uhci_abort_xfer: callback\n")); | 2199 | DPRINTFN(1,("uhci_abort_xfer: callback\n")); | |
2200 | #ifdef DIAGNOSTIC | 2200 | #ifdef DIAGNOSTIC | |
2201 | ii->isdone = 1; | 2201 | ii->isdone = 1; | |
2202 | #endif | 2202 | #endif | |
2203 | wake = xfer->hcflags & UXFER_ABORTWAIT; | 2203 | wake = xfer->hcflags & UXFER_ABORTWAIT; | |
2204 | xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | 2204 | xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | |
2205 | usb_transfer_complete(xfer); | 2205 | usb_transfer_complete(xfer); | |
2206 | if (wake) | 2206 | if (wake) | |
2207 | cv_broadcast(&xfer->hccv); | 2207 | cv_broadcast(&xfer->hccv); | |
2208 | done: | 2208 | done: | |
2209 | mutex_exit(&sc->sc_lock); | 2209 | mutex_exit(&sc->sc_lock); | |
2210 | } | 2210 | } | |
2211 | 2211 | |||
2212 | /* Close a device bulk pipe. */ | 2212 | /* Close a device bulk pipe. */ | |
2213 | void | 2213 | void | |
2214 | uhci_device_bulk_close(usbd_pipe_handle pipe) | 2214 | uhci_device_bulk_close(usbd_pipe_handle pipe) | |
2215 | { | 2215 | { | |
2216 | struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; | 2216 | struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; | |
2217 | usbd_device_handle dev = upipe->pipe.device; | 2217 | usbd_device_handle dev = upipe->pipe.device; | |
2218 | uhci_softc_t *sc = dev->bus->hci_private; | 2218 | uhci_softc_t *sc = dev->bus->hci_private; | |
2219 | 2219 | |||
2220 | uhci_free_sqh(sc, upipe->u.bulk.sqh); | 2220 | uhci_free_sqh(sc, upipe->u.bulk.sqh); | |
2221 | 2221 | |||
2222 | pipe->endpoint->datatoggle = upipe->nexttoggle; | 2222 | pipe->endpoint->datatoggle = upipe->nexttoggle; | |
2223 | } | 2223 | } | |
2224 | 2224 | |||
2225 | usbd_status | 2225 | usbd_status | |
2226 | uhci_device_ctrl_transfer(usbd_xfer_handle xfer) | 2226 | uhci_device_ctrl_transfer(usbd_xfer_handle xfer) | |
2227 | { | 2227 | { | |
2228 | uhci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2228 | uhci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2229 | usbd_status err; | 2229 | usbd_status err; | |
2230 | 2230 | |||
2231 | /* Insert last in queue. */ | 2231 | /* Insert last in queue. */ | |
2232 | mutex_enter(&sc->sc_lock); | 2232 | mutex_enter(&sc->sc_lock); | |
2233 | err = usb_insert_transfer(xfer); | 2233 | err = usb_insert_transfer(xfer); | |
2234 | mutex_exit(&sc->sc_lock); | 2234 | mutex_exit(&sc->sc_lock); | |
2235 | if (err) | 2235 | if (err) | |
2236 | return (err); | 2236 | return (err); | |
2237 | 2237 | |||
2238 | /* | 2238 | /* | |
2239 | * Pipe isn't running (otherwise err would be USBD_INPROG), | 2239 | * Pipe isn't running (otherwise err would be USBD_INPROG), | |
2240 | * so start it first. | 2240 | * so start it first. | |
2241 | */ | 2241 | */ | |
2242 | return (uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | 2242 | return (uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue))); | |
2243 | } | 2243 | } | |
2244 | 2244 | |||
2245 | usbd_status | 2245 | usbd_status | |
2246 | uhci_device_ctrl_start(usbd_xfer_handle xfer) | 2246 | uhci_device_ctrl_start(usbd_xfer_handle xfer) | |
2247 | { | 2247 | { | |
2248 | uhci_softc_t *sc = xfer->pipe->device->bus->hci_private; | 2248 | uhci_softc_t *sc = xfer->pipe->device->bus->hci_private; | |
2249 | usbd_status err; | 2249 | usbd_status err; | |
2250 | 2250 | |||
2251 | if (sc->sc_dying) | 2251 | if (sc->sc_dying) | |
2252 | return (USBD_IOERROR); | 2252 | return (USBD_IOERROR); | |
2253 | 2253 | |||
2254 | #ifdef DIAGNOSTIC | 2254 | #ifdef DIAGNOSTIC | |
2255 | if (!(xfer->rqflags & URQ_REQUEST)) | 2255 | if (!(xfer->rqflags & URQ_REQUEST)) | |
2256 | panic("uhci_device_ctrl_transfer: not a request"); | 2256 | panic("uhci_device_ctrl_transfer: not a request"); | |
2257 | #endif | 2257 | #endif |
--- src/sys/dev/usb/usb.c 2011/12/07 22:52:17 1.125.6.3
+++ src/sys/dev/usb/usb.c 2011/12/08 02:51:08 1.125.6.4
@@ -1,1037 +1,1044 @@ | @@ -1,1037 +1,1044 @@ | |||
1 | /* $NetBSD: usb.c,v 1.125.6.3 2011/12/07 22:52:17 mrg Exp $ */ | 1 | /* $NetBSD: usb.c,v 1.125.6.4 2011/12/08 02:51:08 mrg Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1998, 2002, 2008 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1998, 2002, 2008 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | 8 | * by Lennart Augustsson (lennart@augustsson.net) at | |
9 | * Carlstedt Research & Technology. | 9 | * Carlstedt Research & Technology. | |
10 | * | 10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | 12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | 13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright | |
15 | * notice, this list of conditions and the following disclaimer. | 15 | * notice, this list of conditions and the following disclaimer. | |
16 | * 2. Redistributions in binary form must reproduce the above copyright | 16 | * 2. Redistributions in binary form must reproduce the above copyright | |
17 | * notice, this list of conditions and the following disclaimer in the | 17 | * notice, this list of conditions and the following disclaimer in the | |
18 | * documentation and/or other materials provided with the distribution. | 18 | * documentation and/or other materials provided with the distribution. | |
19 | * | 19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
30 | * POSSIBILITY OF SUCH DAMAGE. | 30 | * POSSIBILITY OF SUCH DAMAGE. | |
31 | */ | 31 | */ | |
32 | 32 | |||
33 | /* | 33 | /* | |
34 | * USB specifications and other documentation can be found at | 34 | * USB specifications and other documentation can be found at | |
35 | * http://www.usb.org/developers/docs/ and | 35 | * http://www.usb.org/developers/docs/ and | |
36 | * http://www.usb.org/developers/devclass_docs/ | 36 | * http://www.usb.org/developers/devclass_docs/ | |
37 | */ | 37 | */ | |
38 | 38 | |||
39 | #include <sys/cdefs.h> | 39 | #include <sys/cdefs.h> | |
40 | __KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.125.6.3 2011/12/07 22:52:17 mrg Exp $"); | 40 | __KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.125.6.4 2011/12/08 02:51:08 mrg Exp $"); | |
41 | 41 | |||
42 | #include "opt_compat_netbsd.h" | 42 | #include "opt_compat_netbsd.h" | |
43 | #include "opt_usb.h" | 43 | #include "opt_usb.h" | |
44 | 44 | |||
45 | #include <sys/param.h> | 45 | #include <sys/param.h> | |
46 | #include <sys/systm.h> | 46 | #include <sys/systm.h> | |
47 | #include <sys/kernel.h> | 47 | #include <sys/kernel.h> | |
48 | #include <sys/malloc.h> | 48 | #include <sys/malloc.h> | |
49 | #include <sys/device.h> | 49 | #include <sys/device.h> | |
50 | #include <sys/kthread.h> | 50 | #include <sys/kthread.h> | |
51 | #include <sys/proc.h> | 51 | #include <sys/proc.h> | |
52 | #include <sys/conf.h> | 52 | #include <sys/conf.h> | |
53 | #include <sys/fcntl.h> | 53 | #include <sys/fcntl.h> | |
54 | #include <sys/poll.h> | 54 | #include <sys/poll.h> | |
55 | #include <sys/select.h> | 55 | #include <sys/select.h> | |
56 | #include <sys/vnode.h> | 56 | #include <sys/vnode.h> | |
57 | #include <sys/signalvar.h> | 57 | #include <sys/signalvar.h> | |
58 | #include <sys/intr.h> | 58 | #include <sys/intr.h> | |
59 | #include <sys/module.h> | 59 | #include <sys/module.h> | |
60 | 60 | |||
61 | #include <dev/usb/usb.h> | 61 | #include <dev/usb/usb.h> | |
62 | #include <dev/usb/usbdi.h> | 62 | #include <dev/usb/usbdi.h> | |
63 | #include <dev/usb/usbdi_util.h> | 63 | #include <dev/usb/usbdi_util.h> | |
64 | #include <dev/usb/usb_verbose.h> | 64 | #include <dev/usb/usb_verbose.h> | |
65 | 65 | |||
66 | #define USB_DEV_MINOR 255 | 66 | #define USB_DEV_MINOR 255 | |
67 | 67 | |||
68 | #include <sys/bus.h> | 68 | #include <sys/bus.h> | |
69 | 69 | |||
70 | #include <dev/usb/usbdivar.h> | 70 | #include <dev/usb/usbdivar.h> | |
71 | #include <dev/usb/usb_quirks.h> | 71 | #include <dev/usb/usb_quirks.h> | |
72 | 72 | |||
73 | #ifdef USB_DEBUG | 73 | #ifdef USB_DEBUG | |
74 | #define DPRINTF(x) if (usbdebug) printf x | 74 | #define DPRINTF(x) if (usbdebug) printf x | |
75 | #define DPRINTFN(n,x) if (usbdebug>(n)) printf x | 75 | #define DPRINTFN(n,x) if (usbdebug>(n)) printf x | |
76 | int usbdebug = 0; | 76 | int usbdebug = 0; | |
77 | /* | 77 | /* | |
78 | * 0 - do usual exploration | 78 | * 0 - do usual exploration | |
79 | * 1 - do not use timeout exploration | 79 | * 1 - do not use timeout exploration | |
80 | * >1 - do no exploration | 80 | * >1 - do no exploration | |
81 | */ | 81 | */ | |
82 | int usb_noexplore = 0; | 82 | int usb_noexplore = 0; | |
83 | #else | 83 | #else | |
84 | #define DPRINTF(x) | 84 | #define DPRINTF(x) | |
85 | #define DPRINTFN(n,x) | 85 | #define DPRINTFN(n,x) | |
86 | #define usb_noexplore 0 | 86 | #define usb_noexplore 0 | |
87 | #endif | 87 | #endif | |
88 | 88 | |||
89 | struct usb_softc { | 89 | struct usb_softc { | |
90 | #if 0 | 90 | #if 0 | |
91 | device_t sc_dev; /* base device */ | 91 | device_t sc_dev; /* base device */ | |
92 | #endif | 92 | #endif | |
93 | usbd_bus_handle sc_bus; /* USB controller */ | 93 | usbd_bus_handle sc_bus; /* USB controller */ | |
94 | struct usbd_port sc_port; /* dummy port for root hub */ | 94 | struct usbd_port sc_port; /* dummy port for root hub */ | |
95 | 95 | |||
96 | struct lwp *sc_event_thread; | 96 | struct lwp *sc_event_thread; | |
97 | 97 | |||
98 | char sc_dying; | 98 | char sc_dying; | |
99 | }; | 99 | }; | |
100 | 100 | |||
101 | struct usb_taskq { | 101 | struct usb_taskq { | |
102 | TAILQ_HEAD(, usb_task) tasks; | 102 | TAILQ_HEAD(, usb_task) tasks; | |
103 | struct lwp *task_thread_lwp; | 103 | struct lwp *task_thread_lwp; | |
104 | const char *name; | 104 | const char *name; | |
105 | int taskcreated; /* task thread exists. */ | 105 | int taskcreated; /* task thread exists. */ | |
106 | }; | 106 | }; | |
107 | 107 | |||
108 | static struct usb_taskq usb_taskq[USB_NUM_TASKQS]; | 108 | static struct usb_taskq usb_taskq[USB_NUM_TASKQS]; | |
109 | 109 | |||
110 | dev_type_open(usbopen); | 110 | dev_type_open(usbopen); | |
111 | dev_type_close(usbclose); | 111 | dev_type_close(usbclose); | |
112 | dev_type_read(usbread); | 112 | dev_type_read(usbread); | |
113 | dev_type_ioctl(usbioctl); | 113 | dev_type_ioctl(usbioctl); | |
114 | dev_type_poll(usbpoll); | 114 | dev_type_poll(usbpoll); | |
115 | dev_type_kqfilter(usbkqfilter); | 115 | dev_type_kqfilter(usbkqfilter); | |
116 | 116 | |||
117 | const struct cdevsw usb_cdevsw = { | 117 | const struct cdevsw usb_cdevsw = { | |
118 | usbopen, usbclose, usbread, nowrite, usbioctl, | 118 | usbopen, usbclose, usbread, nowrite, usbioctl, | |
119 | nostop, notty, usbpoll, nommap, usbkqfilter, D_OTHER, | 119 | nostop, notty, usbpoll, nommap, usbkqfilter, D_OTHER, | |
120 | }; | 120 | }; | |
121 | 121 | |||
122 | Static void usb_discover(struct usb_softc *); | 122 | Static void usb_discover(struct usb_softc *); | |
123 | Static void usb_create_event_thread(device_t); | 123 | Static void usb_create_event_thread(device_t); | |
124 | Static void usb_event_thread(void *); | 124 | Static void usb_event_thread(void *); | |
125 | Static void usb_task_thread(void *); | 125 | Static void usb_task_thread(void *); | |
126 | 126 | |||
127 | #define USB_MAX_EVENTS 100 | 127 | #define USB_MAX_EVENTS 100 | |
128 | struct usb_event_q { | 128 | struct usb_event_q { | |
129 | struct usb_event ue; | 129 | struct usb_event ue; | |
130 | SIMPLEQ_ENTRY(usb_event_q) next; | 130 | SIMPLEQ_ENTRY(usb_event_q) next; | |
131 | }; | 131 | }; | |
132 | Static SIMPLEQ_HEAD(, usb_event_q) usb_events = | 132 | Static SIMPLEQ_HEAD(, usb_event_q) usb_events = | |
133 | SIMPLEQ_HEAD_INITIALIZER(usb_events); | 133 | SIMPLEQ_HEAD_INITIALIZER(usb_events); | |
134 | Static int usb_nevents = 0; | 134 | Static int usb_nevents = 0; | |
135 | Static struct selinfo usb_selevent; | 135 | Static struct selinfo usb_selevent; | |
136 | Static proc_t *usb_async_proc; /* process that wants USB SIGIO */ | 136 | Static proc_t *usb_async_proc; /* process that wants USB SIGIO */ | |
137 | Static void *usb_async_sih; | 137 | Static void *usb_async_sih; | |
138 | Static int usb_dev_open = 0; | 138 | Static int usb_dev_open = 0; | |
139 | Static struct usb_event *usb_alloc_event(void); | 139 | Static struct usb_event *usb_alloc_event(void); | |
140 | Static void usb_free_event(struct usb_event *); | 140 | Static void usb_free_event(struct usb_event *); | |
141 | Static void usb_add_event(int, struct usb_event *); | 141 | Static void usb_add_event(int, struct usb_event *); | |
142 | Static int usb_get_next_event(struct usb_event *); | 142 | Static int usb_get_next_event(struct usb_event *); | |
143 | Static void usb_async_intr(void *); | 143 | Static void usb_async_intr(void *); | |
144 | 144 | |||
145 | #ifdef COMPAT_30 | 145 | #ifdef COMPAT_30 | |
146 | Static void usb_copy_old_devinfo(struct usb_device_info_old *, const struct usb_device_info *); | 146 | Static void usb_copy_old_devinfo(struct usb_device_info_old *, const struct usb_device_info *); | |
147 | #endif | 147 | #endif | |
148 | 148 | |||
149 | Static const char *usbrev_str[] = USBREV_STR; | 149 | Static const char *usbrev_str[] = USBREV_STR; | |
150 | 150 | |||
151 | static int usb_match(device_t, cfdata_t, void *); | 151 | static int usb_match(device_t, cfdata_t, void *); | |
152 | static void usb_attach(device_t, device_t, void *); | 152 | static void usb_attach(device_t, device_t, void *); | |
153 | static int usb_detach(device_t, int); | 153 | static int usb_detach(device_t, int); | |
154 | static int usb_activate(device_t, enum devact); | 154 | static int usb_activate(device_t, enum devact); | |
155 | static void usb_childdet(device_t, device_t); | 155 | static void usb_childdet(device_t, device_t); | |
156 | static void usb_doattach(device_t); | 156 | static void usb_doattach(device_t); | |
157 | 157 | |||
158 | extern struct cfdriver usb_cd; | 158 | extern struct cfdriver usb_cd; | |
159 | 159 | |||
160 | CFATTACH_DECL3_NEW(usb, sizeof(struct usb_softc), | 160 | CFATTACH_DECL3_NEW(usb, sizeof(struct usb_softc), | |
161 | usb_match, usb_attach, usb_detach, usb_activate, NULL, usb_childdet, | 161 | usb_match, usb_attach, usb_detach, usb_activate, NULL, usb_childdet, | |
162 | DVF_DETACH_SHUTDOWN); | 162 | DVF_DETACH_SHUTDOWN); | |
163 | 163 | |||
164 | int | 164 | int | |
165 | usb_match(device_t parent, cfdata_t match, void *aux) | 165 | usb_match(device_t parent, cfdata_t match, void *aux) | |
166 | { | 166 | { | |
167 | DPRINTF(("usbd_match\n")); | 167 | DPRINTF(("usbd_match\n")); | |
168 | return (UMATCH_GENERIC); | 168 | return (UMATCH_GENERIC); | |
169 | } | 169 | } | |
170 | 170 | |||
171 | void | 171 | void | |
172 | usb_attach(device_t parent, device_t self, void *aux) | 172 | usb_attach(device_t parent, device_t self, void *aux) | |
173 | { | 173 | { | |
174 | struct usb_softc *sc = device_private(self); | 174 | struct usb_softc *sc = device_private(self); | |
175 | int usbrev; | 175 | int usbrev; | |
176 | 176 | |||
177 | sc->sc_bus = aux; | 177 | sc->sc_bus = aux; | |
178 | usbrev = sc->sc_bus->usbrev; | 178 | usbrev = sc->sc_bus->usbrev; | |
179 | 179 | |||
180 | aprint_naive("\n"); | 180 | aprint_naive("\n"); | |
181 | aprint_normal(": USB revision %s", usbrev_str[usbrev]); | 181 | aprint_normal(": USB revision %s", usbrev_str[usbrev]); | |
182 | switch (usbrev) { | 182 | switch (usbrev) { | |
183 | case USBREV_1_0: | 183 | case USBREV_1_0: | |
184 | case USBREV_1_1: | 184 | case USBREV_1_1: | |
185 | case USBREV_2_0: | 185 | case USBREV_2_0: | |
186 | break; | 186 | break; | |
187 | default: | 187 | default: | |
188 | aprint_error(", not supported\n"); | 188 | aprint_error(", not supported\n"); | |
189 | sc->sc_dying = 1; | 189 | sc->sc_dying = 1; | |
190 | return; | 190 | return; | |
191 | } | 191 | } | |
192 | aprint_normal("\n"); | 192 | aprint_normal("\n"); | |
193 | 193 | |||
194 | config_interrupts(self, usb_doattach); | 194 | config_interrupts(self, usb_doattach); | |
195 | } | 195 | } | |
196 | 196 | |||
197 | static void | 197 | static void | |
198 | usb_doattach(device_t self) | 198 | usb_doattach(device_t self) | |
199 | { | 199 | { | |
200 | static bool usb_selevent_init; /* XXX */ | 200 | static bool usb_selevent_init; /* XXX */ | |
201 | struct usb_softc *sc = device_private(self); | 201 | struct usb_softc *sc = device_private(self); | |
202 | usbd_device_handle dev; | 202 | usbd_device_handle dev; | |
203 | usbd_status err; | 203 | usbd_status err; | |
204 | int speed; | 204 | int speed; | |
205 | struct usb_event *ue; | 205 | struct usb_event *ue; | |
206 | bool mpsafe = sc->sc_bus->methods->get_locks ? true : false; | 206 | bool mpsafe = sc->sc_bus->methods->get_locks ? true : false; | |
207 | 207 | |||
208 | if (!usb_selevent_init) { | 208 | if (!usb_selevent_init) { | |
209 | selinit(&usb_selevent); | 209 | selinit(&usb_selevent); | |
210 | usb_selevent_init = true; | 210 | usb_selevent_init = true; | |
211 | } | 211 | } | |
212 | DPRINTF(("usbd_doattach\n")); | 212 | DPRINTF(("usbd_doattach\n")); | |
213 | 213 | |||
214 | sc->sc_bus->usbctl = self; | 214 | sc->sc_bus->usbctl = self; | |
215 | sc->sc_port.power = USB_MAX_POWER; | 215 | sc->sc_port.power = USB_MAX_POWER; | |
216 | 216 | |||
217 | switch (sc->sc_bus->usbrev) { | 217 | switch (sc->sc_bus->usbrev) { | |
218 | case USBREV_1_0: | 218 | case USBREV_1_0: | |
219 | case USBREV_1_1: | 219 | case USBREV_1_1: | |
220 | speed = USB_SPEED_FULL; | 220 | speed = USB_SPEED_FULL; | |
221 | break; | 221 | break; | |
222 | case USBREV_2_0: | 222 | case USBREV_2_0: | |
223 | speed = USB_SPEED_HIGH; | 223 | speed = USB_SPEED_HIGH; | |
224 | break; | 224 | break; | |
225 | default: | 225 | default: | |
226 | panic("usb_doattach"); | 226 | panic("usb_doattach"); | |
227 | } | 227 | } | |
228 | 228 | |||
229 | if (mpsafe) { | |||
230 | sc->sc_bus->methods->get_locks(sc->sc_bus, | |||
231 | &sc->sc_bus->intr_lock, &sc->sc_bus->lock); | |||
232 | } else { | |||
233 | sc->sc_bus->intr_lock = sc->sc_bus->lock = NULL; | |||
234 | } | |||
235 | ||||
229 | ue = usb_alloc_event(); | 236 | ue = usb_alloc_event(); | |
230 | ue->u.ue_ctrlr.ue_bus = device_unit(self); | 237 | ue->u.ue_ctrlr.ue_bus = device_unit(self); | |
231 | usb_add_event(USB_EVENT_CTRLR_ATTACH, ue); | 238 | usb_add_event(USB_EVENT_CTRLR_ATTACH, ue); | |
232 | 239 | |||
233 | /* XXX we should have our own level */ | 240 | /* XXX we should have our own level */ | |
234 | sc->sc_bus->soft = softint_establish( | 241 | sc->sc_bus->soft = softint_establish( | |
235 | SOFTINT_NET | (mpsafe ? SOFTINT_MPSAFE : 0), | 242 | SOFTINT_NET | (mpsafe ? SOFTINT_MPSAFE : 0), | |
236 | sc->sc_bus->methods->soft_intr, sc->sc_bus); | 243 | sc->sc_bus->methods->soft_intr, sc->sc_bus); | |
237 | if (sc->sc_bus->soft == NULL) { | 244 | if (sc->sc_bus->soft == NULL) { | |
238 | aprint_error("%s: can't register softintr\n", | 245 | aprint_error("%s: can't register softintr\n", | |
239 | device_xname(self)); | 246 | device_xname(self)); | |
240 | sc->sc_dying = 1; | 247 | sc->sc_dying = 1; | |
241 | return; | 248 | return; | |
242 | } | 249 | } | |
243 | 250 | |||
244 | err = usbd_new_device(self, sc->sc_bus, 0, speed, 0, | 251 | err = usbd_new_device(self, sc->sc_bus, 0, speed, 0, | |
245 | &sc->sc_port); | 252 | &sc->sc_port); | |
246 | if (!err) { | 253 | if (!err) { | |
247 | dev = sc->sc_port.device; | 254 | dev = sc->sc_port.device; | |
248 | if (dev->hub == NULL) { | 255 | if (dev->hub == NULL) { | |
249 | sc->sc_dying = 1; | 256 | sc->sc_dying = 1; | |
250 | aprint_error("%s: root device is not a hub\n", | 257 | aprint_error("%s: root device is not a hub\n", | |
251 | device_xname(self)); | 258 | device_xname(self)); | |
252 | return; | 259 | return; | |
253 | } | 260 | } | |
254 | sc->sc_bus->root_hub = dev; | 261 | sc->sc_bus->root_hub = dev; | |
255 | #if 1 | 262 | #if 1 | |
256 | /* | 263 | /* | |
257 | * Turning this code off will delay attachment of USB devices | 264 | * Turning this code off will delay attachment of USB devices | |
258 | * until the USB event thread is running, which means that | 265 | * until the USB event thread is running, which means that | |
259 | * the keyboard will not work until after cold boot. | 266 | * the keyboard will not work until after cold boot. | |
260 | */ | 267 | */ | |
261 | if (cold && (device_cfdata(self)->cf_flags & 1)) | 268 | if (cold && (device_cfdata(self)->cf_flags & 1)) | |
262 | dev->hub->explore(sc->sc_bus->root_hub); | 269 | dev->hub->explore(sc->sc_bus->root_hub); | |
263 | #endif | 270 | #endif | |
264 | } else { | 271 | } else { | |
265 | aprint_error("%s: root hub problem, error=%d\n", | 272 | aprint_error("%s: root hub problem, error=%d\n", | |
266 | device_xname(self), err); | 273 | device_xname(self), err); | |
267 | sc->sc_dying = 1; | 274 | sc->sc_dying = 1; | |
268 | } | 275 | } | |
269 | 276 | |||
270 | config_pending_incr(); | 277 | config_pending_incr(); | |
271 | usb_create_event_thread(self); | 278 | usb_create_event_thread(self); | |
272 | 279 | |||
273 | if (!pmf_device_register(self, NULL, NULL)) | 280 | if (!pmf_device_register(self, NULL, NULL)) | |
274 | aprint_error_dev(self, "couldn't establish power handler\n"); | 281 | aprint_error_dev(self, "couldn't establish power handler\n"); | |
275 | 282 | |||
276 | usb_async_sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE, | 283 | usb_async_sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE, | |
277 | usb_async_intr, NULL); | 284 | usb_async_intr, NULL); | |
278 | 285 | |||
279 | return; | 286 | return; | |
280 | } | 287 | } | |
281 | 288 | |||
282 | static const char *taskq_names[] = USB_TASKQ_NAMES; | 289 | static const char *taskq_names[] = USB_TASKQ_NAMES; | |
283 | 290 | |||
284 | void | 291 | void | |
285 | usb_create_event_thread(device_t self) | 292 | usb_create_event_thread(device_t self) | |
286 | { | 293 | { | |
287 | struct usb_softc *sc = device_private(self); | 294 | struct usb_softc *sc = device_private(self); | |
288 | struct usb_taskq *taskq; | 295 | struct usb_taskq *taskq; | |
289 | int i; | 296 | int i; | |
290 | 297 | |||
291 | if (kthread_create(PRI_NONE, 0, NULL, usb_event_thread, sc, | 298 | if (kthread_create(PRI_NONE, 0, NULL, usb_event_thread, sc, | |
292 | &sc->sc_event_thread, "%s", device_xname(self))) { | 299 | &sc->sc_event_thread, "%s", device_xname(self))) { | |
293 | printf("%s: unable to create event thread for\n", | 300 | printf("%s: unable to create event thread for\n", | |
294 | device_xname(self)); | 301 | device_xname(self)); | |
295 | panic("usb_create_event_thread"); | 302 | panic("usb_create_event_thread"); | |
296 | } | 303 | } | |
297 | for (i = 0; i < USB_NUM_TASKQS; i++) { | 304 | for (i = 0; i < USB_NUM_TASKQS; i++) { | |
298 | taskq = &usb_taskq[i]; | 305 | taskq = &usb_taskq[i]; | |
299 | 306 | |||
300 | if (taskq->taskcreated) | 307 | if (taskq->taskcreated) | |
301 | continue; | 308 | continue; | |
302 | 309 | |||
303 | TAILQ_INIT(&taskq->tasks); | 310 | TAILQ_INIT(&taskq->tasks); | |
304 | taskq->taskcreated = 1; | 311 | taskq->taskcreated = 1; | |
305 | taskq->name = taskq_names[i]; | 312 | taskq->name = taskq_names[i]; | |
306 | if (kthread_create(PRI_NONE, 0, NULL, usb_task_thread, | 313 | if (kthread_create(PRI_NONE, 0, NULL, usb_task_thread, | |
307 | taskq, &taskq->task_thread_lwp, "%s", taskq->name)) { | 314 | taskq, &taskq->task_thread_lwp, "%s", taskq->name)) { | |
308 | printf("unable to create task thread: %s\n", taskq->name); | 315 | printf("unable to create task thread: %s\n", taskq->name); | |
309 | panic("usb_create_event_thread task"); | 316 | panic("usb_create_event_thread task"); | |
310 | } | 317 | } | |
311 | } | 318 | } | |
312 | } | 319 | } | |
313 | 320 | |||
314 | /* | 321 | /* | |
315 | * Add a task to be performed by the task thread. This function can be | 322 | * Add a task to be performed by the task thread. This function can be | |
316 | * called from any context and the task will be executed in a process | 323 | * called from any context and the task will be executed in a process | |
317 | * context ASAP. | 324 | * context ASAP. | |
318 | */ | 325 | */ | |
319 | void | 326 | void | |
320 | usb_add_task(usbd_device_handle dev, struct usb_task *task, int queue) | 327 | usb_add_task(usbd_device_handle dev, struct usb_task *task, int queue) | |
321 | { | 328 | { | |
322 | struct usb_taskq *taskq; | 329 | struct usb_taskq *taskq; | |
323 | int s; | 330 | int s; | |
324 | 331 | |||
325 | taskq = &usb_taskq[queue]; | 332 | taskq = &usb_taskq[queue]; | |
326 | s = splusb(); | 333 | s = splusb(); | |
327 | if (task->queue == -1) { | 334 | if (task->queue == -1) { | |
328 | DPRINTFN(2,("usb_add_task: task=%p\n", task)); | 335 | DPRINTFN(2,("usb_add_task: task=%p\n", task)); | |
329 | TAILQ_INSERT_TAIL(&taskq->tasks, task, next); | 336 | TAILQ_INSERT_TAIL(&taskq->tasks, task, next); | |
330 | task->queue = queue; | 337 | task->queue = queue; | |
331 | } else { | 338 | } else { | |
332 | DPRINTFN(3,("usb_add_task: task=%p on q\n", task)); | 339 | DPRINTFN(3,("usb_add_task: task=%p on q\n", task)); | |
333 | } | 340 | } | |
334 | wakeup(&taskq->tasks); | 341 | wakeup(&taskq->tasks); | |
335 | splx(s); | 342 | splx(s); | |
336 | } | 343 | } | |
337 | 344 | |||
338 | void | 345 | void | |
339 | usb_rem_task(usbd_device_handle dev, struct usb_task *task) | 346 | usb_rem_task(usbd_device_handle dev, struct usb_task *task) | |
340 | { | 347 | { | |
341 | struct usb_taskq *taskq; | 348 | struct usb_taskq *taskq; | |
342 | int s; | 349 | int s; | |
343 | 350 | |||
344 | taskq = &usb_taskq[task->queue]; | 351 | taskq = &usb_taskq[task->queue]; | |
345 | s = splusb(); | 352 | s = splusb(); | |
346 | if (task->queue != -1) { | 353 | if (task->queue != -1) { | |
347 | TAILQ_REMOVE(&taskq->tasks, task, next); | 354 | TAILQ_REMOVE(&taskq->tasks, task, next); | |
348 | task->queue = -1; | 355 | task->queue = -1; | |
349 | } | 356 | } | |
350 | splx(s); | 357 | splx(s); | |
351 | } | 358 | } | |
352 | 359 | |||
353 | void | 360 | void | |
354 | usb_event_thread(void *arg) | 361 | usb_event_thread(void *arg) | |
355 | { | 362 | { | |
356 | struct usb_softc *sc = arg; | 363 | struct usb_softc *sc = arg; | |
357 | 364 | |||
358 | DPRINTF(("usb_event_thread: start\n")); | 365 | DPRINTF(("usb_event_thread: start\n")); | |
359 | 366 | |||
360 | /* | 367 | /* | |
361 | * In case this controller is a companion controller to an | 368 | * In case this controller is a companion controller to an | |
362 | * EHCI controller we need to wait until the EHCI controller | 369 | * EHCI controller we need to wait until the EHCI controller | |
363 | * has grabbed the port. | 370 | * has grabbed the port. | |
364 | * XXX It would be nicer to do this with a tsleep(), but I don't | 371 | * XXX It would be nicer to do this with a tsleep(), but I don't | |
365 | * know how to synchronize the creation of the threads so it | 372 | * know how to synchronize the creation of the threads so it | |
366 | * will work. | 373 | * will work. | |
367 | */ | 374 | */ | |
368 | usb_delay_ms(sc->sc_bus, 500); | 375 | usb_delay_ms(sc->sc_bus, 500); | |
369 | 376 | |||
370 | /* Make sure first discover does something. */ | 377 | /* Make sure first discover does something. */ | |
371 | sc->sc_bus->needs_explore = 1; | 378 | sc->sc_bus->needs_explore = 1; | |
372 | usb_discover(sc); | 379 | usb_discover(sc); | |
373 | config_pending_decr(); | 380 | config_pending_decr(); | |
374 | 381 | |||
375 | while (!sc->sc_dying) { | 382 | while (!sc->sc_dying) { | |
376 | if (usb_noexplore < 2) | 383 | if (usb_noexplore < 2) | |
377 | usb_discover(sc); | 384 | usb_discover(sc); | |
378 | (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt", | 385 | (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt", | |
379 | usb_noexplore ? 0 : hz * 60); | 386 | usb_noexplore ? 0 : hz * 60); | |
380 | DPRINTFN(2,("usb_event_thread: woke up\n")); | 387 | DPRINTFN(2,("usb_event_thread: woke up\n")); | |
381 | } | 388 | } | |
382 | sc->sc_event_thread = NULL; | 389 | sc->sc_event_thread = NULL; | |
383 | 390 | |||
384 | /* In case parent is waiting for us to exit. */ | 391 | /* In case parent is waiting for us to exit. */ | |
385 | wakeup(sc); | 392 | wakeup(sc); | |
386 | 393 | |||
387 | DPRINTF(("usb_event_thread: exit\n")); | 394 | DPRINTF(("usb_event_thread: exit\n")); | |
388 | kthread_exit(0); | 395 | kthread_exit(0); | |
389 | } | 396 | } | |
390 | 397 | |||
391 | void | 398 | void | |
392 | usb_task_thread(void *arg) | 399 | usb_task_thread(void *arg) | |
393 | { | 400 | { | |
394 | struct usb_task *task; | 401 | struct usb_task *task; | |
395 | struct usb_taskq *taskq; | 402 | struct usb_taskq *taskq; | |
396 | int s; | 403 | int s; | |
397 | 404 | |||
398 | taskq = arg; | 405 | taskq = arg; | |
399 | DPRINTF(("usb_task_thread: start taskq %s\n", taskq->name)); | 406 | DPRINTF(("usb_task_thread: start taskq %s\n", taskq->name)); | |
400 | 407 | |||
401 | s = splusb(); | 408 | s = splusb(); | |
402 | for (;;) { | 409 | for (;;) { | |
403 | task = TAILQ_FIRST(&taskq->tasks); | 410 | task = TAILQ_FIRST(&taskq->tasks); | |
404 | if (task == NULL) { | 411 | if (task == NULL) { | |
405 | tsleep(&taskq->tasks, PWAIT, "usbtsk", 0); | 412 | tsleep(&taskq->tasks, PWAIT, "usbtsk", 0); | |
406 | task = TAILQ_FIRST(&taskq->tasks); | 413 | task = TAILQ_FIRST(&taskq->tasks); | |
407 | } | 414 | } | |
408 | DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task)); | 415 | DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task)); | |
409 | if (task != NULL) { | 416 | if (task != NULL) { | |
410 | TAILQ_REMOVE(&taskq->tasks, task, next); | 417 | TAILQ_REMOVE(&taskq->tasks, task, next); | |
411 | task->queue = -1; | 418 | task->queue = -1; | |
412 | splx(s); | 419 | splx(s); | |
413 | task->fun(task->arg); | 420 | task->fun(task->arg); | |
414 | s = splusb(); | 421 | s = splusb(); | |
415 | } | 422 | } | |
416 | } | 423 | } | |
417 | } | 424 | } | |
418 | 425 | |||
419 | int | 426 | int | |
420 | usbctlprint(void *aux, const char *pnp) | 427 | usbctlprint(void *aux, const char *pnp) | |
421 | { | 428 | { | |
422 | /* only "usb"es can attach to host controllers */ | 429 | /* only "usb"es can attach to host controllers */ | |
423 | if (pnp) | 430 | if (pnp) | |
424 | aprint_normal("usb at %s", pnp); | 431 | aprint_normal("usb at %s", pnp); | |
425 | 432 | |||
426 | return (UNCONF); | 433 | return (UNCONF); | |
427 | } | 434 | } | |
428 | 435 | |||
429 | int | 436 | int | |
430 | usbopen(dev_t dev, int flag, int mode, struct lwp *l) | 437 | usbopen(dev_t dev, int flag, int mode, struct lwp *l) | |
431 | { | 438 | { | |
432 | int unit = minor(dev); | 439 | int unit = minor(dev); | |
433 | struct usb_softc *sc; | 440 | struct usb_softc *sc; | |
434 | 441 | |||
435 | if (unit == USB_DEV_MINOR) { | 442 | if (unit == USB_DEV_MINOR) { | |
436 | if (usb_dev_open) | 443 | if (usb_dev_open) | |
437 | return (EBUSY); | 444 | return (EBUSY); | |
438 | usb_dev_open = 1; | 445 | usb_dev_open = 1; | |
439 | mutex_enter(proc_lock); | 446 | mutex_enter(proc_lock); | |
440 | usb_async_proc = 0; | 447 | usb_async_proc = 0; | |
441 | mutex_exit(proc_lock); | 448 | mutex_exit(proc_lock); | |
442 | return (0); | 449 | return (0); | |
443 | } | 450 | } | |
444 | 451 | |||
445 | sc = device_lookup_private(&usb_cd, unit); | 452 | sc = device_lookup_private(&usb_cd, unit); | |
446 | if (!sc) | 453 | if (!sc) | |
447 | return (ENXIO); | 454 | return (ENXIO); | |
448 | 455 | |||
449 | if (sc->sc_dying) | 456 | if (sc->sc_dying) | |
450 | return (EIO); | 457 | return (EIO); | |
451 | 458 | |||
452 | return (0); | 459 | return (0); | |
453 | } | 460 | } | |
454 | 461 | |||
455 | int | 462 | int | |
456 | usbread(dev_t dev, struct uio *uio, int flag) | 463 | usbread(dev_t dev, struct uio *uio, int flag) | |
457 | { | 464 | { | |
458 | struct usb_event *ue; | 465 | struct usb_event *ue; | |
459 | #ifdef COMPAT_30 | 466 | #ifdef COMPAT_30 | |
460 | struct usb_event_old *ueo = NULL; /* XXXGCC */ | 467 | struct usb_event_old *ueo = NULL; /* XXXGCC */ | |
461 | #endif | 468 | #endif | |
462 | int s, error, n, useold; | 469 | int s, error, n, useold; | |
463 | 470 | |||
464 | if (minor(dev) != USB_DEV_MINOR) | 471 | if (minor(dev) != USB_DEV_MINOR) | |
465 | return (ENXIO); | 472 | return (ENXIO); | |
466 | 473 | |||
467 | useold = 0; | 474 | useold = 0; | |
468 | switch (uio->uio_resid) { | 475 | switch (uio->uio_resid) { | |
469 | #ifdef COMPAT_30 | 476 | #ifdef COMPAT_30 | |
470 | case sizeof(struct usb_event_old): | 477 | case sizeof(struct usb_event_old): | |
471 | ueo = malloc(sizeof(struct usb_event_old), M_USBDEV, | 478 | ueo = malloc(sizeof(struct usb_event_old), M_USBDEV, | |
472 | M_WAITOK|M_ZERO); | 479 | M_WAITOK|M_ZERO); | |
473 | useold = 1; | 480 | useold = 1; | |
474 | /* FALLTHRU */ | 481 | /* FALLTHRU */ | |
475 | #endif | 482 | #endif | |
476 | case sizeof(struct usb_event): | 483 | case sizeof(struct usb_event): | |
477 | ue = usb_alloc_event(); | 484 | ue = usb_alloc_event(); | |
478 | break; | 485 | break; | |
479 | default: | 486 | default: | |
480 | return (EINVAL); | 487 | return (EINVAL); | |
481 | } | 488 | } | |
482 | 489 | |||
483 | error = 0; | 490 | error = 0; | |
484 | s = splusb(); | 491 | s = splusb(); | |
485 | for (;;) { | 492 | for (;;) { | |
486 | n = usb_get_next_event(ue); | 493 | n = usb_get_next_event(ue); | |
487 | if (n != 0) | 494 | if (n != 0) | |
488 | break; | 495 | break; | |
489 | if (flag & IO_NDELAY) { | 496 | if (flag & IO_NDELAY) { | |
490 | error = EWOULDBLOCK; | 497 | error = EWOULDBLOCK; | |
491 | break; | 498 | break; | |
492 | } | 499 | } | |
493 | error = tsleep(&usb_events, PZERO | PCATCH, "usbrea", 0); | 500 | error = tsleep(&usb_events, PZERO | PCATCH, "usbrea", 0); | |
494 | if (error) | 501 | if (error) | |
495 | break; | 502 | break; | |
496 | } | 503 | } | |
497 | splx(s); | 504 | splx(s); | |
498 | if (!error) { | 505 | if (!error) { | |
499 | #ifdef COMPAT_30 | 506 | #ifdef COMPAT_30 | |
500 | if (useold) { /* copy fields to old struct */ | 507 | if (useold) { /* copy fields to old struct */ | |
501 | ueo->ue_type = ue->ue_type; | 508 | ueo->ue_type = ue->ue_type; | |
502 | memcpy(&ueo->ue_time, &ue->ue_time, | 509 | memcpy(&ueo->ue_time, &ue->ue_time, | |
503 | sizeof(struct timespec)); | 510 | sizeof(struct timespec)); | |
504 | switch (ue->ue_type) { | 511 | switch (ue->ue_type) { | |
505 | case USB_EVENT_DEVICE_ATTACH: | 512 | case USB_EVENT_DEVICE_ATTACH: | |
506 | case USB_EVENT_DEVICE_DETACH: | 513 | case USB_EVENT_DEVICE_DETACH: | |
507 | usb_copy_old_devinfo(&ueo->u.ue_device, &ue->u.ue_device); | 514 | usb_copy_old_devinfo(&ueo->u.ue_device, &ue->u.ue_device); | |
508 | break; | 515 | break; | |
509 | 516 | |||
510 | case USB_EVENT_CTRLR_ATTACH: | 517 | case USB_EVENT_CTRLR_ATTACH: | |
511 | case USB_EVENT_CTRLR_DETACH: | 518 | case USB_EVENT_CTRLR_DETACH: | |
512 | ueo->u.ue_ctrlr.ue_bus=ue->u.ue_ctrlr.ue_bus; | 519 | ueo->u.ue_ctrlr.ue_bus=ue->u.ue_ctrlr.ue_bus; | |
513 | break; | 520 | break; | |
514 | 521 | |||
515 | case USB_EVENT_DRIVER_ATTACH: | 522 | case USB_EVENT_DRIVER_ATTACH: | |
516 | case USB_EVENT_DRIVER_DETACH: | 523 | case USB_EVENT_DRIVER_DETACH: | |
517 | ueo->u.ue_driver.ue_cookie=ue->u.ue_driver.ue_cookie; | 524 | ueo->u.ue_driver.ue_cookie=ue->u.ue_driver.ue_cookie; | |
518 | memcpy(ueo->u.ue_driver.ue_devname, | 525 | memcpy(ueo->u.ue_driver.ue_devname, | |
519 | ue->u.ue_driver.ue_devname, | 526 | ue->u.ue_driver.ue_devname, | |
520 | sizeof(ue->u.ue_driver.ue_devname)); | 527 | sizeof(ue->u.ue_driver.ue_devname)); | |
521 | break; | 528 | break; | |
522 | default: | 529 | default: | |
523 | ; | 530 | ; | |
524 | } | 531 | } | |
525 | 532 | |||
526 | error = uiomove((void *)ueo, sizeof *ueo, uio); | 533 | error = uiomove((void *)ueo, sizeof *ueo, uio); | |
527 | } else | 534 | } else | |
528 | #endif | 535 | #endif | |
529 | error = uiomove((void *)ue, sizeof *ue, uio); | 536 | error = uiomove((void *)ue, sizeof *ue, uio); | |
530 | } | 537 | } | |
531 | usb_free_event(ue); | 538 | usb_free_event(ue); | |
532 | #ifdef COMPAT_30 | 539 | #ifdef COMPAT_30 | |
533 | if (useold) | 540 | if (useold) | |
534 | free(ueo, M_USBDEV); | 541 | free(ueo, M_USBDEV); | |
535 | #endif | 542 | #endif | |
536 | 543 | |||
537 | return (error); | 544 | return (error); | |
538 | } | 545 | } | |
539 | 546 | |||
540 | int | 547 | int | |
541 | usbclose(dev_t dev, int flag, int mode, | 548 | usbclose(dev_t dev, int flag, int mode, | |
542 | struct lwp *l) | 549 | struct lwp *l) | |
543 | { | 550 | { | |
544 | int unit = minor(dev); | 551 | int unit = minor(dev); | |
545 | 552 | |||
546 | if (unit == USB_DEV_MINOR) { | 553 | if (unit == USB_DEV_MINOR) { | |
547 | mutex_enter(proc_lock); | 554 | mutex_enter(proc_lock); | |
548 | usb_async_proc = 0; | 555 | usb_async_proc = 0; | |
549 | mutex_exit(proc_lock); | 556 | mutex_exit(proc_lock); | |
550 | usb_dev_open = 0; | 557 | usb_dev_open = 0; | |
551 | } | 558 | } | |
552 | 559 | |||
553 | return (0); | 560 | return (0); | |
554 | } | 561 | } | |
555 | 562 | |||
556 | int | 563 | int | |
557 | usbioctl(dev_t devt, u_long cmd, void *data, int flag, struct lwp *l) | 564 | usbioctl(dev_t devt, u_long cmd, void *data, int flag, struct lwp *l) | |
558 | { | 565 | { | |
559 | struct usb_softc *sc; | 566 | struct usb_softc *sc; | |
560 | int unit = minor(devt); | 567 | int unit = minor(devt); | |
561 | 568 | |||
562 | if (unit == USB_DEV_MINOR) { | 569 | if (unit == USB_DEV_MINOR) { | |
563 | switch (cmd) { | 570 | switch (cmd) { | |
564 | case FIONBIO: | 571 | case FIONBIO: | |
565 | /* All handled in the upper FS layer. */ | 572 | /* All handled in the upper FS layer. */ | |
566 | return (0); | 573 | return (0); | |
567 | 574 | |||
568 | case FIOASYNC: | 575 | case FIOASYNC: | |
569 | mutex_enter(proc_lock); | 576 | mutex_enter(proc_lock); | |
570 | if (*(int *)data) | 577 | if (*(int *)data) | |
571 | usb_async_proc = l->l_proc; | 578 | usb_async_proc = l->l_proc; | |
572 | else | 579 | else | |
573 | usb_async_proc = 0; | 580 | usb_async_proc = 0; | |
574 | mutex_exit(proc_lock); | 581 | mutex_exit(proc_lock); | |
575 | return (0); | 582 | return (0); | |
576 | 583 | |||
577 | default: | 584 | default: | |
578 | return (EINVAL); | 585 | return (EINVAL); | |
579 | } | 586 | } | |
580 | } | 587 | } | |
581 | 588 | |||
582 | sc = device_lookup_private(&usb_cd, unit); | 589 | sc = device_lookup_private(&usb_cd, unit); | |
583 | 590 | |||
584 | if (sc->sc_dying) | 591 | if (sc->sc_dying) | |
585 | return (EIO); | 592 | return (EIO); | |
586 | 593 | |||
587 | switch (cmd) { | 594 | switch (cmd) { | |
588 | #ifdef USB_DEBUG | 595 | #ifdef USB_DEBUG | |
589 | case USB_SETDEBUG: | 596 | case USB_SETDEBUG: | |
590 | if (!(flag & FWRITE)) | 597 | if (!(flag & FWRITE)) | |
591 | return (EBADF); | 598 | return (EBADF); | |
592 | usbdebug = ((*(int *)data) & 0x000000ff); | 599 | usbdebug = ((*(int *)data) & 0x000000ff); | |
593 | break; | 600 | break; | |
594 | #endif /* USB_DEBUG */ | 601 | #endif /* USB_DEBUG */ | |
595 | case USB_REQUEST: | 602 | case USB_REQUEST: | |
596 | { | 603 | { | |
597 | struct usb_ctl_request *ur = (void *)data; | 604 | struct usb_ctl_request *ur = (void *)data; | |
598 | int len = UGETW(ur->ucr_request.wLength); | 605 | int len = UGETW(ur->ucr_request.wLength); | |
599 | struct iovec iov; | 606 | struct iovec iov; | |
600 | struct uio uio; | 607 | struct uio uio; | |
601 | void *ptr = 0; | 608 | void *ptr = 0; | |
602 | int addr = ur->ucr_addr; | 609 | int addr = ur->ucr_addr; | |
603 | usbd_status err; | 610 | usbd_status err; | |
604 | int error = 0; | 611 | int error = 0; | |
605 | 612 | |||
606 | if (!(flag & FWRITE)) | 613 | if (!(flag & FWRITE)) | |
607 | return (EBADF); | 614 | return (EBADF); | |
608 | 615 | |||
609 | DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len)); | 616 | DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len)); | |
610 | if (len < 0 || len > 32768) | 617 | if (len < 0 || len > 32768) | |
611 | return (EINVAL); | 618 | return (EINVAL); | |
612 | if (addr < 0 || addr >= USB_MAX_DEVICES || | 619 | if (addr < 0 || addr >= USB_MAX_DEVICES || | |
613 | sc->sc_bus->devices[addr] == 0) | 620 | sc->sc_bus->devices[addr] == 0) | |
614 | return (EINVAL); | 621 | return (EINVAL); | |
615 | if (len != 0) { | 622 | if (len != 0) { | |
616 | iov.iov_base = (void *)ur->ucr_data; | 623 | iov.iov_base = (void *)ur->ucr_data; | |
617 | iov.iov_len = len; | 624 | iov.iov_len = len; | |
618 | uio.uio_iov = &iov; | 625 | uio.uio_iov = &iov; | |
619 | uio.uio_iovcnt = 1; | 626 | uio.uio_iovcnt = 1; | |
620 | uio.uio_resid = len; | 627 | uio.uio_resid = len; | |
621 | uio.uio_offset = 0; | 628 | uio.uio_offset = 0; | |
622 | uio.uio_rw = | 629 | uio.uio_rw = | |
623 | ur->ucr_request.bmRequestType & UT_READ ? | 630 | ur->ucr_request.bmRequestType & UT_READ ? | |
624 | UIO_READ : UIO_WRITE; | 631 | UIO_READ : UIO_WRITE; | |
625 | uio.uio_vmspace = l->l_proc->p_vmspace; | 632 | uio.uio_vmspace = l->l_proc->p_vmspace; | |
626 | ptr = malloc(len, M_TEMP, M_WAITOK); | 633 | ptr = malloc(len, M_TEMP, M_WAITOK); | |
627 | if (uio.uio_rw == UIO_WRITE) { | 634 | if (uio.uio_rw == UIO_WRITE) { | |
628 | error = uiomove(ptr, len, &uio); | 635 | error = uiomove(ptr, len, &uio); | |
629 | if (error) | 636 | if (error) | |
630 | goto ret; | 637 | goto ret; | |
631 | } | 638 | } | |
632 | } | 639 | } | |
633 | err = usbd_do_request_flags(sc->sc_bus->devices[addr], | 640 | err = usbd_do_request_flags(sc->sc_bus->devices[addr], | |
634 | &ur->ucr_request, ptr, ur->ucr_flags, &ur->ucr_actlen, | 641 | &ur->ucr_request, ptr, ur->ucr_flags, &ur->ucr_actlen, | |
635 | USBD_DEFAULT_TIMEOUT); | 642 | USBD_DEFAULT_TIMEOUT); | |
636 | if (err) { | 643 | if (err) { | |
637 | error = EIO; | 644 | error = EIO; | |
638 | goto ret; | 645 | goto ret; | |
639 | } | 646 | } | |
640 | if (len > ur->ucr_actlen) | 647 | if (len > ur->ucr_actlen) | |
641 | len = ur->ucr_actlen; | 648 | len = ur->ucr_actlen; | |
642 | if (len != 0) { | 649 | if (len != 0) { | |
643 | if (uio.uio_rw == UIO_READ) { | 650 | if (uio.uio_rw == UIO_READ) { | |
644 | error = uiomove(ptr, len, &uio); | 651 | error = uiomove(ptr, len, &uio); | |
645 | if (error) | 652 | if (error) | |
646 | goto ret; | 653 | goto ret; | |
647 | } | 654 | } | |
648 | } | 655 | } | |
649 | ret: | 656 | ret: | |
650 | if (ptr) | 657 | if (ptr) | |
651 | free(ptr, M_TEMP); | 658 | free(ptr, M_TEMP); | |
652 | return (error); | 659 | return (error); | |
653 | } | 660 | } | |
654 | 661 | |||
655 | case USB_DEVICEINFO: | 662 | case USB_DEVICEINFO: | |
656 | { | 663 | { | |
657 | usbd_device_handle dev; | 664 | usbd_device_handle dev; | |
658 | struct usb_device_info *di = (void *)data; | 665 | struct usb_device_info *di = (void *)data; | |
659 | int addr = di->udi_addr; | 666 | int addr = di->udi_addr; | |
660 | 667 | |||
661 | if (addr < 1 || addr >= USB_MAX_DEVICES) | 668 | if (addr < 1 || addr >= USB_MAX_DEVICES) | |
662 | return EINVAL; | 669 | return EINVAL; | |
663 | if ((dev = sc->sc_bus->devices[addr]) == NULL) | 670 | if ((dev = sc->sc_bus->devices[addr]) == NULL) | |
664 | return ENXIO; | 671 | return ENXIO; | |
665 | usbd_fill_deviceinfo(dev, di, 1); | 672 | usbd_fill_deviceinfo(dev, di, 1); | |
666 | break; | 673 | break; | |
667 | } | 674 | } | |
668 | 675 | |||
669 | #ifdef COMPAT_30 | 676 | #ifdef COMPAT_30 | |
670 | case USB_DEVICEINFO_OLD: | 677 | case USB_DEVICEINFO_OLD: | |
671 | { | 678 | { | |
672 | usbd_device_handle dev; | 679 | usbd_device_handle dev; | |
673 | struct usb_device_info_old *di = (void *)data; | 680 | struct usb_device_info_old *di = (void *)data; | |
674 | int addr = di->udi_addr; | 681 | int addr = di->udi_addr; | |
675 | 682 | |||
676 | if (addr < 1 || addr >= USB_MAX_DEVICES) | 683 | if (addr < 1 || addr >= USB_MAX_DEVICES) | |
677 | return EINVAL; | 684 | return EINVAL; | |
678 | if ((dev = sc->sc_bus->devices[addr]) == NULL) | 685 | if ((dev = sc->sc_bus->devices[addr]) == NULL) | |
679 | return ENXIO; | 686 | return ENXIO; | |
680 | usbd_fill_deviceinfo_old(dev, di, 1); | 687 | usbd_fill_deviceinfo_old(dev, di, 1); | |
681 | break; | 688 | break; | |
682 | } | 689 | } | |
683 | #endif | 690 | #endif | |
684 | 691 | |||
685 | case USB_DEVICESTATS: | 692 | case USB_DEVICESTATS: | |
686 | *(struct usb_device_stats *)data = sc->sc_bus->stats; | 693 | *(struct usb_device_stats *)data = sc->sc_bus->stats; | |
687 | break; | 694 | break; | |
688 | 695 | |||
689 | default: | 696 | default: | |
690 | return (EINVAL); | 697 | return (EINVAL); | |
691 | } | 698 | } | |
692 | return (0); | 699 | return (0); | |
693 | } | 700 | } | |
694 | 701 | |||
695 | int | 702 | int | |
696 | usbpoll(dev_t dev, int events, struct lwp *l) | 703 | usbpoll(dev_t dev, int events, struct lwp *l) | |
697 | { | 704 | { | |
698 | int revents, mask, s; | 705 | int revents, mask, s; | |
699 | 706 | |||
700 | if (minor(dev) == USB_DEV_MINOR) { | 707 | if (minor(dev) == USB_DEV_MINOR) { | |
701 | revents = 0; | 708 | revents = 0; | |
702 | mask = POLLIN | POLLRDNORM; | 709 | mask = POLLIN | POLLRDNORM; | |
703 | 710 | |||
704 | s = splusb(); | 711 | s = splusb(); | |
705 | if (events & mask && usb_nevents > 0) | 712 | if (events & mask && usb_nevents > 0) | |
706 | revents |= events & mask; | 713 | revents |= events & mask; | |
707 | if (revents == 0 && events & mask) | 714 | if (revents == 0 && events & mask) | |
708 | selrecord(l, &usb_selevent); | 715 | selrecord(l, &usb_selevent); | |
709 | splx(s); | 716 | splx(s); | |
710 | 717 | |||
711 | return (revents); | 718 | return (revents); | |
712 | } else { | 719 | } else { | |
713 | return (0); | 720 | return (0); | |
714 | } | 721 | } | |
715 | } | 722 | } | |
716 | 723 | |||
717 | static void | 724 | static void | |
718 | filt_usbrdetach(struct knote *kn) | 725 | filt_usbrdetach(struct knote *kn) | |
719 | { | 726 | { | |
720 | int s; | 727 | int s; | |
721 | 728 | |||
722 | s = splusb(); | 729 | s = splusb(); | |
723 | SLIST_REMOVE(&usb_selevent.sel_klist, kn, knote, kn_selnext); | 730 | SLIST_REMOVE(&usb_selevent.sel_klist, kn, knote, kn_selnext); | |
724 | splx(s); | 731 | splx(s); | |
725 | } | 732 | } | |
726 | 733 | |||
727 | static int | 734 | static int | |
728 | filt_usbread(struct knote *kn, long hint) | 735 | filt_usbread(struct knote *kn, long hint) | |
729 | { | 736 | { | |
730 | 737 | |||
731 | if (usb_nevents == 0) | 738 | if (usb_nevents == 0) | |
732 | return (0); | 739 | return (0); | |
733 | 740 | |||
734 | kn->kn_data = sizeof(struct usb_event); | 741 | kn->kn_data = sizeof(struct usb_event); | |
735 | return (1); | 742 | return (1); | |
736 | } | 743 | } | |
737 | 744 | |||
738 | static const struct filterops usbread_filtops = | 745 | static const struct filterops usbread_filtops = | |
739 | { 1, NULL, filt_usbrdetach, filt_usbread }; | 746 | { 1, NULL, filt_usbrdetach, filt_usbread }; | |
740 | 747 | |||
741 | int | 748 | int | |
742 | usbkqfilter(dev_t dev, struct knote *kn) | 749 | usbkqfilter(dev_t dev, struct knote *kn) | |
743 | { | 750 | { | |
744 | struct klist *klist; | 751 | struct klist *klist; | |
745 | int s; | 752 | int s; | |
746 | 753 | |||
747 | switch (kn->kn_filter) { | 754 | switch (kn->kn_filter) { | |
748 | case EVFILT_READ: | 755 | case EVFILT_READ: | |
749 | if (minor(dev) != USB_DEV_MINOR) | 756 | if (minor(dev) != USB_DEV_MINOR) | |
750 | return (1); | 757 | return (1); | |
751 | klist = &usb_selevent.sel_klist; | 758 | klist = &usb_selevent.sel_klist; | |
752 | kn->kn_fop = &usbread_filtops; | 759 | kn->kn_fop = &usbread_filtops; | |
753 | break; | 760 | break; | |
754 | 761 | |||
755 | default: | 762 | default: | |
756 | return (EINVAL); | 763 | return (EINVAL); | |
757 | } | 764 | } | |
758 | 765 | |||
759 | kn->kn_hook = NULL; | 766 | kn->kn_hook = NULL; | |
760 | 767 | |||
761 | s = splusb(); | 768 | s = splusb(); | |
762 | SLIST_INSERT_HEAD(klist, kn, kn_selnext); | 769 | SLIST_INSERT_HEAD(klist, kn, kn_selnext); | |
763 | splx(s); | 770 | splx(s); | |
764 | 771 | |||
765 | return (0); | 772 | return (0); | |
766 | } | 773 | } | |
767 | 774 | |||
768 | /* Explore device tree from the root. */ | 775 | /* Explore device tree from the root. */ | |
769 | Static void | 776 | Static void | |
770 | usb_discover(struct usb_softc *sc) | 777 | usb_discover(struct usb_softc *sc) | |
771 | { | 778 | { | |
772 | 779 | |||
773 | DPRINTFN(2,("usb_discover\n")); | 780 | DPRINTFN(2,("usb_discover\n")); | |
774 | if (usb_noexplore > 1) | 781 | if (usb_noexplore > 1) | |
775 | return; | 782 | return; | |
776 | /* | 783 | /* | |
777 | * We need mutual exclusion while traversing the device tree, | 784 | * We need mutual exclusion while traversing the device tree, | |
778 | * but this is guaranteed since this function is only called | 785 | * but this is guaranteed since this function is only called | |
779 | * from the event thread for the controller. | 786 | * from the event thread for the controller. | |
780 | */ | 787 | */ | |
781 | while (sc->sc_bus->needs_explore && !sc->sc_dying) { | 788 | while (sc->sc_bus->needs_explore && !sc->sc_dying) { | |
782 | sc->sc_bus->needs_explore = 0; | 789 | sc->sc_bus->needs_explore = 0; | |
783 | sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub); | 790 | sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub); | |
784 | } | 791 | } | |
785 | } | 792 | } | |
786 | 793 | |||
787 | void | 794 | void | |
788 | usb_needs_explore(usbd_device_handle dev) | 795 | usb_needs_explore(usbd_device_handle dev) | |
789 | { | 796 | { | |
790 | DPRINTFN(2,("usb_needs_explore\n")); | 797 | DPRINTFN(2,("usb_needs_explore\n")); | |
791 | dev->bus->needs_explore = 1; | 798 | dev->bus->needs_explore = 1; | |
792 | wakeup(&dev->bus->needs_explore); | 799 | wakeup(&dev->bus->needs_explore); | |
793 | } | 800 | } | |
794 | 801 | |||
795 | void | 802 | void | |
796 | usb_needs_reattach(usbd_device_handle dev) | 803 | usb_needs_reattach(usbd_device_handle dev) | |
797 | { | 804 | { | |
798 | DPRINTFN(2,("usb_needs_reattach\n")); | 805 | DPRINTFN(2,("usb_needs_reattach\n")); | |
799 | dev->powersrc->reattach = 1; | 806 | dev->powersrc->reattach = 1; | |
800 | dev->bus->needs_explore = 1; | 807 | dev->bus->needs_explore = 1; | |
801 | wakeup(&dev->bus->needs_explore); | 808 | wakeup(&dev->bus->needs_explore); | |
802 | } | 809 | } | |
803 | 810 | |||
804 | /* Called at splusb() */ | 811 | /* Called at splusb() */ | |
805 | int | 812 | int | |
806 | usb_get_next_event(struct usb_event *ue) | 813 | usb_get_next_event(struct usb_event *ue) | |
807 | { | 814 | { | |
808 | struct usb_event_q *ueq; | 815 | struct usb_event_q *ueq; | |
809 | 816 | |||
810 | if (usb_nevents <= 0) | 817 | if (usb_nevents <= 0) | |
811 | return (0); | 818 | return (0); | |
812 | ueq = SIMPLEQ_FIRST(&usb_events); | 819 | ueq = SIMPLEQ_FIRST(&usb_events); | |
813 | #ifdef DIAGNOSTIC | 820 | #ifdef DIAGNOSTIC | |
814 | if (ueq == NULL) { | 821 | if (ueq == NULL) { | |
815 | printf("usb: usb_nevents got out of sync! %d\n", usb_nevents); | 822 | printf("usb: usb_nevents got out of sync! %d\n", usb_nevents); | |
816 | usb_nevents = 0; | 823 | usb_nevents = 0; | |
817 | return (0); | 824 | return (0); | |
818 | } | 825 | } | |
819 | #endif | 826 | #endif | |
820 | if (ue) | 827 | if (ue) | |
821 | *ue = ueq->ue; | 828 | *ue = ueq->ue; | |
822 | SIMPLEQ_REMOVE_HEAD(&usb_events, next); | 829 | SIMPLEQ_REMOVE_HEAD(&usb_events, next); | |
823 | usb_free_event((struct usb_event *)(void *)ueq); | 830 | usb_free_event((struct usb_event *)(void *)ueq); | |
824 | usb_nevents--; | 831 | usb_nevents--; | |
825 | return (1); | 832 | return (1); | |
826 | } | 833 | } | |
827 | 834 | |||
828 | void | 835 | void | |
829 | usbd_add_dev_event(int type, usbd_device_handle udev) | 836 | usbd_add_dev_event(int type, usbd_device_handle udev) | |
830 | { | 837 | { | |
831 | struct usb_event *ue = usb_alloc_event(); | 838 | struct usb_event *ue = usb_alloc_event(); | |
832 | 839 | |||
833 | usbd_fill_deviceinfo(udev, &ue->u.ue_device, USB_EVENT_IS_ATTACH(type)); | 840 | usbd_fill_deviceinfo(udev, &ue->u.ue_device, USB_EVENT_IS_ATTACH(type)); | |
834 | usb_add_event(type, ue); | 841 | usb_add_event(type, ue); | |
835 | } | 842 | } | |
836 | 843 | |||
837 | void | 844 | void | |
838 | usbd_add_drv_event(int type, usbd_device_handle udev, device_t dev) | 845 | usbd_add_drv_event(int type, usbd_device_handle udev, device_t dev) | |
839 | { | 846 | { | |
840 | struct usb_event *ue = usb_alloc_event(); | 847 | struct usb_event *ue = usb_alloc_event(); | |
841 | 848 | |||
842 | ue->u.ue_driver.ue_cookie = udev->cookie; | 849 | ue->u.ue_driver.ue_cookie = udev->cookie; | |
843 | strncpy(ue->u.ue_driver.ue_devname, device_xname(dev), | 850 | strncpy(ue->u.ue_driver.ue_devname, device_xname(dev), | |
844 | sizeof ue->u.ue_driver.ue_devname); | 851 | sizeof ue->u.ue_driver.ue_devname); | |
845 | usb_add_event(type, ue); | 852 | usb_add_event(type, ue); | |
846 | } | 853 | } | |
847 | 854 | |||
848 | Static struct usb_event * | 855 | Static struct usb_event * | |
849 | usb_alloc_event(void) | 856 | usb_alloc_event(void) | |
850 | { | 857 | { | |
851 | /* Yes, this is right; we allocate enough so that we can use it later */ | 858 | /* Yes, this is right; we allocate enough so that we can use it later */ | |
852 | return malloc(sizeof(struct usb_event_q), M_USBDEV, M_WAITOK|M_ZERO); | 859 | return malloc(sizeof(struct usb_event_q), M_USBDEV, M_WAITOK|M_ZERO); | |
853 | } | 860 | } | |
854 | 861 | |||
855 | Static void | 862 | Static void | |
856 | usb_free_event(struct usb_event *uep) | 863 | usb_free_event(struct usb_event *uep) | |
857 | { | 864 | { | |
858 | free(uep, M_USBDEV); | 865 | free(uep, M_USBDEV); | |
859 | } | 866 | } | |
860 | 867 | |||
861 | Static void | 868 | Static void | |
862 | usb_add_event(int type, struct usb_event *uep) | 869 | usb_add_event(int type, struct usb_event *uep) | |
863 | { | 870 | { | |
864 | struct usb_event_q *ueq; | 871 | struct usb_event_q *ueq; | |
865 | struct timeval thetime; | 872 | struct timeval thetime; | |
866 | int s; | 873 | int s; | |
867 | 874 | |||
868 | microtime(&thetime); | 875 | microtime(&thetime); | |
869 | /* Don't want to wait here inside splusb() */ | 876 | /* Don't want to wait here inside splusb() */ | |
870 | ueq = (struct usb_event_q *)(void *)uep; | 877 | ueq = (struct usb_event_q *)(void *)uep; | |
871 | ueq->ue = *uep; | 878 | ueq->ue = *uep; | |
872 | ueq->ue.ue_type = type; | 879 | ueq->ue.ue_type = type; | |
873 | TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time); | 880 | TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time); | |
874 | 881 | |||
875 | s = splusb(); | 882 | s = splusb(); | |
876 | if (++usb_nevents >= USB_MAX_EVENTS) { | 883 | if (++usb_nevents >= USB_MAX_EVENTS) { | |
877 | /* Too many queued events, drop an old one. */ | 884 | /* Too many queued events, drop an old one. */ | |
878 | DPRINTFN(-1,("usb: event dropped\n")); | 885 | DPRINTFN(-1,("usb: event dropped\n")); | |
879 | (void)usb_get_next_event(0); | 886 | (void)usb_get_next_event(0); | |
880 | } | 887 | } | |
881 | SIMPLEQ_INSERT_TAIL(&usb_events, ueq, next); | 888 | SIMPLEQ_INSERT_TAIL(&usb_events, ueq, next); | |
882 | wakeup(&usb_events); | 889 | wakeup(&usb_events); | |
883 | selnotify(&usb_selevent, 0, 0); | 890 | selnotify(&usb_selevent, 0, 0); | |
884 | if (usb_async_proc != NULL) { | 891 | if (usb_async_proc != NULL) { | |
885 | kpreempt_disable(); | 892 | kpreempt_disable(); | |
886 | softint_schedule(usb_async_sih); | 893 | softint_schedule(usb_async_sih); | |
887 | kpreempt_enable(); | 894 | kpreempt_enable(); | |
888 | } | 895 | } | |
889 | splx(s); | 896 | splx(s); | |
890 | } | 897 | } | |
891 | 898 | |||
892 | Static void | 899 | Static void | |
893 | usb_async_intr(void *cookie) | 900 | usb_async_intr(void *cookie) | |
894 | { | 901 | { | |
895 | proc_t *proc; | 902 | proc_t *proc; | |
896 | 903 | |||
897 | mutex_enter(proc_lock); | 904 | mutex_enter(proc_lock); | |
898 | if ((proc = usb_async_proc) != NULL) | 905 | if ((proc = usb_async_proc) != NULL) | |
899 | psignal(proc, SIGIO); | 906 | psignal(proc, SIGIO); | |
900 | mutex_exit(proc_lock); | 907 | mutex_exit(proc_lock); | |
901 | } | 908 | } | |
902 | 909 | |||
903 | void | 910 | void | |
904 | usb_schedsoftintr(usbd_bus_handle bus) | 911 | usb_schedsoftintr(usbd_bus_handle bus) | |
905 | { | 912 | { | |
906 | DPRINTFN(10,("usb_schedsoftintr: polling=%d\n", bus->use_polling)); | 913 | DPRINTFN(10,("usb_schedsoftintr: polling=%d\n", bus->use_polling)); | |
907 | if (bus->use_polling) { | 914 | if (bus->use_polling) { | |
908 | bus->methods->soft_intr(bus); | 915 | bus->methods->soft_intr(bus); | |
909 | } else { | 916 | } else { | |
910 | kpreempt_disable(); | 917 | kpreempt_disable(); | |
911 | softint_schedule(bus->soft); | 918 | softint_schedule(bus->soft); | |
912 | kpreempt_enable(); | 919 | kpreempt_enable(); | |
913 | } | 920 | } | |
914 | } | 921 | } | |
915 | 922 | |||
916 | int | 923 | int | |
917 | usb_activate(device_t self, enum devact act) | 924 | usb_activate(device_t self, enum devact act) | |
918 | { | 925 | { | |
919 | struct usb_softc *sc = device_private(self); | 926 | struct usb_softc *sc = device_private(self); | |
920 | 927 | |||
921 | switch (act) { | 928 | switch (act) { | |
922 | case DVACT_DEACTIVATE: | 929 | case DVACT_DEACTIVATE: | |
923 | sc->sc_dying = 1; | 930 | sc->sc_dying = 1; | |
924 | return 0; | 931 | return 0; | |
925 | default: | 932 | default: | |
926 | return EOPNOTSUPP; | 933 | return EOPNOTSUPP; | |
927 | } | 934 | } | |
928 | } | 935 | } | |
929 | 936 | |||
930 | void | 937 | void | |
931 | usb_childdet(device_t self, device_t child) | 938 | usb_childdet(device_t self, device_t child) | |
932 | { | 939 | { | |
933 | int i; | 940 | int i; | |
934 | struct usb_softc *sc = device_private(self); | 941 | struct usb_softc *sc = device_private(self); | |
935 | struct usbd_device *dev; | 942 | struct usbd_device *dev; | |
936 | 943 | |||
937 | if ((dev = sc->sc_port.device) == NULL || dev->subdevlen == 0) | 944 | if ((dev = sc->sc_port.device) == NULL || dev->subdevlen == 0) | |
938 | return; | 945 | return; | |
939 | 946 | |||
940 | for (i = 0; i < dev->subdevlen; i++) | 947 | for (i = 0; i < dev->subdevlen; i++) | |
941 | if (dev->subdevs[i] == child) | 948 | if (dev->subdevs[i] == child) | |
942 | dev->subdevs[i] = NULL; | 949 | dev->subdevs[i] = NULL; | |
943 | } | 950 | } | |
944 | 951 | |||
945 | int | 952 | int | |
946 | usb_detach(device_t self, int flags) | 953 | usb_detach(device_t self, int flags) | |
947 | { | 954 | { | |
948 | struct usb_softc *sc = device_private(self); | 955 | struct usb_softc *sc = device_private(self); | |
949 | struct usb_event *ue; | 956 | struct usb_event *ue; | |
950 | int rc; | 957 | int rc; | |
951 | 958 | |||
952 | DPRINTF(("usb_detach: start\n")); | 959 | DPRINTF(("usb_detach: start\n")); | |
953 | 960 | |||
954 | /* Make all devices disconnect. */ | 961 | /* Make all devices disconnect. */ | |
955 | if (sc->sc_port.device != NULL && | 962 | if (sc->sc_port.device != NULL && | |
956 | (rc = usb_disconnect_port(&sc->sc_port, self, flags)) != 0) | 963 | (rc = usb_disconnect_port(&sc->sc_port, self, flags)) != 0) | |
957 | return rc; | 964 | return rc; | |
958 | 965 | |||
959 | pmf_device_deregister(self); | 966 | pmf_device_deregister(self); | |
960 | /* Kill off event thread. */ | 967 | /* Kill off event thread. */ | |
961 | sc->sc_dying = 1; | 968 | sc->sc_dying = 1; | |
962 | while (sc->sc_event_thread != NULL) { | 969 | while (sc->sc_event_thread != NULL) { | |
963 | wakeup(&sc->sc_bus->needs_explore); | 970 | wakeup(&sc->sc_bus->needs_explore); | |
964 | tsleep(sc, PWAIT, "usbdet", hz * 60); | 971 | tsleep(sc, PWAIT, "usbdet", hz * 60); | |
965 | } | 972 | } | |
966 | DPRINTF(("usb_detach: event thread dead\n")); | 973 | DPRINTF(("usb_detach: event thread dead\n")); | |
967 | 974 | |||
968 | if (sc->sc_bus->soft != NULL) { | 975 | if (sc->sc_bus->soft != NULL) { | |
969 | softint_disestablish(sc->sc_bus->soft); | 976 | softint_disestablish(sc->sc_bus->soft); | |
970 | sc->sc_bus->soft = NULL; | 977 | sc->sc_bus->soft = NULL; | |
971 | } | 978 | } | |
972 | 979 | |||
973 | ue = usb_alloc_event(); | 980 | ue = usb_alloc_event(); | |
974 | ue->u.ue_ctrlr.ue_bus = device_unit(self); | 981 | ue->u.ue_ctrlr.ue_bus = device_unit(self); | |
975 | usb_add_event(USB_EVENT_CTRLR_DETACH, ue); | 982 | usb_add_event(USB_EVENT_CTRLR_DETACH, ue); | |
976 | 983 | |||
977 | return (0); | 984 | return (0); | |
978 | } | 985 | } | |
979 | 986 | |||
980 | #ifdef COMPAT_30 | 987 | #ifdef COMPAT_30 | |
981 | Static void | 988 | Static void | |
982 | usb_copy_old_devinfo(struct usb_device_info_old *uo, | 989 | usb_copy_old_devinfo(struct usb_device_info_old *uo, | |
983 | const struct usb_device_info *ue) | 990 | const struct usb_device_info *ue) | |
984 | { | 991 | { | |
985 | const unsigned char *p; | 992 | const unsigned char *p; | |
986 | unsigned char *q; | 993 | unsigned char *q; | |
987 | int i, n; | 994 | int i, n; | |
988 | 995 | |||
989 | uo->udi_bus = ue->udi_bus; | 996 | uo->udi_bus = ue->udi_bus; | |
990 | uo->udi_addr = ue->udi_addr; | 997 | uo->udi_addr = ue->udi_addr; | |
991 | uo->udi_cookie = ue->udi_cookie; | 998 | uo->udi_cookie = ue->udi_cookie; | |
992 | for (i = 0, p = (const unsigned char *)ue->udi_product, | 999 | for (i = 0, p = (const unsigned char *)ue->udi_product, | |
993 | q = (unsigned char *)uo->udi_product; | 1000 | q = (unsigned char *)uo->udi_product; | |
994 | *p && i < USB_MAX_STRING_LEN - 1; p++) { | 1001 | *p && i < USB_MAX_STRING_LEN - 1; p++) { | |
995 | if (*p < 0x80) | 1002 | if (*p < 0x80) | |
996 | q[i++] = *p; | 1003 | q[i++] = *p; | |
997 | else { | 1004 | else { | |
998 | q[i++] = '?'; | 1005 | q[i++] = '?'; | |
999 | if ((*p & 0xe0) == 0xe0) | 1006 | if ((*p & 0xe0) == 0xe0) | |
1000 | p++; | 1007 | p++; | |
1001 | p++; | 1008 | p++; | |
1002 | } | 1009 | } | |
1003 | } | 1010 | } | |
1004 | q[i] = 0; | 1011 | q[i] = 0; | |
1005 | 1012 | |||
1006 | for (i = 0, p = ue->udi_vendor, q = uo->udi_vendor; | 1013 | for (i = 0, p = ue->udi_vendor, q = uo->udi_vendor; | |
1007 | *p && i < USB_MAX_STRING_LEN - 1; p++) { | 1014 | *p && i < USB_MAX_STRING_LEN - 1; p++) { | |
1008 | if (* p < 0x80) | 1015 | if (* p < 0x80) | |
1009 | q[i++] = *p; | 1016 | q[i++] = *p; | |
1010 | else { | 1017 | else { | |
1011 | q[i++] = '?'; | 1018 | q[i++] = '?'; | |
1012 | p++; | 1019 | p++; | |
1013 | if ((*p & 0xe0) == 0xe0) | 1020 | if ((*p & 0xe0) == 0xe0) | |
1014 | p++; | 1021 | p++; | |
1015 | } | 1022 | } | |
1016 | } | 1023 | } | |
1017 | q[i] = 0; | 1024 | q[i] = 0; | |
1018 | 1025 | |||
1019 | memcpy(uo->udi_release, ue->udi_release, sizeof(uo->udi_release)); | 1026 | memcpy(uo->udi_release, ue->udi_release, sizeof(uo->udi_release)); | |
1020 | 1027 | |||
1021 | uo->udi_productNo = ue->udi_productNo; | 1028 | uo->udi_productNo = ue->udi_productNo; | |
1022 | uo->udi_vendorNo = ue->udi_vendorNo; | 1029 | uo->udi_vendorNo = ue->udi_vendorNo; | |
1023 | uo->udi_releaseNo = ue->udi_releaseNo; | 1030 | uo->udi_releaseNo = ue->udi_releaseNo; | |
1024 | uo->udi_class = ue->udi_class; | 1031 | uo->udi_class = ue->udi_class; | |
1025 | uo->udi_subclass = ue->udi_subclass; | 1032 | uo->udi_subclass = ue->udi_subclass; | |
1026 | uo->udi_protocol = ue->udi_protocol; | 1033 | uo->udi_protocol = ue->udi_protocol; | |
1027 | uo->udi_config = ue->udi_config; | 1034 | uo->udi_config = ue->udi_config; | |
1028 | uo->udi_speed = ue->udi_speed; | 1035 | uo->udi_speed = ue->udi_speed; | |
1029 | uo->udi_power = ue->udi_power; | 1036 | uo->udi_power = ue->udi_power; | |
1030 | uo->udi_nports = ue->udi_nports; | 1037 | uo->udi_nports = ue->udi_nports; | |
1031 | 1038 | |||
1032 | for (n=0; n<USB_MAX_DEVNAMES; n++) | 1039 | for (n=0; n<USB_MAX_DEVNAMES; n++) | |
1033 | memcpy(uo->udi_devnames[n], | 1040 | memcpy(uo->udi_devnames[n], | |
1034 | ue->udi_devnames[n], USB_MAX_DEVNAMELEN); | 1041 | ue->udi_devnames[n], USB_MAX_DEVNAMELEN); | |
1035 | memcpy(uo->udi_ports, ue->udi_ports, sizeof(uo->udi_ports)); | 1042 | memcpy(uo->udi_ports, ue->udi_ports, sizeof(uo->udi_ports)); | |
1036 | } | 1043 | } | |
1037 | #endif | 1044 | #endif |
--- src/sys/dev/usb/usb_subr.c 2011/12/04 13:23:17 1.180.6.1
+++ src/sys/dev/usb/usb_subr.c 2011/12/08 02:51:08 1.180.6.2
@@ -1,1577 +1,1572 @@ | @@ -1,1577 +1,1572 @@ | |||
1 | /* $NetBSD: usb_subr.c,v 1.180.6.1 2011/12/04 13:23:17 jmcneill Exp $ */ | 1 | /* $NetBSD: usb_subr.c,v 1.180.6.2 2011/12/08 02:51:08 mrg Exp $ */ | |
2 | /* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */ | 2 | /* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 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 | #include <sys/cdefs.h> | 34 | #include <sys/cdefs.h> | |
35 | __KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.180.6.1 2011/12/04 13:23:17 jmcneill Exp $"); | 35 | __KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.180.6.2 2011/12/08 02:51:08 mrg Exp $"); | |
36 | 36 | |||
37 | #include "opt_compat_netbsd.h" | 37 | #include "opt_compat_netbsd.h" | |
38 | #include "opt_usbverbose.h" | 38 | #include "opt_usbverbose.h" | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/systm.h> | 41 | #include <sys/systm.h> | |
42 | #include <sys/kernel.h> | 42 | #include <sys/kernel.h> | |
43 | #include <sys/malloc.h> | 43 | #include <sys/malloc.h> | |
44 | #include <sys/device.h> | 44 | #include <sys/device.h> | |
45 | #include <sys/select.h> | 45 | #include <sys/select.h> | |
46 | #include <sys/proc.h> | 46 | #include <sys/proc.h> | |
47 | 47 | |||
48 | #include <sys/bus.h> | 48 | #include <sys/bus.h> | |
49 | #include <sys/module.h> | 49 | #include <sys/module.h> | |
50 | 50 | |||
51 | #include <dev/usb/usb.h> | 51 | #include <dev/usb/usb.h> | |
52 | 52 | |||
53 | #include <dev/usb/usbdi.h> | 53 | #include <dev/usb/usbdi.h> | |
54 | #include <dev/usb/usbdi_util.h> | 54 | #include <dev/usb/usbdi_util.h> | |
55 | #include <dev/usb/usbdivar.h> | 55 | #include <dev/usb/usbdivar.h> | |
56 | #include <dev/usb/usbdevs.h> | 56 | #include <dev/usb/usbdevs.h> | |
57 | #include <dev/usb/usb_quirks.h> | 57 | #include <dev/usb/usb_quirks.h> | |
58 | #include <dev/usb/usb_verbose.h> | 58 | #include <dev/usb/usb_verbose.h> | |
59 | 59 | |||
60 | #include "locators.h" | 60 | #include "locators.h" | |
61 | 61 | |||
62 | #ifdef USB_DEBUG | 62 | #ifdef USB_DEBUG | |
63 | #define DPRINTF(x) if (usbdebug) printf x | 63 | #define DPRINTF(x) if (usbdebug) printf x | |
64 | #define DPRINTFN(n,x) if (usbdebug>(n)) printf x | 64 | #define DPRINTFN(n,x) if (usbdebug>(n)) printf x | |
65 | extern int usbdebug; | 65 | extern int usbdebug; | |
66 | #else | 66 | #else | |
67 | #define DPRINTF(x) | 67 | #define DPRINTF(x) | |
68 | #define DPRINTFN(n,x) | 68 | #define DPRINTFN(n,x) | |
69 | #endif | 69 | #endif | |
70 | 70 | |||
71 | MALLOC_DEFINE(M_USB, "USB", "USB misc. memory"); | 71 | MALLOC_DEFINE(M_USB, "USB", "USB misc. memory"); | |
72 | MALLOC_DEFINE(M_USBDEV, "USB device", "USB device driver"); | 72 | MALLOC_DEFINE(M_USBDEV, "USB device", "USB device driver"); | |
73 | MALLOC_DEFINE(M_USBHC, "USB HC", "USB host controller"); | 73 | MALLOC_DEFINE(M_USBHC, "USB HC", "USB host controller"); | |
74 | 74 | |||
75 | Static usbd_status usbd_set_config(usbd_device_handle, int); | 75 | Static usbd_status usbd_set_config(usbd_device_handle, int); | |
76 | Static void usbd_devinfo(usbd_device_handle, int, char *, size_t); | 76 | Static void usbd_devinfo(usbd_device_handle, int, char *, size_t); | |
77 | Static void usbd_devinfo_vp(usbd_device_handle, char *, size_t, char *, size_t, | 77 | Static void usbd_devinfo_vp(usbd_device_handle, char *, size_t, char *, size_t, | |
78 | int, int); | 78 | int, int); | |
79 | Static int usbd_getnewaddr(usbd_bus_handle); | 79 | Static int usbd_getnewaddr(usbd_bus_handle); | |
80 | Static int usbd_print(void *, const char *); | 80 | Static int usbd_print(void *, const char *); | |
81 | Static int usbd_ifprint(void *, const char *); | 81 | Static int usbd_ifprint(void *, const char *); | |
82 | Static void usbd_free_iface_data(usbd_device_handle, int); | 82 | Static void usbd_free_iface_data(usbd_device_handle, int); | |
83 | Static void usbd_kill_pipe(usbd_pipe_handle); | 83 | Static void usbd_kill_pipe(usbd_pipe_handle); | |
84 | usbd_status usbd_attach_roothub(device_t, usbd_device_handle); | 84 | usbd_status usbd_attach_roothub(device_t, usbd_device_handle); | |
85 | Static usbd_status usbd_probe_and_attach(device_t, usbd_device_handle, int, | 85 | Static usbd_status usbd_probe_and_attach(device_t, usbd_device_handle, int, | |
86 | int); | 86 | int); | |
87 | 87 | |||
88 | Static u_int32_t usb_cookie_no = 0; | 88 | Static u_int32_t usb_cookie_no = 0; | |
89 | 89 | |||
90 | Static const char * const usbd_error_strs[] = { | 90 | Static const char * const usbd_error_strs[] = { | |
91 | "NORMAL_COMPLETION", | 91 | "NORMAL_COMPLETION", | |
92 | "IN_PROGRESS", | 92 | "IN_PROGRESS", | |
93 | "PENDING_REQUESTS", | 93 | "PENDING_REQUESTS", | |
94 | "NOT_STARTED", | 94 | "NOT_STARTED", | |
95 | "INVAL", | 95 | "INVAL", | |
96 | "NOMEM", | 96 | "NOMEM", | |
97 | "CANCELLED", | 97 | "CANCELLED", | |
98 | "BAD_ADDRESS", | 98 | "BAD_ADDRESS", | |
99 | "IN_USE", | 99 | "IN_USE", | |
100 | "NO_ADDR", | 100 | "NO_ADDR", | |
101 | "SET_ADDR_FAILED", | 101 | "SET_ADDR_FAILED", | |
102 | "NO_POWER", | 102 | "NO_POWER", | |
103 | "TOO_DEEP", | 103 | "TOO_DEEP", | |
104 | "IOERROR", | 104 | "IOERROR", | |
105 | "NOT_CONFIGURED", | 105 | "NOT_CONFIGURED", | |
106 | "TIMEOUT", | 106 | "TIMEOUT", | |
107 | "SHORT_XFER", | 107 | "SHORT_XFER", | |
108 | "STALLED", | 108 | "STALLED", | |
109 | "INTERRUPTED", | 109 | "INTERRUPTED", | |
110 | "XXX", | 110 | "XXX", | |
111 | }; | 111 | }; | |
112 | 112 | |||
113 | void usb_load_verbose(void); | 113 | void usb_load_verbose(void); | |
114 | 114 | |||
115 | void get_usb_vendor_stub(char *, size_t, usb_vendor_id_t); | 115 | void get_usb_vendor_stub(char *, size_t, usb_vendor_id_t); | |
116 | void get_usb_product_stub(char *, size_t, usb_vendor_id_t, usb_product_id_t); | 116 | void get_usb_product_stub(char *, size_t, usb_vendor_id_t, usb_product_id_t); | |
117 | 117 | |||
118 | void (*get_usb_vendor)(char *, size_t, usb_vendor_id_t) = get_usb_vendor_stub; | 118 | void (*get_usb_vendor)(char *, size_t, usb_vendor_id_t) = get_usb_vendor_stub; | |
119 | void (*get_usb_product)(char *, size_t, usb_vendor_id_t, usb_product_id_t) = | 119 | void (*get_usb_product)(char *, size_t, usb_vendor_id_t, usb_product_id_t) = | |
120 | get_usb_product_stub; | 120 | get_usb_product_stub; | |
121 | 121 | |||
122 | int usb_verbose_loaded = 0; | 122 | int usb_verbose_loaded = 0; | |
123 | 123 | |||
124 | /* | 124 | /* | |
125 | * Load the usbverbose module | 125 | * Load the usbverbose module | |
126 | */ | 126 | */ | |
127 | void usb_load_verbose(void) | 127 | void usb_load_verbose(void) | |
128 | { | 128 | { | |
129 | if (usb_verbose_loaded == 0) | 129 | if (usb_verbose_loaded == 0) | |
130 | module_autoload("usbverbose", MODULE_CLASS_MISC); | 130 | module_autoload("usbverbose", MODULE_CLASS_MISC); | |
131 | } | 131 | } | |
132 | 132 | |||
133 | void get_usb_vendor_stub(char *v, size_t l, usb_vendor_id_t v_id) | 133 | void get_usb_vendor_stub(char *v, size_t l, usb_vendor_id_t v_id) | |
134 | { | 134 | { | |
135 | usb_load_verbose(); | 135 | usb_load_verbose(); | |
136 | if (usb_verbose_loaded) | 136 | if (usb_verbose_loaded) | |
137 | get_usb_vendor(v, l, v_id); | 137 | get_usb_vendor(v, l, v_id); | |
138 | } | 138 | } | |
139 | 139 | |||
140 | void get_usb_product_stub(char *p, size_t l, usb_vendor_id_t v_id, | 140 | void get_usb_product_stub(char *p, size_t l, usb_vendor_id_t v_id, | |
141 | usb_product_id_t p_id) | 141 | usb_product_id_t p_id) | |
142 | { | 142 | { | |
143 | usb_load_verbose(); | 143 | usb_load_verbose(); | |
144 | if (usb_verbose_loaded) | 144 | if (usb_verbose_loaded) | |
145 | get_usb_product(p, l, v_id, p_id); | 145 | get_usb_product(p, l, v_id, p_id); | |
146 | } | 146 | } | |
147 | 147 | |||
148 | const char * | 148 | const char * | |
149 | usbd_errstr(usbd_status err) | 149 | usbd_errstr(usbd_status err) | |
150 | { | 150 | { | |
151 | static char buffer[5]; | 151 | static char buffer[5]; | |
152 | 152 | |||
153 | if (err < USBD_ERROR_MAX) { | 153 | if (err < USBD_ERROR_MAX) { | |
154 | return usbd_error_strs[err]; | 154 | return usbd_error_strs[err]; | |
155 | } else { | 155 | } else { | |
156 | snprintf(buffer, sizeof buffer, "%d", err); | 156 | snprintf(buffer, sizeof buffer, "%d", err); | |
157 | return buffer; | 157 | return buffer; | |
158 | } | 158 | } | |
159 | } | 159 | } | |
160 | 160 | |||
161 | usbd_status | 161 | usbd_status | |
162 | usbd_get_string_desc(usbd_device_handle dev, int sindex, int langid, | 162 | usbd_get_string_desc(usbd_device_handle dev, int sindex, int langid, | |
163 | usb_string_descriptor_t *sdesc, int *sizep) | 163 | usb_string_descriptor_t *sdesc, int *sizep) | |
164 | { | 164 | { | |
165 | usb_device_request_t req; | 165 | usb_device_request_t req; | |
166 | usbd_status err; | 166 | usbd_status err; | |
167 | int actlen; | 167 | int actlen; | |
168 | 168 | |||
169 | req.bmRequestType = UT_READ_DEVICE; | 169 | req.bmRequestType = UT_READ_DEVICE; | |
170 | req.bRequest = UR_GET_DESCRIPTOR; | 170 | req.bRequest = UR_GET_DESCRIPTOR; | |
171 | USETW2(req.wValue, UDESC_STRING, sindex); | 171 | USETW2(req.wValue, UDESC_STRING, sindex); | |
172 | USETW(req.wIndex, langid); | 172 | USETW(req.wIndex, langid); | |
173 | USETW(req.wLength, 2); /* only size byte first */ | 173 | USETW(req.wLength, 2); /* only size byte first */ | |
174 | err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, | 174 | err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, | |
175 | &actlen, USBD_DEFAULT_TIMEOUT); | 175 | &actlen, USBD_DEFAULT_TIMEOUT); | |
176 | if (err) | 176 | if (err) | |
177 | return (err); | 177 | return (err); | |
178 | 178 | |||
179 | if (actlen < 2) | 179 | if (actlen < 2) | |
180 | return (USBD_SHORT_XFER); | 180 | return (USBD_SHORT_XFER); | |
181 | 181 | |||
182 | USETW(req.wLength, sdesc->bLength); /* the whole string */ | 182 | USETW(req.wLength, sdesc->bLength); /* the whole string */ | |
183 | err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, | 183 | err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, | |
184 | &actlen, USBD_DEFAULT_TIMEOUT); | 184 | &actlen, USBD_DEFAULT_TIMEOUT); | |
185 | if (err) | 185 | if (err) | |
186 | return (err); | 186 | return (err); | |
187 | 187 | |||
188 | if (actlen != sdesc->bLength) { | 188 | if (actlen != sdesc->bLength) { | |
189 | DPRINTFN(-1, ("usbd_get_string_desc: expected %d, got %d\n", | 189 | DPRINTFN(-1, ("usbd_get_string_desc: expected %d, got %d\n", | |
190 | sdesc->bLength, actlen)); | 190 | sdesc->bLength, actlen)); | |
191 | } | 191 | } | |
192 | 192 | |||
193 | *sizep = actlen; | 193 | *sizep = actlen; | |
194 | return (USBD_NORMAL_COMPLETION); | 194 | return (USBD_NORMAL_COMPLETION); | |
195 | } | 195 | } | |
196 | 196 | |||
197 | static void | 197 | static void | |
198 | usbd_trim_spaces(char *p) | 198 | usbd_trim_spaces(char *p) | |
199 | { | 199 | { | |
200 | char *q, *e; | 200 | char *q, *e; | |
201 | 201 | |||
202 | q = e = p; | 202 | q = e = p; | |
203 | while (*q == ' ') /* skip leading spaces */ | 203 | while (*q == ' ') /* skip leading spaces */ | |
204 | q++; | 204 | q++; | |
205 | while ((*p = *q++)) /* copy string */ | 205 | while ((*p = *q++)) /* copy string */ | |
206 | if (*p++ != ' ') /* remember last non-space */ | 206 | if (*p++ != ' ') /* remember last non-space */ | |
207 | e = p; | 207 | e = p; | |
208 | *e = '\0'; /* kill trailing spaces */ | 208 | *e = '\0'; /* kill trailing spaces */ | |
209 | } | 209 | } | |
210 | 210 | |||
211 | Static void | 211 | Static void | |
212 | usbd_devinfo_vp(usbd_device_handle dev, char *v, size_t vl, char *p, | 212 | usbd_devinfo_vp(usbd_device_handle dev, char *v, size_t vl, char *p, | |
213 | size_t pl, int usedev, int useencoded) | 213 | size_t pl, int usedev, int useencoded) | |
214 | { | 214 | { | |
215 | usb_device_descriptor_t *udd = &dev->ddesc; | 215 | usb_device_descriptor_t *udd = &dev->ddesc; | |
216 | if (dev == NULL) | 216 | if (dev == NULL) | |
217 | return; | 217 | return; | |
218 | 218 | |||
219 | v[0] = p[0] = '\0'; | 219 | v[0] = p[0] = '\0'; | |
220 | 220 | |||
221 | if (usedev) { | 221 | if (usedev) { | |
222 | if (usbd_get_string0(dev, udd->iManufacturer, v, useencoded) == | 222 | if (usbd_get_string0(dev, udd->iManufacturer, v, useencoded) == | |
223 | USBD_NORMAL_COMPLETION) | 223 | USBD_NORMAL_COMPLETION) | |
224 | usbd_trim_spaces(v); | 224 | usbd_trim_spaces(v); | |
225 | if (usbd_get_string0(dev, udd->iProduct, p, useencoded) == | 225 | if (usbd_get_string0(dev, udd->iProduct, p, useencoded) == | |
226 | USBD_NORMAL_COMPLETION) | 226 | USBD_NORMAL_COMPLETION) | |
227 | usbd_trim_spaces(p); | 227 | usbd_trim_spaces(p); | |
228 | } | 228 | } | |
229 | if (v[0] == '\0') | 229 | if (v[0] == '\0') | |
230 | get_usb_vendor(v, vl, UGETW(udd->idVendor)); | 230 | get_usb_vendor(v, vl, UGETW(udd->idVendor)); | |
231 | if (p[0] == '\0') | 231 | if (p[0] == '\0') | |
232 | get_usb_product(p, pl, UGETW(udd->idVendor), | 232 | get_usb_product(p, pl, UGETW(udd->idVendor), | |
233 | UGETW(udd->idProduct)); | 233 | UGETW(udd->idProduct)); | |
234 | 234 | |||
235 | if (v[0] == '\0') | 235 | if (v[0] == '\0') | |
236 | snprintf(v, vl, "vendor 0x%04x", UGETW(udd->idVendor)); | 236 | snprintf(v, vl, "vendor 0x%04x", UGETW(udd->idVendor)); | |
237 | if (p[0] == '\0') | 237 | if (p[0] == '\0') | |
238 | snprintf(p, pl, "product 0x%04x", UGETW(udd->idProduct)); | 238 | snprintf(p, pl, "product 0x%04x", UGETW(udd->idProduct)); | |
239 | } | 239 | } | |
240 | 240 | |||
241 | int | 241 | int | |
242 | usbd_printBCD(char *cp, size_t l, int bcd) | 242 | usbd_printBCD(char *cp, size_t l, int bcd) | |
243 | { | 243 | { | |
244 | return snprintf(cp, l, "%x.%02x", bcd >> 8, bcd & 0xff); | 244 | return snprintf(cp, l, "%x.%02x", bcd >> 8, bcd & 0xff); | |
245 | } | 245 | } | |
246 | 246 | |||
247 | Static void | 247 | Static void | |
248 | usbd_devinfo(usbd_device_handle dev, int showclass, char *cp, size_t l) | 248 | usbd_devinfo(usbd_device_handle dev, int showclass, char *cp, size_t l) | |
249 | { | 249 | { | |
250 | usb_device_descriptor_t *udd = &dev->ddesc; | 250 | usb_device_descriptor_t *udd = &dev->ddesc; | |
251 | char *vendor, *product; | 251 | char *vendor, *product; | |
252 | int bcdDevice, bcdUSB; | 252 | int bcdDevice, bcdUSB; | |
253 | char *ep; | 253 | char *ep; | |
254 | 254 | |||
255 | vendor = malloc(USB_MAX_ENCODED_STRING_LEN * 2, M_USB, M_NOWAIT); | 255 | vendor = malloc(USB_MAX_ENCODED_STRING_LEN * 2, M_USB, M_NOWAIT); | |
256 | if (vendor == NULL) { | 256 | if (vendor == NULL) { | |
257 | *cp = '\0'; | 257 | *cp = '\0'; | |
258 | return; | 258 | return; | |
259 | } | 259 | } | |
260 | product = &vendor[USB_MAX_ENCODED_STRING_LEN]; | 260 | product = &vendor[USB_MAX_ENCODED_STRING_LEN]; | |
261 | 261 | |||
262 | ep = cp + l; | 262 | ep = cp + l; | |
263 | 263 | |||
264 | usbd_devinfo_vp(dev, vendor, USB_MAX_ENCODED_STRING_LEN, | 264 | usbd_devinfo_vp(dev, vendor, USB_MAX_ENCODED_STRING_LEN, | |
265 | product, USB_MAX_ENCODED_STRING_LEN, 1, 1); | 265 | product, USB_MAX_ENCODED_STRING_LEN, 1, 1); | |
266 | cp += snprintf(cp, ep - cp, "%s %s", vendor, product); | 266 | cp += snprintf(cp, ep - cp, "%s %s", vendor, product); | |
267 | if (showclass) | 267 | if (showclass) | |
268 | cp += snprintf(cp, ep - cp, ", class %d/%d", | 268 | cp += snprintf(cp, ep - cp, ", class %d/%d", | |
269 | udd->bDeviceClass, udd->bDeviceSubClass); | 269 | udd->bDeviceClass, udd->bDeviceSubClass); | |
270 | bcdUSB = UGETW(udd->bcdUSB); | 270 | bcdUSB = UGETW(udd->bcdUSB); | |
271 | bcdDevice = UGETW(udd->bcdDevice); | 271 | bcdDevice = UGETW(udd->bcdDevice); | |
272 | cp += snprintf(cp, ep - cp, ", rev "); | 272 | cp += snprintf(cp, ep - cp, ", rev "); | |
273 | cp += usbd_printBCD(cp, ep - cp, bcdUSB); | 273 | cp += usbd_printBCD(cp, ep - cp, bcdUSB); | |
274 | *cp++ = '/'; | 274 | *cp++ = '/'; | |
275 | cp += usbd_printBCD(cp, ep - cp, bcdDevice); | 275 | cp += usbd_printBCD(cp, ep - cp, bcdDevice); | |
276 | cp += snprintf(cp, ep - cp, ", addr %d", dev->address); | 276 | cp += snprintf(cp, ep - cp, ", addr %d", dev->address); | |
277 | *cp = 0; | 277 | *cp = 0; | |
278 | free(vendor, M_USB); | 278 | free(vendor, M_USB); | |
279 | } | 279 | } | |
280 | 280 | |||
281 | char * | 281 | char * | |
282 | usbd_devinfo_alloc(usbd_device_handle dev, int showclass) | 282 | usbd_devinfo_alloc(usbd_device_handle dev, int showclass) | |
283 | { | 283 | { | |
284 | char *devinfop; | 284 | char *devinfop; | |
285 | 285 | |||
286 | devinfop = malloc(DEVINFOSIZE, M_TEMP, M_WAITOK); | 286 | devinfop = malloc(DEVINFOSIZE, M_TEMP, M_WAITOK); | |
287 | usbd_devinfo(dev, showclass, devinfop, DEVINFOSIZE); | 287 | usbd_devinfo(dev, showclass, devinfop, DEVINFOSIZE); | |
288 | return devinfop; | 288 | return devinfop; | |
289 | } | 289 | } | |
290 | 290 | |||
291 | void | 291 | void | |
292 | usbd_devinfo_free(char *devinfop) | 292 | usbd_devinfo_free(char *devinfop) | |
293 | { | 293 | { | |
294 | free(devinfop, M_TEMP); | 294 | free(devinfop, M_TEMP); | |
295 | } | 295 | } | |
296 | 296 | |||
297 | /* Delay for a certain number of ms */ | 297 | /* Delay for a certain number of ms */ | |
298 | void | 298 | void | |
299 | usb_delay_ms(usbd_bus_handle bus, u_int ms) | 299 | usb_delay_ms(usbd_bus_handle bus, u_int ms) | |
300 | { | 300 | { | |
301 | /* Wait at least two clock ticks so we know the time has passed. */ | 301 | /* Wait at least two clock ticks so we know the time has passed. */ | |
302 | if (bus->use_polling || cold) | 302 | if (bus->use_polling || cold) | |
303 | delay((ms+1) * 1000); | 303 | delay((ms+1) * 1000); | |
304 | else | 304 | else | |
305 | tsleep(&ms, PRIBIO, "usbdly", (ms*hz+999)/1000 + 1); | 305 | tsleep(&ms, PRIBIO, "usbdly", (ms*hz+999)/1000 + 1); | |
306 | } | 306 | } | |
307 | 307 | |||
308 | /* Delay given a device handle. */ | 308 | /* Delay given a device handle. */ | |
309 | void | 309 | void | |
310 | usbd_delay_ms(usbd_device_handle dev, u_int ms) | 310 | usbd_delay_ms(usbd_device_handle dev, u_int ms) | |
311 | { | 311 | { | |
312 | usb_delay_ms(dev->bus, ms); | 312 | usb_delay_ms(dev->bus, ms); | |
313 | } | 313 | } | |
314 | 314 | |||
315 | usbd_status | 315 | usbd_status | |
316 | usbd_reset_port(usbd_device_handle dev, int port, usb_port_status_t *ps) | 316 | usbd_reset_port(usbd_device_handle dev, int port, usb_port_status_t *ps) | |
317 | { | 317 | { | |
318 | usb_device_request_t req; | 318 | usb_device_request_t req; | |
319 | usbd_status err; | 319 | usbd_status err; | |
320 | int n; | 320 | int n; | |
321 | 321 | |||
322 | req.bmRequestType = UT_WRITE_CLASS_OTHER; | 322 | req.bmRequestType = UT_WRITE_CLASS_OTHER; | |
323 | req.bRequest = UR_SET_FEATURE; | 323 | req.bRequest = UR_SET_FEATURE; | |
324 | USETW(req.wValue, UHF_PORT_RESET); | 324 | USETW(req.wValue, UHF_PORT_RESET); | |
325 | USETW(req.wIndex, port); | 325 | USETW(req.wIndex, port); | |
326 | USETW(req.wLength, 0); | 326 | USETW(req.wLength, 0); | |
327 | err = usbd_do_request(dev, &req, 0); | 327 | err = usbd_do_request(dev, &req, 0); | |
328 | DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n", | 328 | DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n", | |
329 | port, usbd_errstr(err))); | 329 | port, usbd_errstr(err))); | |
330 | if (err) | 330 | if (err) | |
331 | return (err); | 331 | return (err); | |
332 | n = 10; | 332 | n = 10; | |
333 | do { | 333 | do { | |
334 | /* Wait for device to recover from reset. */ | 334 | /* Wait for device to recover from reset. */ | |
335 | usbd_delay_ms(dev, USB_PORT_RESET_DELAY); | 335 | usbd_delay_ms(dev, USB_PORT_RESET_DELAY); | |
336 | err = usbd_get_port_status(dev, port, ps); | 336 | err = usbd_get_port_status(dev, port, ps); | |
337 | if (err) { | 337 | if (err) { | |
338 | DPRINTF(("usbd_reset_port: get status failed %d\n", | 338 | DPRINTF(("usbd_reset_port: get status failed %d\n", | |
339 | err)); | 339 | err)); | |
340 | return (err); | 340 | return (err); | |
341 | } | 341 | } | |
342 | /* If the device disappeared, just give up. */ | 342 | /* If the device disappeared, just give up. */ | |
343 | if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) | 343 | if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) | |
344 | return (USBD_NORMAL_COMPLETION); | 344 | return (USBD_NORMAL_COMPLETION); | |
345 | } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0); | 345 | } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0); | |
346 | if (n == 0) | 346 | if (n == 0) | |
347 | return (USBD_TIMEOUT); | 347 | return (USBD_TIMEOUT); | |
348 | err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET); | 348 | err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET); | |
349 | #ifdef USB_DEBUG | 349 | #ifdef USB_DEBUG | |
350 | if (err) | 350 | if (err) | |
351 | DPRINTF(("usbd_reset_port: clear port feature failed %d\n", | 351 | DPRINTF(("usbd_reset_port: clear port feature failed %d\n", | |
352 | err)); | 352 | err)); | |
353 | #endif | 353 | #endif | |
354 | 354 | |||
355 | /* Wait for the device to recover from reset. */ | 355 | /* Wait for the device to recover from reset. */ | |
356 | usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY); | 356 | usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY); | |
357 | return (err); | 357 | return (err); | |
358 | } | 358 | } | |
359 | 359 | |||
360 | usb_interface_descriptor_t * | 360 | usb_interface_descriptor_t * | |
361 | usbd_find_idesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx) | 361 | usbd_find_idesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx) | |
362 | { | 362 | { | |
363 | char *p = (char *)cd; | 363 | char *p = (char *)cd; | |
364 | char *end = p + UGETW(cd->wTotalLength); | 364 | char *end = p + UGETW(cd->wTotalLength); | |
365 | usb_interface_descriptor_t *d; | 365 | usb_interface_descriptor_t *d; | |
366 | int curidx, lastidx, curaidx = 0; | 366 | int curidx, lastidx, curaidx = 0; | |
367 | 367 | |||
368 | for (curidx = lastidx = -1; p < end; ) { | 368 | for (curidx = lastidx = -1; p < end; ) { | |
369 | d = (usb_interface_descriptor_t *)p; | 369 | d = (usb_interface_descriptor_t *)p; | |
370 | DPRINTFN(4,("usbd_find_idesc: idx=%d(%d) altidx=%d(%d) len=%d " | 370 | DPRINTFN(4,("usbd_find_idesc: idx=%d(%d) altidx=%d(%d) len=%d " | |
371 | "type=%d\n", | 371 | "type=%d\n", | |
372 | ifaceidx, curidx, altidx, curaidx, | 372 | ifaceidx, curidx, altidx, curaidx, | |
373 | d->bLength, d->bDescriptorType)); | 373 | d->bLength, d->bDescriptorType)); | |
374 | if (d->bLength == 0) /* bad descriptor */ | 374 | if (d->bLength == 0) /* bad descriptor */ | |
375 | break; | 375 | break; | |
376 | p += d->bLength; | 376 | p += d->bLength; | |
377 | if (p <= end && d->bDescriptorType == UDESC_INTERFACE) { | 377 | if (p <= end && d->bDescriptorType == UDESC_INTERFACE) { | |
378 | if (d->bInterfaceNumber != lastidx) { | 378 | if (d->bInterfaceNumber != lastidx) { | |
379 | lastidx = d->bInterfaceNumber; | 379 | lastidx = d->bInterfaceNumber; | |
380 | curidx++; | 380 | curidx++; | |
381 | curaidx = 0; | 381 | curaidx = 0; | |
382 | } else | 382 | } else | |
383 | curaidx++; | 383 | curaidx++; | |
384 | if (ifaceidx == curidx && altidx == curaidx) | 384 | if (ifaceidx == curidx && altidx == curaidx) | |
385 | return (d); | 385 | return (d); | |
386 | } | 386 | } | |
387 | } | 387 | } | |
388 | return (NULL); | 388 | return (NULL); | |
389 | } | 389 | } | |
390 | 390 | |||
391 | usb_endpoint_descriptor_t * | 391 | usb_endpoint_descriptor_t * | |
392 | usbd_find_edesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx, | 392 | usbd_find_edesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx, | |
393 | int endptidx) | 393 | int endptidx) | |
394 | { | 394 | { | |
395 | char *p = (char *)cd; | 395 | char *p = (char *)cd; | |
396 | char *end = p + UGETW(cd->wTotalLength); | 396 | char *end = p + UGETW(cd->wTotalLength); | |
397 | usb_interface_descriptor_t *d; | 397 | usb_interface_descriptor_t *d; | |
398 | usb_endpoint_descriptor_t *e; | 398 | usb_endpoint_descriptor_t *e; | |
399 | int curidx; | 399 | int curidx; | |
400 | 400 | |||
401 | d = usbd_find_idesc(cd, ifaceidx, altidx); | 401 | d = usbd_find_idesc(cd, ifaceidx, altidx); | |
402 | if (d == NULL) | 402 | if (d == NULL) | |
403 | return (NULL); | 403 | return (NULL); | |
404 | if (endptidx >= d->bNumEndpoints) /* quick exit */ | 404 | if (endptidx >= d->bNumEndpoints) /* quick exit */ | |
405 | return (NULL); | 405 | return (NULL); | |
406 | 406 | |||
407 | curidx = -1; | 407 | curidx = -1; | |
408 | for (p = (char *)d + d->bLength; p < end; ) { | 408 | for (p = (char *)d + d->bLength; p < end; ) { | |
409 | e = (usb_endpoint_descriptor_t *)p; | 409 | e = (usb_endpoint_descriptor_t *)p; | |
410 | if (e->bLength == 0) /* bad descriptor */ | 410 | if (e->bLength == 0) /* bad descriptor */ | |
411 | break; | 411 | break; | |
412 | p += e->bLength; | 412 | p += e->bLength; | |
413 | if (p <= end && e->bDescriptorType == UDESC_INTERFACE) | 413 | if (p <= end && e->bDescriptorType == UDESC_INTERFACE) | |
414 | return (NULL); | 414 | return (NULL); | |
415 | if (p <= end && e->bDescriptorType == UDESC_ENDPOINT) { | 415 | if (p <= end && e->bDescriptorType == UDESC_ENDPOINT) { | |
416 | curidx++; | 416 | curidx++; | |
417 | if (curidx == endptidx) | 417 | if (curidx == endptidx) | |
418 | return (e); | 418 | return (e); | |
419 | } | 419 | } | |
420 | } | 420 | } | |
421 | return (NULL); | 421 | return (NULL); | |
422 | } | 422 | } | |
423 | 423 | |||
424 | usbd_status | 424 | usbd_status | |
425 | usbd_fill_iface_data(usbd_device_handle dev, int ifaceidx, int altidx) | 425 | usbd_fill_iface_data(usbd_device_handle dev, int ifaceidx, int altidx) | |
426 | { | 426 | { | |
427 | usbd_interface_handle ifc = &dev->ifaces[ifaceidx]; | 427 | usbd_interface_handle ifc = &dev->ifaces[ifaceidx]; | |
428 | usb_interface_descriptor_t *idesc; | 428 | usb_interface_descriptor_t *idesc; | |
429 | char *p, *end; | 429 | char *p, *end; | |
430 | int endpt, nendpt; | 430 | int endpt, nendpt; | |
431 | 431 | |||
432 | DPRINTFN(4,("usbd_fill_iface_data: ifaceidx=%d altidx=%d\n", | 432 | DPRINTFN(4,("usbd_fill_iface_data: ifaceidx=%d altidx=%d\n", | |
433 | ifaceidx, altidx)); | 433 | ifaceidx, altidx)); | |
434 | idesc = usbd_find_idesc(dev->cdesc, ifaceidx, altidx); | 434 | idesc = usbd_find_idesc(dev->cdesc, ifaceidx, altidx); | |
435 | if (idesc == NULL) | 435 | if (idesc == NULL) | |
436 | return (USBD_INVAL); | 436 | return (USBD_INVAL); | |
437 | ifc->device = dev; | 437 | ifc->device = dev; | |
438 | ifc->idesc = idesc; | 438 | ifc->idesc = idesc; | |
439 | ifc->index = ifaceidx; | 439 | ifc->index = ifaceidx; | |
440 | ifc->altindex = altidx; | 440 | ifc->altindex = altidx; | |
441 | nendpt = ifc->idesc->bNumEndpoints; | 441 | nendpt = ifc->idesc->bNumEndpoints; | |
442 | DPRINTFN(4,("usbd_fill_iface_data: found idesc nendpt=%d\n", nendpt)); | 442 | DPRINTFN(4,("usbd_fill_iface_data: found idesc nendpt=%d\n", nendpt)); | |
443 | if (nendpt != 0) { | 443 | if (nendpt != 0) { | |
444 | ifc->endpoints = malloc(nendpt * sizeof(struct usbd_endpoint), | 444 | ifc->endpoints = malloc(nendpt * sizeof(struct usbd_endpoint), | |
445 | M_USB, M_NOWAIT); | 445 | M_USB, M_NOWAIT); | |
446 | if (ifc->endpoints == NULL) | 446 | if (ifc->endpoints == NULL) | |
447 | return (USBD_NOMEM); | 447 | return (USBD_NOMEM); | |
448 | } else | 448 | } else | |
449 | ifc->endpoints = NULL; | 449 | ifc->endpoints = NULL; | |
450 | ifc->priv = NULL; | 450 | ifc->priv = NULL; | |
451 | p = (char *)ifc->idesc + ifc->idesc->bLength; | 451 | p = (char *)ifc->idesc + ifc->idesc->bLength; | |
452 | end = (char *)dev->cdesc + UGETW(dev->cdesc->wTotalLength); | 452 | end = (char *)dev->cdesc + UGETW(dev->cdesc->wTotalLength); | |
453 | #define ed ((usb_endpoint_descriptor_t *)p) | 453 | #define ed ((usb_endpoint_descriptor_t *)p) | |
454 | for (endpt = 0; endpt < nendpt; endpt++) { | 454 | for (endpt = 0; endpt < nendpt; endpt++) { | |
455 | DPRINTFN(10,("usbd_fill_iface_data: endpt=%d\n", endpt)); | 455 | DPRINTFN(10,("usbd_fill_iface_data: endpt=%d\n", endpt)); | |
456 | for (; p < end; p += ed->bLength) { | 456 | for (; p < end; p += ed->bLength) { | |
457 | DPRINTFN(10,("usbd_fill_iface_data: p=%p end=%p " | 457 | DPRINTFN(10,("usbd_fill_iface_data: p=%p end=%p " | |
458 | "len=%d type=%d\n", | 458 | "len=%d type=%d\n", | |
459 | p, end, ed->bLength, ed->bDescriptorType)); | 459 | p, end, ed->bLength, ed->bDescriptorType)); | |
460 | if (p + ed->bLength <= end && ed->bLength != 0 && | 460 | if (p + ed->bLength <= end && ed->bLength != 0 && | |
461 | ed->bDescriptorType == UDESC_ENDPOINT) | 461 | ed->bDescriptorType == UDESC_ENDPOINT) | |
462 | goto found; | 462 | goto found; | |
463 | if (ed->bLength == 0 || | 463 | if (ed->bLength == 0 || | |
464 | ed->bDescriptorType == UDESC_INTERFACE) | 464 | ed->bDescriptorType == UDESC_INTERFACE) | |
465 | break; | 465 | break; | |
466 | } | 466 | } | |
467 | /* passed end, or bad desc */ | 467 | /* passed end, or bad desc */ | |
468 | printf("usbd_fill_iface_data: bad descriptor(s): %s\n", | 468 | printf("usbd_fill_iface_data: bad descriptor(s): %s\n", | |
469 | ed->bLength == 0 ? "0 length" : | 469 | ed->bLength == 0 ? "0 length" : | |
470 | ed->bDescriptorType == UDESC_INTERFACE ? "iface desc": | 470 | ed->bDescriptorType == UDESC_INTERFACE ? "iface desc": | |
471 | "out of data"); | 471 | "out of data"); | |
472 | goto bad; | 472 | goto bad; | |
473 | found: | 473 | found: | |
474 | ifc->endpoints[endpt].edesc = ed; | 474 | ifc->endpoints[endpt].edesc = ed; | |
475 | if (dev->speed == USB_SPEED_HIGH) { | 475 | if (dev->speed == USB_SPEED_HIGH) { | |
476 | u_int mps; | 476 | u_int mps; | |
477 | /* Control and bulk endpoints have max packet limits. */ | 477 | /* Control and bulk endpoints have max packet limits. */ | |
478 | switch (UE_GET_XFERTYPE(ed->bmAttributes)) { | 478 | switch (UE_GET_XFERTYPE(ed->bmAttributes)) { | |
479 | case UE_CONTROL: | 479 | case UE_CONTROL: | |
480 | mps = USB_2_MAX_CTRL_PACKET; | 480 | mps = USB_2_MAX_CTRL_PACKET; | |
481 | goto check; | 481 | goto check; | |
482 | case UE_BULK: | 482 | case UE_BULK: | |
483 | mps = USB_2_MAX_BULK_PACKET; | 483 | mps = USB_2_MAX_BULK_PACKET; | |
484 | check: | 484 | check: | |
485 | if (UGETW(ed->wMaxPacketSize) != mps) { | 485 | if (UGETW(ed->wMaxPacketSize) != mps) { | |
486 | USETW(ed->wMaxPacketSize, mps); | 486 | USETW(ed->wMaxPacketSize, mps); | |
487 | #ifdef DIAGNOSTIC | 487 | #ifdef DIAGNOSTIC | |
488 | printf("usbd_fill_iface_data: bad max " | 488 | printf("usbd_fill_iface_data: bad max " | |
489 | "packet size\n"); | 489 | "packet size\n"); | |
490 | #endif | 490 | #endif | |
491 | } | 491 | } | |
492 | break; | 492 | break; | |
493 | default: | 493 | default: | |
494 | break; | 494 | break; | |
495 | } | 495 | } | |
496 | } | 496 | } | |
497 | ifc->endpoints[endpt].refcnt = 0; | 497 | ifc->endpoints[endpt].refcnt = 0; | |
498 | ifc->endpoints[endpt].datatoggle = 0; | 498 | ifc->endpoints[endpt].datatoggle = 0; | |
499 | p += ed->bLength; | 499 | p += ed->bLength; | |
500 | } | 500 | } | |
501 | #undef ed | 501 | #undef ed | |
502 | LIST_INIT(&ifc->pipes); | 502 | LIST_INIT(&ifc->pipes); | |
503 | return (USBD_NORMAL_COMPLETION); | 503 | return (USBD_NORMAL_COMPLETION); | |
504 | 504 | |||
505 | bad: | 505 | bad: | |
506 | if (ifc->endpoints != NULL) { | 506 | if (ifc->endpoints != NULL) { | |
507 | free(ifc->endpoints, M_USB); | 507 | free(ifc->endpoints, M_USB); | |
508 | ifc->endpoints = NULL; | 508 | ifc->endpoints = NULL; | |
509 | } | 509 | } | |
510 | return (USBD_INVAL); | 510 | return (USBD_INVAL); | |
511 | } | 511 | } | |
512 | 512 | |||
513 | void | 513 | void | |
514 | usbd_free_iface_data(usbd_device_handle dev, int ifcno) | 514 | usbd_free_iface_data(usbd_device_handle dev, int ifcno) | |
515 | { | 515 | { | |
516 | usbd_interface_handle ifc = &dev->ifaces[ifcno]; | 516 | usbd_interface_handle ifc = &dev->ifaces[ifcno]; | |
517 | if (ifc->endpoints) | 517 | if (ifc->endpoints) | |
518 | free(ifc->endpoints, M_USB); | 518 | free(ifc->endpoints, M_USB); | |
519 | } | 519 | } | |
520 | 520 | |||
521 | Static usbd_status | 521 | Static usbd_status | |
522 | usbd_set_config(usbd_device_handle dev, int conf) | 522 | usbd_set_config(usbd_device_handle dev, int conf) | |
523 | { | 523 | { | |
524 | usb_device_request_t req; | 524 | usb_device_request_t req; | |
525 | 525 | |||
526 | req.bmRequestType = UT_WRITE_DEVICE; | 526 | req.bmRequestType = UT_WRITE_DEVICE; | |
527 | req.bRequest = UR_SET_CONFIG; | 527 | req.bRequest = UR_SET_CONFIG; | |
528 | USETW(req.wValue, conf); | 528 | USETW(req.wValue, conf); | |
529 | USETW(req.wIndex, 0); | 529 | USETW(req.wIndex, 0); | |
530 | USETW(req.wLength, 0); | 530 | USETW(req.wLength, 0); | |
531 | return (usbd_do_request(dev, &req, 0)); | 531 | return (usbd_do_request(dev, &req, 0)); | |
532 | } | 532 | } | |
533 | 533 | |||
534 | usbd_status | 534 | usbd_status | |
535 | usbd_set_config_no(usbd_device_handle dev, int no, int msg) | 535 | usbd_set_config_no(usbd_device_handle dev, int no, int msg) | |
536 | { | 536 | { | |
537 | int index; | 537 | int index; | |
538 | usb_config_descriptor_t cd; | 538 | usb_config_descriptor_t cd; | |
539 | usbd_status err; | 539 | usbd_status err; | |
540 | 540 | |||
541 | if (no == USB_UNCONFIG_NO) | 541 | if (no == USB_UNCONFIG_NO) | |
542 | return (usbd_set_config_index(dev, USB_UNCONFIG_INDEX, msg)); | 542 | return (usbd_set_config_index(dev, USB_UNCONFIG_INDEX, msg)); | |
543 | 543 | |||
544 | DPRINTFN(5,("usbd_set_config_no: %d\n", no)); | 544 | DPRINTFN(5,("usbd_set_config_no: %d\n", no)); | |
545 | /* Figure out what config index to use. */ | 545 | /* Figure out what config index to use. */ | |
546 | for (index = 0; index < dev->ddesc.bNumConfigurations; index++) { | 546 | for (index = 0; index < dev->ddesc.bNumConfigurations; index++) { | |
547 | err = usbd_get_config_desc(dev, index, &cd); | 547 | err = usbd_get_config_desc(dev, index, &cd); | |
548 | if (err) | 548 | if (err) | |
549 | return (err); | 549 | return (err); | |
550 | if (cd.bConfigurationValue == no) | 550 | if (cd.bConfigurationValue == no) | |
551 | return (usbd_set_config_index(dev, index, msg)); | 551 | return (usbd_set_config_index(dev, index, msg)); | |
552 | } | 552 | } | |
553 | return (USBD_INVAL); | 553 | return (USBD_INVAL); | |
554 | } | 554 | } | |
555 | 555 | |||
556 | usbd_status | 556 | usbd_status | |
557 | usbd_set_config_index(usbd_device_handle dev, int index, int msg) | 557 | usbd_set_config_index(usbd_device_handle dev, int index, int msg) | |
558 | { | 558 | { | |
559 | usb_config_descriptor_t cd, *cdp; | 559 | usb_config_descriptor_t cd, *cdp; | |
560 | usbd_status err; | 560 | usbd_status err; | |
561 | int i, ifcidx, nifc, len, selfpowered, power; | 561 | int i, ifcidx, nifc, len, selfpowered, power; | |
562 | 562 | |||
563 | DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index)); | 563 | DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index)); | |
564 | 564 | |||
565 | if (index >= dev->ddesc.bNumConfigurations && | 565 | if (index >= dev->ddesc.bNumConfigurations && | |
566 | index != USB_UNCONFIG_INDEX) { | 566 | index != USB_UNCONFIG_INDEX) { | |
567 | /* panic? */ | 567 | /* panic? */ | |
568 | printf("usbd_set_config_index: illegal index\n"); | 568 | printf("usbd_set_config_index: illegal index\n"); | |
569 | return (USBD_INVAL); | 569 | return (USBD_INVAL); | |
570 | } | 570 | } | |
571 | 571 | |||
572 | /* XXX check that all interfaces are idle */ | 572 | /* XXX check that all interfaces are idle */ | |
573 | if (dev->config != USB_UNCONFIG_NO) { | 573 | if (dev->config != USB_UNCONFIG_NO) { | |
574 | DPRINTF(("usbd_set_config_index: free old config\n")); | 574 | DPRINTF(("usbd_set_config_index: free old config\n")); | |
575 | /* Free all configuration data structures. */ | 575 | /* Free all configuration data structures. */ | |
576 | nifc = dev->cdesc->bNumInterface; | 576 | nifc = dev->cdesc->bNumInterface; | |
577 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) | 577 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) | |
578 | usbd_free_iface_data(dev, ifcidx); | 578 | usbd_free_iface_data(dev, ifcidx); | |
579 | free(dev->ifaces, M_USB); | 579 | free(dev->ifaces, M_USB); | |
580 | free(dev->cdesc, M_USB); | 580 | free(dev->cdesc, M_USB); | |
581 | dev->ifaces = NULL; | 581 | dev->ifaces = NULL; | |
582 | dev->cdesc = NULL; | 582 | dev->cdesc = NULL; | |
583 | dev->config = USB_UNCONFIG_NO; | 583 | dev->config = USB_UNCONFIG_NO; | |
584 | } | 584 | } | |
585 | 585 | |||
586 | if (index == USB_UNCONFIG_INDEX) { | 586 | if (index == USB_UNCONFIG_INDEX) { | |
587 | /* We are unconfiguring the device, so leave unallocated. */ | 587 | /* We are unconfiguring the device, so leave unallocated. */ | |
588 | DPRINTF(("usbd_set_config_index: set config 0\n")); | 588 | DPRINTF(("usbd_set_config_index: set config 0\n")); | |
589 | err = usbd_set_config(dev, USB_UNCONFIG_NO); | 589 | err = usbd_set_config(dev, USB_UNCONFIG_NO); | |
590 | if (err) { | 590 | if (err) { | |
591 | DPRINTF(("usbd_set_config_index: setting config=0 " | 591 | DPRINTF(("usbd_set_config_index: setting config=0 " | |
592 | "failed, error=%s\n", usbd_errstr(err))); | 592 | "failed, error=%s\n", usbd_errstr(err))); | |
593 | } | 593 | } | |
594 | return (err); | 594 | return (err); | |
595 | } | 595 | } | |
596 | 596 | |||
597 | /* Get the short descriptor. */ | 597 | /* Get the short descriptor. */ | |
598 | err = usbd_get_config_desc(dev, index, &cd); | 598 | err = usbd_get_config_desc(dev, index, &cd); | |
599 | if (err) { | 599 | if (err) { | |
600 | DPRINTF(("usbd_set_config_index: get_config_desc=%d\n", err)); | 600 | DPRINTF(("usbd_set_config_index: get_config_desc=%d\n", err)); | |
601 | return (err); | 601 | return (err); | |
602 | } | 602 | } | |
603 | len = UGETW(cd.wTotalLength); | 603 | len = UGETW(cd.wTotalLength); | |
604 | cdp = malloc(len, M_USB, M_NOWAIT); | 604 | cdp = malloc(len, M_USB, M_NOWAIT); | |
605 | if (cdp == NULL) | 605 | if (cdp == NULL) | |
606 | return (USBD_NOMEM); | 606 | return (USBD_NOMEM); | |
607 | 607 | |||
608 | /* Get the full descriptor. Try a few times for slow devices. */ | 608 | /* Get the full descriptor. Try a few times for slow devices. */ | |
609 | for (i = 0; i < 3; i++) { | 609 | for (i = 0; i < 3; i++) { | |
610 | err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp); | 610 | err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp); | |
611 | if (!err) | 611 | if (!err) | |
612 | break; | 612 | break; | |
613 | usbd_delay_ms(dev, 200); | 613 | usbd_delay_ms(dev, 200); | |
614 | } | 614 | } | |
615 | if (err) { | 615 | if (err) { | |
616 | DPRINTF(("usbd_set_config_index: get_desc=%d\n", err)); | 616 | DPRINTF(("usbd_set_config_index: get_desc=%d\n", err)); | |
617 | goto bad; | 617 | goto bad; | |
618 | } | 618 | } | |
619 | if (cdp->bDescriptorType != UDESC_CONFIG) { | 619 | if (cdp->bDescriptorType != UDESC_CONFIG) { | |
620 | DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n", | 620 | DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n", | |
621 | cdp->bDescriptorType)); | 621 | cdp->bDescriptorType)); | |
622 | err = USBD_INVAL; | 622 | err = USBD_INVAL; | |
623 | goto bad; | 623 | goto bad; | |
624 | } | 624 | } | |
625 | 625 | |||
626 | /* | 626 | /* | |
627 | * Figure out if the device is self or bus powered. | 627 | * Figure out if the device is self or bus powered. | |
628 | */ | 628 | */ | |
629 | #if 0 /* XXX various devices don't report the power state correctly */ | 629 | #if 0 /* XXX various devices don't report the power state correctly */ | |
630 | selfpowered = 0; | 630 | selfpowered = 0; | |
631 | err = usbd_get_device_status(dev, &ds); | 631 | err = usbd_get_device_status(dev, &ds); | |
632 | if (!err && (UGETW(ds.wStatus) & UDS_SELF_POWERED)) | 632 | if (!err && (UGETW(ds.wStatus) & UDS_SELF_POWERED)) | |
633 | selfpowered = 1; | 633 | selfpowered = 1; | |
634 | #endif | 634 | #endif | |
635 | /* | 635 | /* | |
636 | * Use the power state in the configuration we are going | 636 | * Use the power state in the configuration we are going | |
637 | * to set. This doesn't necessarily reflect the actual | 637 | * to set. This doesn't necessarily reflect the actual | |
638 | * power state of the device; the driver can control this | 638 | * power state of the device; the driver can control this | |
639 | * by choosing the appropriate configuration. | 639 | * by choosing the appropriate configuration. | |
640 | */ | 640 | */ | |
641 | selfpowered = !!(cdp->bmAttributes & UC_SELF_POWERED); | 641 | selfpowered = !!(cdp->bmAttributes & UC_SELF_POWERED); | |
642 | 642 | |||
643 | DPRINTF(("usbd_set_config_index: (addr %d) cno=%d attr=0x%02x, " | 643 | DPRINTF(("usbd_set_config_index: (addr %d) cno=%d attr=0x%02x, " | |
644 | "selfpowered=%d, power=%d\n", | 644 | "selfpowered=%d, power=%d\n", | |
645 | cdp->bConfigurationValue, dev->address, cdp->bmAttributes, | 645 | cdp->bConfigurationValue, dev->address, cdp->bmAttributes, | |
646 | selfpowered, cdp->bMaxPower * 2)); | 646 | selfpowered, cdp->bMaxPower * 2)); | |
647 | 647 | |||
648 | /* Check if we have enough power. */ | 648 | /* Check if we have enough power. */ | |
649 | #if 0 /* this is a no-op, see above */ | 649 | #if 0 /* this is a no-op, see above */ | |
650 | if ((cdp->bmAttributes & UC_SELF_POWERED) && !selfpowered) { | 650 | if ((cdp->bmAttributes & UC_SELF_POWERED) && !selfpowered) { | |
651 | if (msg) | 651 | if (msg) | |
652 | printf("%s: device addr %d (config %d): " | 652 | printf("%s: device addr %d (config %d): " | |
653 | "can't set self powered configuration\n", | 653 | "can't set self powered configuration\n", | |
654 | device_xname(dev->bus->bdev), dev->address, | 654 | device_xname(dev->bus->bdev), dev->address, | |
655 | cdp->bConfigurationValue); | 655 | cdp->bConfigurationValue); | |
656 | err = USBD_NO_POWER; | 656 | err = USBD_NO_POWER; | |
657 | goto bad; | 657 | goto bad; | |
658 | } | 658 | } | |
659 | #endif | 659 | #endif | |
660 | #ifdef USB_DEBUG | 660 | #ifdef USB_DEBUG | |
661 | if (dev->powersrc == NULL) { | 661 | if (dev->powersrc == NULL) { | |
662 | DPRINTF(("usbd_set_config_index: No power source?\n")); | 662 | DPRINTF(("usbd_set_config_index: No power source?\n")); | |
663 | err = USBD_IOERROR; | 663 | err = USBD_IOERROR; | |
664 | goto bad; | 664 | goto bad; | |
665 | } | 665 | } | |
666 | #endif | 666 | #endif | |
667 | power = cdp->bMaxPower * 2; | 667 | power = cdp->bMaxPower * 2; | |
668 | if (power > dev->powersrc->power) { | 668 | if (power > dev->powersrc->power) { | |
669 | DPRINTF(("power exceeded %d %d\n", power,dev->powersrc->power)); | 669 | DPRINTF(("power exceeded %d %d\n", power,dev->powersrc->power)); | |
670 | /* XXX print nicer message. */ | 670 | /* XXX print nicer message. */ | |
671 | if (msg) | 671 | if (msg) | |
672 | printf("%s: device addr %d (config %d) exceeds power " | 672 | printf("%s: device addr %d (config %d) exceeds power " | |
673 | "budget, %d mA > %d mA\n", | 673 | "budget, %d mA > %d mA\n", | |
674 | device_xname(dev->bus->usbctl), dev->address, | 674 | device_xname(dev->bus->usbctl), dev->address, | |
675 | cdp->bConfigurationValue, | 675 | cdp->bConfigurationValue, | |
676 | power, dev->powersrc->power); | 676 | power, dev->powersrc->power); | |
677 | err = USBD_NO_POWER; | 677 | err = USBD_NO_POWER; | |
678 | goto bad; | 678 | goto bad; | |
679 | } | 679 | } | |
680 | dev->power = power; | 680 | dev->power = power; | |
681 | dev->self_powered = selfpowered; | 681 | dev->self_powered = selfpowered; | |
682 | 682 | |||
683 | /* Set the actual configuration value. */ | 683 | /* Set the actual configuration value. */ | |
684 | DPRINTF(("usbd_set_config_index: set config %d\n", | 684 | DPRINTF(("usbd_set_config_index: set config %d\n", | |
685 | cdp->bConfigurationValue)); | 685 | cdp->bConfigurationValue)); | |
686 | err = usbd_set_config(dev, cdp->bConfigurationValue); | 686 | err = usbd_set_config(dev, cdp->bConfigurationValue); | |
687 | if (err) { | 687 | if (err) { | |
688 | DPRINTF(("usbd_set_config_index: setting config=%d failed, " | 688 | DPRINTF(("usbd_set_config_index: setting config=%d failed, " | |
689 | "error=%s\n", | 689 | "error=%s\n", | |
690 | cdp->bConfigurationValue, usbd_errstr(err))); | 690 | cdp->bConfigurationValue, usbd_errstr(err))); | |
691 | goto bad; | 691 | goto bad; | |
692 | } | 692 | } | |
693 | 693 | |||
694 | /* Allocate and fill interface data. */ | 694 | /* Allocate and fill interface data. */ | |
695 | nifc = cdp->bNumInterface; | 695 | nifc = cdp->bNumInterface; | |
696 | dev->ifaces = malloc(nifc * sizeof(struct usbd_interface), | 696 | dev->ifaces = malloc(nifc * sizeof(struct usbd_interface), | |
697 | M_USB, M_NOWAIT); | 697 | M_USB, M_NOWAIT); | |
698 | if (dev->ifaces == NULL) { | 698 | if (dev->ifaces == NULL) { | |
699 | err = USBD_NOMEM; | 699 | err = USBD_NOMEM; | |
700 | goto bad; | 700 | goto bad; | |
701 | } | 701 | } | |
702 | DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp)); | 702 | DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp)); | |
703 | dev->cdesc = cdp; | 703 | dev->cdesc = cdp; | |
704 | dev->config = cdp->bConfigurationValue; | 704 | dev->config = cdp->bConfigurationValue; | |
705 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) { | 705 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) { | |
706 | err = usbd_fill_iface_data(dev, ifcidx, 0); | 706 | err = usbd_fill_iface_data(dev, ifcidx, 0); | |
707 | if (err) { | 707 | if (err) { | |
708 | while (--ifcidx >= 0) | 708 | while (--ifcidx >= 0) | |
709 | usbd_free_iface_data(dev, ifcidx); | 709 | usbd_free_iface_data(dev, ifcidx); | |
710 | goto bad; | 710 | goto bad; | |
711 | } | 711 | } | |
712 | } | 712 | } | |
713 | 713 | |||
714 | return (USBD_NORMAL_COMPLETION); | 714 | return (USBD_NORMAL_COMPLETION); | |
715 | 715 | |||
716 | bad: | 716 | bad: | |
717 | free(cdp, M_USB); | 717 | free(cdp, M_USB); | |
718 | return (err); | 718 | return (err); | |
719 | } | 719 | } | |
720 | 720 | |||
721 | /* XXX add function for alternate settings */ | 721 | /* XXX add function for alternate settings */ | |
722 | 722 | |||
723 | usbd_status | 723 | usbd_status | |
724 | usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface, | 724 | usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface, | |
725 | struct usbd_endpoint *ep, int ival, usbd_pipe_handle *pipe) | 725 | struct usbd_endpoint *ep, int ival, usbd_pipe_handle *pipe) | |
726 | { | 726 | { | |
727 | usbd_pipe_handle p; | 727 | usbd_pipe_handle p; | |
728 | usbd_status err; | 728 | usbd_status err; | |
729 | 729 | |||
730 | DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n", | 730 | DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n", | |
731 | dev, iface, ep, pipe)); | 731 | dev, iface, ep, pipe)); | |
732 | p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT); | 732 | p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT); | |
733 | if (p == NULL) | 733 | if (p == NULL) | |
734 | return (USBD_NOMEM); | 734 | return (USBD_NOMEM); | |
735 | p->device = dev; | 735 | p->device = dev; | |
736 | p->iface = iface; | 736 | p->iface = iface; | |
737 | p->endpoint = ep; | 737 | p->endpoint = ep; | |
738 | ep->refcnt++; | 738 | ep->refcnt++; | |
739 | p->refcnt = 1; | 739 | p->refcnt = 1; | |
740 | p->intrxfer = 0; | 740 | p->intrxfer = 0; | |
741 | p->running = 0; | 741 | p->running = 0; | |
742 | p->aborting = 0; | 742 | p->aborting = 0; | |
743 | p->repeat = 0; | 743 | p->repeat = 0; | |
744 | p->interval = ival; | 744 | p->interval = ival; | |
745 | SIMPLEQ_INIT(&p->queue); | 745 | SIMPLEQ_INIT(&p->queue); | |
746 | err = dev->bus->methods->open_pipe(p); | 746 | err = dev->bus->methods->open_pipe(p); | |
747 | if (err) { | 747 | if (err) { | |
748 | DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error=" | 748 | DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error=" | |
749 | "%s\n", | 749 | "%s\n", | |
750 | ep->edesc->bEndpointAddress, usbd_errstr(err))); | 750 | ep->edesc->bEndpointAddress, usbd_errstr(err))); | |
751 | free(p, M_USB); | 751 | free(p, M_USB); | |
752 | return (err); | 752 | return (err); | |
753 | } | 753 | } | |
754 | if (dev->bus->methods->get_locks) { | |||
755 | dev->bus->methods->get_locks(dev->bus, &p->intr_lock, &p->lock); | |||
756 | } else { | |||
757 | p->intr_lock = p->lock = NULL; | |||
758 | } | |||
759 | *pipe = p; | 754 | *pipe = p; | |
760 | return (USBD_NORMAL_COMPLETION); | 755 | return (USBD_NORMAL_COMPLETION); | |
761 | } | 756 | } | |
762 | 757 | |||
763 | /* Abort the device control pipe. */ | 758 | /* Abort the device control pipe. */ | |
764 | void | 759 | void | |
765 | usbd_kill_pipe(usbd_pipe_handle pipe) | 760 | usbd_kill_pipe(usbd_pipe_handle pipe) | |
766 | { | 761 | { | |
767 | usbd_abort_pipe(pipe); | 762 | usbd_abort_pipe(pipe); | |
768 | pipe->methods->close(pipe); | 763 | pipe->methods->close(pipe); | |
769 | pipe->endpoint->refcnt--; | 764 | pipe->endpoint->refcnt--; | |
770 | free(pipe, M_USB); | 765 | free(pipe, M_USB); | |
771 | } | 766 | } | |
772 | 767 | |||
773 | int | 768 | int | |
774 | usbd_getnewaddr(usbd_bus_handle bus) | 769 | usbd_getnewaddr(usbd_bus_handle bus) | |
775 | { | 770 | { | |
776 | int addr; | 771 | int addr; | |
777 | 772 | |||
778 | for (addr = 1; addr < USB_MAX_DEVICES; addr++) | 773 | for (addr = 1; addr < USB_MAX_DEVICES; addr++) | |
779 | if (bus->devices[addr] == 0) | 774 | if (bus->devices[addr] == 0) | |
780 | return (addr); | 775 | return (addr); | |
781 | return (-1); | 776 | return (-1); | |
782 | } | 777 | } | |
783 | 778 | |||
784 | usbd_status | 779 | usbd_status | |
785 | usbd_attach_roothub(device_t parent, usbd_device_handle dev) | 780 | usbd_attach_roothub(device_t parent, usbd_device_handle dev) | |
786 | { | 781 | { | |
787 | struct usb_attach_arg uaa; | 782 | struct usb_attach_arg uaa; | |
788 | usb_device_descriptor_t *dd = &dev->ddesc; | 783 | usb_device_descriptor_t *dd = &dev->ddesc; | |
789 | device_t dv; | 784 | device_t dv; | |
790 | 785 | |||
791 | uaa.device = dev; | 786 | uaa.device = dev; | |
792 | uaa.usegeneric = 0; | 787 | uaa.usegeneric = 0; | |
793 | uaa.port = 0; | 788 | uaa.port = 0; | |
794 | uaa.vendor = UGETW(dd->idVendor); | 789 | uaa.vendor = UGETW(dd->idVendor); | |
795 | uaa.product = UGETW(dd->idProduct); | 790 | uaa.product = UGETW(dd->idProduct); | |
796 | uaa.release = UGETW(dd->bcdDevice); | 791 | uaa.release = UGETW(dd->bcdDevice); | |
797 | uaa.class = dd->bDeviceClass; | 792 | uaa.class = dd->bDeviceClass; | |
798 | uaa.subclass = dd->bDeviceSubClass; | 793 | uaa.subclass = dd->bDeviceSubClass; | |
799 | uaa.proto = dd->bDeviceProtocol; | 794 | uaa.proto = dd->bDeviceProtocol; | |
800 | 795 | |||
801 | dv = config_found_ia(parent, "usbroothubif", &uaa, 0); | 796 | dv = config_found_ia(parent, "usbroothubif", &uaa, 0); | |
802 | if (dv) { | 797 | if (dv) { | |
803 | dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT); | 798 | dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT); | |
804 | if (dev->subdevs == NULL) | 799 | if (dev->subdevs == NULL) | |
805 | return (USBD_NOMEM); | 800 | return (USBD_NOMEM); | |
806 | dev->subdevs[0] = dv; | 801 | dev->subdevs[0] = dv; | |
807 | dev->subdevlen = 1; | 802 | dev->subdevlen = 1; | |
808 | } | 803 | } | |
809 | return (USBD_NORMAL_COMPLETION); | 804 | return (USBD_NORMAL_COMPLETION); | |
810 | } | 805 | } | |
811 | 806 | |||
812 | static usbd_status | 807 | static usbd_status | |
813 | usbd_attachwholedevice(device_t parent, usbd_device_handle dev, int port, | 808 | usbd_attachwholedevice(device_t parent, usbd_device_handle dev, int port, | |
814 | int usegeneric) | 809 | int usegeneric) | |
815 | { | 810 | { | |
816 | struct usb_attach_arg uaa; | 811 | struct usb_attach_arg uaa; | |
817 | usb_device_descriptor_t *dd = &dev->ddesc; | 812 | usb_device_descriptor_t *dd = &dev->ddesc; | |
818 | device_t dv; | 813 | device_t dv; | |
819 | int dlocs[USBDEVIFCF_NLOCS]; | 814 | int dlocs[USBDEVIFCF_NLOCS]; | |
820 | 815 | |||
821 | uaa.device = dev; | 816 | uaa.device = dev; | |
822 | uaa.usegeneric = usegeneric; | 817 | uaa.usegeneric = usegeneric; | |
823 | uaa.port = port; | 818 | uaa.port = port; | |
824 | uaa.vendor = UGETW(dd->idVendor); | 819 | uaa.vendor = UGETW(dd->idVendor); | |
825 | uaa.product = UGETW(dd->idProduct); | 820 | uaa.product = UGETW(dd->idProduct); | |
826 | uaa.release = UGETW(dd->bcdDevice); | 821 | uaa.release = UGETW(dd->bcdDevice); | |
827 | uaa.class = dd->bDeviceClass; | 822 | uaa.class = dd->bDeviceClass; | |
828 | uaa.subclass = dd->bDeviceSubClass; | 823 | uaa.subclass = dd->bDeviceSubClass; | |
829 | uaa.proto = dd->bDeviceProtocol; | 824 | uaa.proto = dd->bDeviceProtocol; | |
830 | 825 | |||
831 | dlocs[USBDEVIFCF_PORT] = uaa.port; | 826 | dlocs[USBDEVIFCF_PORT] = uaa.port; | |
832 | dlocs[USBDEVIFCF_VENDOR] = uaa.vendor; | 827 | dlocs[USBDEVIFCF_VENDOR] = uaa.vendor; | |
833 | dlocs[USBDEVIFCF_PRODUCT] = uaa.product; | 828 | dlocs[USBDEVIFCF_PRODUCT] = uaa.product; | |
834 | dlocs[USBDEVIFCF_RELEASE] = uaa.release; | 829 | dlocs[USBDEVIFCF_RELEASE] = uaa.release; | |
835 | /* the rest is historical ballast */ | 830 | /* the rest is historical ballast */ | |
836 | dlocs[USBDEVIFCF_CONFIGURATION] = -1; | 831 | dlocs[USBDEVIFCF_CONFIGURATION] = -1; | |
837 | dlocs[USBDEVIFCF_INTERFACE] = -1; | 832 | dlocs[USBDEVIFCF_INTERFACE] = -1; | |
838 | 833 | |||
839 | dv = config_found_sm_loc(parent, "usbdevif", dlocs, &uaa, usbd_print, | 834 | dv = config_found_sm_loc(parent, "usbdevif", dlocs, &uaa, usbd_print, | |
840 | config_stdsubmatch); | 835 | config_stdsubmatch); | |
841 | if (dv) { | 836 | if (dv) { | |
842 | dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT); | 837 | dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT); | |
843 | if (dev->subdevs == NULL) | 838 | if (dev->subdevs == NULL) | |
844 | return (USBD_NOMEM); | 839 | return (USBD_NOMEM); | |
845 | dev->subdevs[0] = dv; | 840 | dev->subdevs[0] = dv; | |
846 | dev->subdevlen = 1; | 841 | dev->subdevlen = 1; | |
847 | dev->nifaces_claimed = 1; /* XXX */ | 842 | dev->nifaces_claimed = 1; /* XXX */ | |
848 | } | 843 | } | |
849 | return (USBD_NORMAL_COMPLETION); | 844 | return (USBD_NORMAL_COMPLETION); | |
850 | } | 845 | } | |
851 | 846 | |||
852 | static usbd_status | 847 | static usbd_status | |
853 | usbd_attachinterfaces(device_t parent, usbd_device_handle dev, | 848 | usbd_attachinterfaces(device_t parent, usbd_device_handle dev, | |
854 | int port, const int *locators) | 849 | int port, const int *locators) | |
855 | { | 850 | { | |
856 | struct usbif_attach_arg uiaa; | 851 | struct usbif_attach_arg uiaa; | |
857 | int ilocs[USBIFIFCF_NLOCS]; | 852 | int ilocs[USBIFIFCF_NLOCS]; | |
858 | usb_device_descriptor_t *dd = &dev->ddesc; | 853 | usb_device_descriptor_t *dd = &dev->ddesc; | |
859 | int nifaces; | 854 | int nifaces; | |
860 | usbd_interface_handle *ifaces; | 855 | usbd_interface_handle *ifaces; | |
861 | int i, j, loc; | 856 | int i, j, loc; | |
862 | device_t dv; | 857 | device_t dv; | |
863 | 858 | |||
864 | nifaces = dev->cdesc->bNumInterface; | 859 | nifaces = dev->cdesc->bNumInterface; | |
865 | ifaces = malloc(nifaces * sizeof(*ifaces), M_USB, M_NOWAIT|M_ZERO); | 860 | ifaces = malloc(nifaces * sizeof(*ifaces), M_USB, M_NOWAIT|M_ZERO); | |
866 | if (!ifaces) | 861 | if (!ifaces) | |
867 | return (USBD_NOMEM); | 862 | return (USBD_NOMEM); | |
868 | for (i = 0; i < nifaces; i++) | 863 | for (i = 0; i < nifaces; i++) | |
869 | if (!dev->subdevs[i]) | 864 | if (!dev->subdevs[i]) | |
870 | ifaces[i] = &dev->ifaces[i]; | 865 | ifaces[i] = &dev->ifaces[i]; | |
871 | 866 | |||
872 | uiaa.device = dev; | 867 | uiaa.device = dev; | |
873 | uiaa.port = port; | 868 | uiaa.port = port; | |
874 | uiaa.vendor = UGETW(dd->idVendor); | 869 | uiaa.vendor = UGETW(dd->idVendor); | |
875 | uiaa.product = UGETW(dd->idProduct); | 870 | uiaa.product = UGETW(dd->idProduct); | |
876 | uiaa.release = UGETW(dd->bcdDevice); | 871 | uiaa.release = UGETW(dd->bcdDevice); | |
877 | uiaa.configno = dev->cdesc->bConfigurationValue; | 872 | uiaa.configno = dev->cdesc->bConfigurationValue; | |
878 | uiaa.ifaces = ifaces; | 873 | uiaa.ifaces = ifaces; | |
879 | uiaa.nifaces = nifaces; | 874 | uiaa.nifaces = nifaces; | |
880 | ilocs[USBIFIFCF_PORT] = uiaa.port; | 875 | ilocs[USBIFIFCF_PORT] = uiaa.port; | |
881 | ilocs[USBIFIFCF_VENDOR] = uiaa.vendor; | 876 | ilocs[USBIFIFCF_VENDOR] = uiaa.vendor; | |
882 | ilocs[USBIFIFCF_PRODUCT] = uiaa.product; | 877 | ilocs[USBIFIFCF_PRODUCT] = uiaa.product; | |
883 | ilocs[USBIFIFCF_RELEASE] = uiaa.release; | 878 | ilocs[USBIFIFCF_RELEASE] = uiaa.release; | |
884 | ilocs[USBIFIFCF_CONFIGURATION] = uiaa.configno; | 879 | ilocs[USBIFIFCF_CONFIGURATION] = uiaa.configno; | |
885 | 880 | |||
886 | for (i = 0; i < nifaces; i++) { | 881 | for (i = 0; i < nifaces; i++) { | |
887 | if (!ifaces[i]) | 882 | if (!ifaces[i]) | |
888 | continue; /* interface already claimed */ | 883 | continue; /* interface already claimed */ | |
889 | uiaa.iface = ifaces[i]; | 884 | uiaa.iface = ifaces[i]; | |
890 | uiaa.class = ifaces[i]->idesc->bInterfaceClass; | 885 | uiaa.class = ifaces[i]->idesc->bInterfaceClass; | |
891 | uiaa.subclass = ifaces[i]->idesc->bInterfaceSubClass; | 886 | uiaa.subclass = ifaces[i]->idesc->bInterfaceSubClass; | |
892 | uiaa.proto = ifaces[i]->idesc->bInterfaceProtocol; | 887 | uiaa.proto = ifaces[i]->idesc->bInterfaceProtocol; | |
893 | uiaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; | 888 | uiaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; | |
894 | ilocs[USBIFIFCF_INTERFACE] = uiaa.ifaceno; | 889 | ilocs[USBIFIFCF_INTERFACE] = uiaa.ifaceno; | |
895 | if (locators != NULL) { | 890 | if (locators != NULL) { | |
896 | loc = locators[USBIFIFCF_CONFIGURATION]; | 891 | loc = locators[USBIFIFCF_CONFIGURATION]; | |
897 | if (loc != USBIFIFCF_CONFIGURATION_DEFAULT && | 892 | if (loc != USBIFIFCF_CONFIGURATION_DEFAULT && | |
898 | loc != uiaa.configno) | 893 | loc != uiaa.configno) | |
899 | continue; | 894 | continue; | |
900 | loc = locators[USBIFIFCF_INTERFACE]; | 895 | loc = locators[USBIFIFCF_INTERFACE]; | |
901 | if (loc != USBIFIFCF_INTERFACE && loc != uiaa.ifaceno) | 896 | if (loc != USBIFIFCF_INTERFACE && loc != uiaa.ifaceno) | |
902 | continue; | 897 | continue; | |
903 | } | 898 | } | |
904 | dv = config_found_sm_loc(parent, "usbifif", ilocs, &uiaa, | 899 | dv = config_found_sm_loc(parent, "usbifif", ilocs, &uiaa, | |
905 | usbd_ifprint, config_stdsubmatch); | 900 | usbd_ifprint, config_stdsubmatch); | |
906 | if (!dv) | 901 | if (!dv) | |
907 | continue; | 902 | continue; | |
908 | ifaces[i] = 0; /* claim */ | 903 | ifaces[i] = 0; /* claim */ | |
909 | /* account for ifaces claimed by the driver behind our back */ | 904 | /* account for ifaces claimed by the driver behind our back */ | |
910 | for (j = 0; j < nifaces; j++) { | 905 | for (j = 0; j < nifaces; j++) { | |
911 | if (!ifaces[j] && !dev->subdevs[j]) { | 906 | if (!ifaces[j] && !dev->subdevs[j]) { | |
912 | dev->subdevs[j] = dv; | 907 | dev->subdevs[j] = dv; | |
913 | dev->nifaces_claimed++; | 908 | dev->nifaces_claimed++; | |
914 | } | 909 | } | |
915 | } | 910 | } | |
916 | } | 911 | } | |
917 | 912 | |||
918 | free(ifaces, M_USB); | 913 | free(ifaces, M_USB); | |
919 | return (USBD_NORMAL_COMPLETION); | 914 | return (USBD_NORMAL_COMPLETION); | |
920 | } | 915 | } | |
921 | 916 | |||
922 | usbd_status | 917 | usbd_status | |
923 | usbd_probe_and_attach(device_t parent, usbd_device_handle dev, | 918 | usbd_probe_and_attach(device_t parent, usbd_device_handle dev, | |
924 | int port, int addr) | 919 | int port, int addr) | |
925 | { | 920 | { | |
926 | usb_device_descriptor_t *dd = &dev->ddesc; | 921 | usb_device_descriptor_t *dd = &dev->ddesc; | |
927 | int confi, nifaces; | 922 | int confi, nifaces; | |
928 | usbd_status err; | 923 | usbd_status err; | |
929 | 924 | |||
930 | /* First try with device specific drivers. */ | 925 | /* First try with device specific drivers. */ | |
931 | DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n")); | 926 | DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n")); | |
932 | err = usbd_attachwholedevice(parent, dev, port, 0); | 927 | err = usbd_attachwholedevice(parent, dev, port, 0); | |
933 | if (dev->nifaces_claimed || err) | 928 | if (dev->nifaces_claimed || err) | |
934 | return (err); | 929 | return (err); | |
935 | DPRINTF(("usbd_probe_and_attach: no device specific driver found\n")); | 930 | DPRINTF(("usbd_probe_and_attach: no device specific driver found\n")); | |
936 | 931 | |||
937 | DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n", | 932 | DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n", | |
938 | dd->bNumConfigurations)); | 933 | dd->bNumConfigurations)); | |
939 | for (confi = 0; confi < dd->bNumConfigurations; confi++) { | 934 | for (confi = 0; confi < dd->bNumConfigurations; confi++) { | |
940 | DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n", | 935 | DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n", | |
941 | confi)); | 936 | confi)); | |
942 | err = usbd_set_config_index(dev, confi, 1); | 937 | err = usbd_set_config_index(dev, confi, 1); | |
943 | if (err) { | 938 | if (err) { | |
944 | #ifdef USB_DEBUG | 939 | #ifdef USB_DEBUG | |
945 | DPRINTF(("%s: port %d, set config at addr %d failed, " | 940 | DPRINTF(("%s: port %d, set config at addr %d failed, " | |
946 | "error=%s\n", device_xname(parent), port, | 941 | "error=%s\n", device_xname(parent), port, | |
947 | addr, usbd_errstr(err))); | 942 | addr, usbd_errstr(err))); | |
948 | #else | 943 | #else | |
949 | printf("%s: port %d, set config at addr %d failed\n", | 944 | printf("%s: port %d, set config at addr %d failed\n", | |
950 | device_xname(parent), port, addr); | 945 | device_xname(parent), port, addr); | |
951 | #endif | 946 | #endif | |
952 | return (err); | 947 | return (err); | |
953 | } | 948 | } | |
954 | nifaces = dev->cdesc->bNumInterface; | 949 | nifaces = dev->cdesc->bNumInterface; | |
955 | dev->subdevs = malloc(nifaces * sizeof(device_t), M_USB, | 950 | dev->subdevs = malloc(nifaces * sizeof(device_t), M_USB, | |
956 | M_NOWAIT|M_ZERO); | 951 | M_NOWAIT|M_ZERO); | |
957 | if (dev->subdevs == NULL) | 952 | if (dev->subdevs == NULL) | |
958 | return (USBD_NOMEM); | 953 | return (USBD_NOMEM); | |
959 | dev->subdevlen = nifaces; | 954 | dev->subdevlen = nifaces; | |
960 | 955 | |||
961 | err = usbd_attachinterfaces(parent, dev, port, NULL); | 956 | err = usbd_attachinterfaces(parent, dev, port, NULL); | |
962 | 957 | |||
963 | if (!dev->nifaces_claimed) { | 958 | if (!dev->nifaces_claimed) { | |
964 | free(dev->subdevs, M_USB); | 959 | free(dev->subdevs, M_USB); | |
965 | dev->subdevs = 0; | 960 | dev->subdevs = 0; | |
966 | dev->subdevlen = 0; | 961 | dev->subdevlen = 0; | |
967 | } | 962 | } | |
968 | if (dev->nifaces_claimed || err) | 963 | if (dev->nifaces_claimed || err) | |
969 | return (err); | 964 | return (err); | |
970 | } | 965 | } | |
971 | /* No interfaces were attached in any of the configurations. */ | 966 | /* No interfaces were attached in any of the configurations. */ | |
972 | 967 | |||
973 | if (dd->bNumConfigurations > 1) /* don't change if only 1 config */ | 968 | if (dd->bNumConfigurations > 1) /* don't change if only 1 config */ | |
974 | usbd_set_config_index(dev, 0, 0); | 969 | usbd_set_config_index(dev, 0, 0); | |
975 | 970 | |||
976 | DPRINTF(("usbd_probe_and_attach: no interface drivers found\n")); | 971 | DPRINTF(("usbd_probe_and_attach: no interface drivers found\n")); | |
977 | 972 | |||
978 | /* Finally try the generic driver. */ | 973 | /* Finally try the generic driver. */ | |
979 | err = usbd_attachwholedevice(parent, dev, port, 1); | 974 | err = usbd_attachwholedevice(parent, dev, port, 1); | |
980 | 975 | |||
981 | /* | 976 | /* | |
982 | * The generic attach failed, but leave the device as it is. | 977 | * The generic attach failed, but leave the device as it is. | |
983 | * We just did not find any drivers, that's all. The device is | 978 | * We just did not find any drivers, that's all. The device is | |
984 | * fully operational and not harming anyone. | 979 | * fully operational and not harming anyone. | |
985 | */ | 980 | */ | |
986 | DPRINTF(("usbd_probe_and_attach: generic attach failed\n")); | 981 | DPRINTF(("usbd_probe_and_attach: generic attach failed\n")); | |
987 | return (USBD_NORMAL_COMPLETION); | 982 | return (USBD_NORMAL_COMPLETION); | |
988 | } | 983 | } | |
989 | 984 | |||
990 | /** | 985 | /** | |
991 | * Called from uhub_rescan(). usbd_new_device() for the target dev must be | 986 | * Called from uhub_rescan(). usbd_new_device() for the target dev must be | |
992 | * called before calling this. | 987 | * called before calling this. | |
993 | */ | 988 | */ | |
994 | usbd_status | 989 | usbd_status | |
995 | usbd_reattach_device(device_t parent, usbd_device_handle dev, | 990 | usbd_reattach_device(device_t parent, usbd_device_handle dev, | |
996 | int port, const int *locators) | 991 | int port, const int *locators) | |
997 | { | 992 | { | |
998 | int i, loc; | 993 | int i, loc; | |
999 | 994 | |||
1000 | if (locators != NULL) { | 995 | if (locators != NULL) { | |
1001 | loc = locators[USBIFIFCF_PORT]; | 996 | loc = locators[USBIFIFCF_PORT]; | |
1002 | if (loc != USBIFIFCF_PORT_DEFAULT && loc != port) | 997 | if (loc != USBIFIFCF_PORT_DEFAULT && loc != port) | |
1003 | return USBD_NORMAL_COMPLETION; | 998 | return USBD_NORMAL_COMPLETION; | |
1004 | loc = locators[USBIFIFCF_VENDOR]; | 999 | loc = locators[USBIFIFCF_VENDOR]; | |
1005 | if (loc != USBIFIFCF_VENDOR_DEFAULT && | 1000 | if (loc != USBIFIFCF_VENDOR_DEFAULT && | |
1006 | loc != UGETW(dev->ddesc.idVendor)) | 1001 | loc != UGETW(dev->ddesc.idVendor)) | |
1007 | return USBD_NORMAL_COMPLETION; | 1002 | return USBD_NORMAL_COMPLETION; | |
1008 | loc = locators[USBIFIFCF_PRODUCT]; | 1003 | loc = locators[USBIFIFCF_PRODUCT]; | |
1009 | if (loc != USBIFIFCF_PRODUCT_DEFAULT && | 1004 | if (loc != USBIFIFCF_PRODUCT_DEFAULT && | |
1010 | loc != UGETW(dev->ddesc.idProduct)) | 1005 | loc != UGETW(dev->ddesc.idProduct)) | |
1011 | return USBD_NORMAL_COMPLETION; | 1006 | return USBD_NORMAL_COMPLETION; | |
1012 | loc = locators[USBIFIFCF_RELEASE]; | 1007 | loc = locators[USBIFIFCF_RELEASE]; | |
1013 | if (loc != USBIFIFCF_RELEASE_DEFAULT && | 1008 | if (loc != USBIFIFCF_RELEASE_DEFAULT && | |
1014 | loc != UGETW(dev->ddesc.bcdDevice)) | 1009 | loc != UGETW(dev->ddesc.bcdDevice)) | |
1015 | return USBD_NORMAL_COMPLETION; | 1010 | return USBD_NORMAL_COMPLETION; | |
1016 | } | 1011 | } | |
1017 | if (dev->subdevlen == 0) { | 1012 | if (dev->subdevlen == 0) { | |
1018 | /* XXX: check USBIFIFCF_CONFIGURATION and | 1013 | /* XXX: check USBIFIFCF_CONFIGURATION and | |
1019 | * USBIFIFCF_INTERFACE too */ | 1014 | * USBIFIFCF_INTERFACE too */ | |
1020 | return usbd_probe_and_attach(parent, dev, port, dev->address); | 1015 | return usbd_probe_and_attach(parent, dev, port, dev->address); | |
1021 | } else if (dev->subdevlen != dev->cdesc->bNumInterface) { | 1016 | } else if (dev->subdevlen != dev->cdesc->bNumInterface) { | |
1022 | /* device-specific or generic driver is already attached. */ | 1017 | /* device-specific or generic driver is already attached. */ | |
1023 | return USBD_NORMAL_COMPLETION; | 1018 | return USBD_NORMAL_COMPLETION; | |
1024 | } | 1019 | } | |
1025 | /* Does the device have unconfigured interfaces? */ | 1020 | /* Does the device have unconfigured interfaces? */ | |
1026 | for (i = 0; i < dev->subdevlen; i++) { | 1021 | for (i = 0; i < dev->subdevlen; i++) { | |
1027 | if (dev->subdevs[i] == NULL) { | 1022 | if (dev->subdevs[i] == NULL) { | |
1028 | break; | 1023 | break; | |
1029 | } | 1024 | } | |
1030 | } | 1025 | } | |
1031 | if (i >= dev->subdevlen) | 1026 | if (i >= dev->subdevlen) | |
1032 | return USBD_NORMAL_COMPLETION; | 1027 | return USBD_NORMAL_COMPLETION; | |
1033 | return usbd_attachinterfaces(parent, dev, port, locators); | 1028 | return usbd_attachinterfaces(parent, dev, port, locators); | |
1034 | } | 1029 | } | |
1035 | 1030 | |||
1036 | /* | 1031 | /* | |
1037 | * Get the first 8 bytes of the device descriptor. | 1032 | * Get the first 8 bytes of the device descriptor. | |
1038 | * Do as Windows does: try to read 64 bytes -- there are devices which | 1033 | * Do as Windows does: try to read 64 bytes -- there are devices which | |
1039 | * recognize the initial descriptor fetch (before the control endpoint's | 1034 | * recognize the initial descriptor fetch (before the control endpoint's | |
1040 | * MaxPacketSize is known by the host) by exactly this length. | 1035 | * MaxPacketSize is known by the host) by exactly this length. | |
1041 | */ | 1036 | */ | |
1042 | static usbd_status | 1037 | static usbd_status | |
1043 | usbd_get_initial_ddesc(usbd_device_handle dev, usb_device_descriptor_t *desc) | 1038 | usbd_get_initial_ddesc(usbd_device_handle dev, usb_device_descriptor_t *desc) | |
1044 | { | 1039 | { | |
1045 | usb_device_request_t req; | 1040 | usb_device_request_t req; | |
1046 | char buf[64]; | 1041 | char buf[64]; | |
1047 | int res, actlen; | 1042 | int res, actlen; | |
1048 | 1043 | |||
1049 | req.bmRequestType = UT_READ_DEVICE; | 1044 | req.bmRequestType = UT_READ_DEVICE; | |
1050 | req.bRequest = UR_GET_DESCRIPTOR; | 1045 | req.bRequest = UR_GET_DESCRIPTOR; | |
1051 | USETW2(req.wValue, UDESC_DEVICE, 0); | 1046 | USETW2(req.wValue, UDESC_DEVICE, 0); | |
1052 | USETW(req.wIndex, 0); | 1047 | USETW(req.wIndex, 0); | |
1053 | USETW(req.wLength, 64); | 1048 | USETW(req.wLength, 64); | |
1054 | res = usbd_do_request_flags(dev, &req, buf, USBD_SHORT_XFER_OK, | 1049 | res = usbd_do_request_flags(dev, &req, buf, USBD_SHORT_XFER_OK, | |
1055 | &actlen, USBD_DEFAULT_TIMEOUT); | 1050 | &actlen, USBD_DEFAULT_TIMEOUT); | |
1056 | if (res) | 1051 | if (res) | |
1057 | return res; | 1052 | return res; | |
1058 | if (actlen < 8) | 1053 | if (actlen < 8) | |
1059 | return USBD_SHORT_XFER; | 1054 | return USBD_SHORT_XFER; | |
1060 | memcpy(desc, buf, 8); | 1055 | memcpy(desc, buf, 8); | |
1061 | return USBD_NORMAL_COMPLETION; | 1056 | return USBD_NORMAL_COMPLETION; | |
1062 | } | 1057 | } | |
1063 | 1058 | |||
1064 | /* | 1059 | /* | |
1065 | * Called when a new device has been put in the powered state, | 1060 | * Called when a new device has been put in the powered state, | |
1066 | * but not yet in the addressed state. | 1061 | * but not yet in the addressed state. | |
1067 | * Get initial descriptor, set the address, get full descriptor, | 1062 | * Get initial descriptor, set the address, get full descriptor, | |
1068 | * and attach a driver. | 1063 | * and attach a driver. | |
1069 | */ | 1064 | */ | |
1070 | usbd_status | 1065 | usbd_status | |
1071 | usbd_new_device(device_t parent, usbd_bus_handle bus, int depth, | 1066 | usbd_new_device(device_t parent, usbd_bus_handle bus, int depth, | |
1072 | int speed, int port, struct usbd_port *up) | 1067 | int speed, int port, struct usbd_port *up) | |
1073 | { | 1068 | { | |
1074 | usbd_device_handle dev, adev; | 1069 | usbd_device_handle dev, adev; | |
1075 | struct usbd_device *hub; | 1070 | struct usbd_device *hub; | |
1076 | usb_device_descriptor_t *dd; | 1071 | usb_device_descriptor_t *dd; | |
1077 | usb_port_status_t ps; | 1072 | usb_port_status_t ps; | |
1078 | usbd_status err; | 1073 | usbd_status err; | |
1079 | int addr; | 1074 | int addr; | |
1080 | int i; | 1075 | int i; | |
1081 | int p; | 1076 | int p; | |
1082 | 1077 | |||
1083 | DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n", | 1078 | DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n", | |
1084 | bus, port, depth, speed)); | 1079 | bus, port, depth, speed)); | |
1085 | addr = usbd_getnewaddr(bus); | 1080 | addr = usbd_getnewaddr(bus); | |
1086 | if (addr < 0) { | 1081 | if (addr < 0) { | |
1087 | printf("%s: No free USB addresses, new device ignored.\n", | 1082 | printf("%s: No free USB addresses, new device ignored.\n", | |
1088 | device_xname(bus->usbctl)); | 1083 | device_xname(bus->usbctl)); | |
1089 | return (USBD_NO_ADDR); | 1084 | return (USBD_NO_ADDR); | |
1090 | } | 1085 | } | |
1091 | 1086 | |||
1092 | dev = malloc(sizeof *dev, M_USB, M_NOWAIT|M_ZERO); | 1087 | dev = malloc(sizeof *dev, M_USB, M_NOWAIT|M_ZERO); | |
1093 | if (dev == NULL) | 1088 | if (dev == NULL) | |
1094 | return (USBD_NOMEM); | 1089 | return (USBD_NOMEM); | |
1095 | 1090 | |||
1096 | dev->bus = bus; | 1091 | dev->bus = bus; | |
1097 | 1092 | |||
1098 | /* Set up default endpoint handle. */ | 1093 | /* Set up default endpoint handle. */ | |
1099 | dev->def_ep.edesc = &dev->def_ep_desc; | 1094 | dev->def_ep.edesc = &dev->def_ep_desc; | |
1100 | 1095 | |||
1101 | /* Set up default endpoint descriptor. */ | 1096 | /* Set up default endpoint descriptor. */ | |
1102 | dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE; | 1097 | dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE; | |
1103 | dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT; | 1098 | dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT; | |
1104 | dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT; | 1099 | dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT; | |
1105 | dev->def_ep_desc.bmAttributes = UE_CONTROL; | 1100 | dev->def_ep_desc.bmAttributes = UE_CONTROL; | |
1106 | /* | 1101 | /* | |
1107 | * temporary, will be fixed after first descriptor fetch | 1102 | * temporary, will be fixed after first descriptor fetch | |
1108 | * (which uses 64 bytes so it shouldn't be less), | 1103 | * (which uses 64 bytes so it shouldn't be less), | |
1109 | * highspeed devices must support 64 byte packets anyway | 1104 | * highspeed devices must support 64 byte packets anyway | |
1110 | */ | 1105 | */ | |
1111 | USETW(dev->def_ep_desc.wMaxPacketSize, 64); | 1106 | USETW(dev->def_ep_desc.wMaxPacketSize, 64); | |
1112 | dev->def_ep_desc.bInterval = 0; | 1107 | dev->def_ep_desc.bInterval = 0; | |
1113 | 1108 | |||
1114 | /* doesn't matter, just don't let it uninitialized */ | 1109 | /* doesn't matter, just don't let it uninitialized */ | |
1115 | dev->def_ep.datatoggle = 0; | 1110 | dev->def_ep.datatoggle = 0; | |
1116 | 1111 | |||
1117 | dev->quirks = &usbd_no_quirk; | 1112 | dev->quirks = &usbd_no_quirk; | |
1118 | dev->address = USB_START_ADDR; | 1113 | dev->address = USB_START_ADDR; | |
1119 | dev->ddesc.bMaxPacketSize = 0; | 1114 | dev->ddesc.bMaxPacketSize = 0; | |
1120 | dev->depth = depth; | 1115 | dev->depth = depth; | |
1121 | dev->powersrc = up; | 1116 | dev->powersrc = up; | |
1122 | dev->myhub = up->parent; | 1117 | dev->myhub = up->parent; | |
1123 | 1118 | |||
1124 | up->device = dev; | 1119 | up->device = dev; | |
1125 | 1120 | |||
1126 | /* Locate port on upstream high speed hub */ | 1121 | /* Locate port on upstream high speed hub */ | |
1127 | for (adev = dev, hub = up->parent; | 1122 | for (adev = dev, hub = up->parent; | |
1128 | hub != NULL && hub->speed != USB_SPEED_HIGH; | 1123 | hub != NULL && hub->speed != USB_SPEED_HIGH; | |
1129 | adev = hub, hub = hub->myhub) | 1124 | adev = hub, hub = hub->myhub) | |
1130 | ; | 1125 | ; | |
1131 | if (hub) { | 1126 | if (hub) { | |
1132 | for (p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) { | 1127 | for (p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) { | |
1133 | if (hub->hub->ports[p].device == adev) { | 1128 | if (hub->hub->ports[p].device == adev) { | |
1134 | dev->myhsport = &hub->hub->ports[p]; | 1129 | dev->myhsport = &hub->hub->ports[p]; | |
1135 | goto found; | 1130 | goto found; | |
1136 | } | 1131 | } | |
1137 | } | 1132 | } | |
1138 | panic("usbd_new_device: cannot find HS port\n"); | 1133 | panic("usbd_new_device: cannot find HS port\n"); | |
1139 | found: | 1134 | found: | |
1140 | DPRINTFN(1,("usbd_new_device: high speed port %d\n", p)); | 1135 | DPRINTFN(1,("usbd_new_device: high speed port %d\n", p)); | |
1141 | } else { | 1136 | } else { | |
1142 | dev->myhsport = NULL; | 1137 | dev->myhsport = NULL; | |
1143 | } | 1138 | } | |
1144 | dev->speed = speed; | 1139 | dev->speed = speed; | |
1145 | dev->langid = USBD_NOLANG; | 1140 | dev->langid = USBD_NOLANG; | |
1146 | dev->cookie.cookie = ++usb_cookie_no; | 1141 | dev->cookie.cookie = ++usb_cookie_no; | |
1147 | 1142 | |||
1148 | /* Establish the default pipe. */ | 1143 | /* Establish the default pipe. */ | |
1149 | err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL, | 1144 | err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL, | |
1150 | &dev->default_pipe); | 1145 | &dev->default_pipe); | |
1151 | if (err) { | 1146 | if (err) { | |
1152 | usbd_remove_device(dev, up); | 1147 | usbd_remove_device(dev, up); | |
1153 | return (err); | 1148 | return (err); | |
1154 | } | 1149 | } | |
1155 | 1150 | |||
1156 | dd = &dev->ddesc; | 1151 | dd = &dev->ddesc; | |
1157 | /* Try a few times in case the device is slow (i.e. outside specs.) */ | 1152 | /* Try a few times in case the device is slow (i.e. outside specs.) */ | |
1158 | for (i = 0; i < 10; i++) { | 1153 | for (i = 0; i < 10; i++) { | |
1159 | /* Get the first 8 bytes of the device descriptor. */ | 1154 | /* Get the first 8 bytes of the device descriptor. */ | |
1160 | err = usbd_get_initial_ddesc(dev, dd); | 1155 | err = usbd_get_initial_ddesc(dev, dd); | |
1161 | if (!err) | 1156 | if (!err) | |
1162 | break; | 1157 | break; | |
1163 | usbd_delay_ms(dev, 200); | 1158 | usbd_delay_ms(dev, 200); | |
1164 | if ((i & 3) == 3) | 1159 | if ((i & 3) == 3) | |
1165 | usbd_reset_port(up->parent, port, &ps); | 1160 | usbd_reset_port(up->parent, port, &ps); | |
1166 | } | 1161 | } | |
1167 | if (err) { | 1162 | if (err) { | |
1168 | DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc " | 1163 | DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc " | |
1169 | "failed: %d\n", addr, err)); | 1164 | "failed: %d\n", addr, err)); | |
1170 | usbd_remove_device(dev, up); | 1165 | usbd_remove_device(dev, up); | |
1171 | return (err); | 1166 | return (err); | |
1172 | } | 1167 | } | |
1173 | 1168 | |||
1174 | /* Windows resets the port here, do likewise */ | 1169 | /* Windows resets the port here, do likewise */ | |
1175 | if (up->parent) | 1170 | if (up->parent) | |
1176 | usbd_reset_port(up->parent, port, &ps); | 1171 | usbd_reset_port(up->parent, port, &ps); | |
1177 | 1172 | |||
1178 | if (speed == USB_SPEED_HIGH) { | 1173 | if (speed == USB_SPEED_HIGH) { | |
1179 | /* Max packet size must be 64 (sec 5.5.3). */ | 1174 | /* Max packet size must be 64 (sec 5.5.3). */ | |
1180 | if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) { | 1175 | if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) { | |
1181 | #ifdef DIAGNOSTIC | 1176 | #ifdef DIAGNOSTIC | |
1182 | printf("usbd_new_device: addr=%d bad max packet " | 1177 | printf("usbd_new_device: addr=%d bad max packet " | |
1183 | "size=%d. adjusting to %d.\n", | 1178 | "size=%d. adjusting to %d.\n", | |
1184 | addr, dd->bMaxPacketSize, USB_2_MAX_CTRL_PACKET); | 1179 | addr, dd->bMaxPacketSize, USB_2_MAX_CTRL_PACKET); | |
1185 | #endif | 1180 | #endif | |
1186 | dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET; | 1181 | dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET; | |
1187 | } | 1182 | } | |
1188 | } | 1183 | } | |
1189 | 1184 | |||
1190 | DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, " | 1185 | DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, " | |
1191 | "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", | 1186 | "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", | |
1192 | addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass, | 1187 | addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass, | |
1193 | dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength, | 1188 | dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength, | |
1194 | dev->speed)); | 1189 | dev->speed)); | |
1195 | 1190 | |||
1196 | if (dd->bDescriptorType != UDESC_DEVICE) { | 1191 | if (dd->bDescriptorType != UDESC_DEVICE) { | |
1197 | /* Illegal device descriptor */ | 1192 | /* Illegal device descriptor */ | |
1198 | DPRINTFN(-1,("usbd_new_device: illegal descriptor %d\n", | 1193 | DPRINTFN(-1,("usbd_new_device: illegal descriptor %d\n", | |
1199 | dd->bDescriptorType)); | 1194 | dd->bDescriptorType)); | |
1200 | usbd_remove_device(dev, up); | 1195 | usbd_remove_device(dev, up); | |
1201 | return (USBD_INVAL); | 1196 | return (USBD_INVAL); | |
1202 | } | 1197 | } | |
1203 | 1198 | |||
1204 | if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) { | 1199 | if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) { | |
1205 | DPRINTFN(-1,("usbd_new_device: bad length %d\n", dd->bLength)); | 1200 | DPRINTFN(-1,("usbd_new_device: bad length %d\n", dd->bLength)); | |
1206 | usbd_remove_device(dev, up); | 1201 | usbd_remove_device(dev, up); | |
1207 | return (USBD_INVAL); | 1202 | return (USBD_INVAL); | |
1208 | } | 1203 | } | |
1209 | 1204 | |||
1210 | USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize); | 1205 | USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize); | |
1211 | 1206 | |||
1212 | /* Set the address */ | 1207 | /* Set the address */ | |
1213 | DPRINTFN(5, ("usbd_new_device: setting device address=%d\n", addr)); | 1208 | DPRINTFN(5, ("usbd_new_device: setting device address=%d\n", addr)); | |
1214 | err = usbd_set_address(dev, addr); | 1209 | err = usbd_set_address(dev, addr); | |
1215 | if (err) { | 1210 | if (err) { | |
1216 | DPRINTFN(-1, ("usbd_new_device: set address %d failed\n", addr)); | 1211 | DPRINTFN(-1, ("usbd_new_device: set address %d failed\n", addr)); | |
1217 | err = USBD_SET_ADDR_FAILED; | 1212 | err = USBD_SET_ADDR_FAILED; | |
1218 | usbd_remove_device(dev, up); | 1213 | usbd_remove_device(dev, up); | |
1219 | return err; | 1214 | return err; | |
1220 | } | 1215 | } | |
1221 | 1216 | |||
1222 | /* Allow device time to set new address */ | 1217 | /* Allow device time to set new address */ | |
1223 | usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE); | 1218 | usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE); | |
1224 | dev->address = addr; /* new device address now */ | 1219 | dev->address = addr; /* new device address now */ | |
1225 | bus->devices[addr] = dev; | 1220 | bus->devices[addr] = dev; | |
1226 | 1221 | |||
1227 | err = usbd_reload_device_desc(dev); | 1222 | err = usbd_reload_device_desc(dev); | |
1228 | if (err) { | 1223 | if (err) { | |
1229 | DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc " | 1224 | DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc " | |
1230 | "failed\n", addr)); | 1225 | "failed\n", addr)); | |
1231 | usbd_remove_device(dev, up); | 1226 | usbd_remove_device(dev, up); | |
1232 | return (err); | 1227 | return (err); | |
1233 | } | 1228 | } | |
1234 | 1229 | |||
1235 | /* Re-establish the default pipe with the new address. */ | 1230 | /* Re-establish the default pipe with the new address. */ | |
1236 | usbd_kill_pipe(dev->default_pipe); | 1231 | usbd_kill_pipe(dev->default_pipe); | |
1237 | err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL, | 1232 | err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL, | |
1238 | &dev->default_pipe); | 1233 | &dev->default_pipe); | |
1239 | if (err) { | 1234 | if (err) { | |
1240 | DPRINTFN(-1, ("usbd_new_device: setup default pipe failed\n")); | 1235 | DPRINTFN(-1, ("usbd_new_device: setup default pipe failed\n")); | |
1241 | usbd_remove_device(dev, up); | 1236 | usbd_remove_device(dev, up); | |
1242 | return err; | 1237 | return err; | |
1243 | } | 1238 | } | |
1244 | 1239 | |||
1245 | /* Assume 100mA bus powered for now. Changed when configured. */ | 1240 | /* Assume 100mA bus powered for now. Changed when configured. */ | |
1246 | dev->power = USB_MIN_POWER; | 1241 | dev->power = USB_MIN_POWER; | |
1247 | dev->self_powered = 0; | 1242 | dev->self_powered = 0; | |
1248 | 1243 | |||
1249 | DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n", | 1244 | DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n", | |
1250 | addr, dev, parent)); | 1245 | addr, dev, parent)); | |
1251 | 1246 | |||
1252 | usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev); | 1247 | usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev); | |
1253 | 1248 | |||
1254 | if (port == 0) { /* root hub */ | 1249 | if (port == 0) { /* root hub */ | |
1255 | KASSERT(addr == 1); | 1250 | KASSERT(addr == 1); | |
1256 | usbd_attach_roothub(parent, dev); | 1251 | usbd_attach_roothub(parent, dev); | |
1257 | return (USBD_NORMAL_COMPLETION); | 1252 | return (USBD_NORMAL_COMPLETION); | |
1258 | } | 1253 | } | |
1259 | 1254 | |||
1260 | err = usbd_probe_and_attach(parent, dev, port, addr); | 1255 | err = usbd_probe_and_attach(parent, dev, port, addr); | |
1261 | if (err) { | 1256 | if (err) { | |
1262 | usbd_remove_device(dev, up); | 1257 | usbd_remove_device(dev, up); | |
1263 | return (err); | 1258 | return (err); | |
1264 | } | 1259 | } | |
1265 | 1260 | |||
1266 | return (USBD_NORMAL_COMPLETION); | 1261 | return (USBD_NORMAL_COMPLETION); | |
1267 | } | 1262 | } | |
1268 | 1263 | |||
1269 | usbd_status | 1264 | usbd_status | |
1270 | usbd_reload_device_desc(usbd_device_handle dev) | 1265 | usbd_reload_device_desc(usbd_device_handle dev) | |
1271 | { | 1266 | { | |
1272 | usbd_status err; | 1267 | usbd_status err; | |
1273 | 1268 | |||
1274 | /* Get the full device descriptor. */ | 1269 | /* Get the full device descriptor. */ | |
1275 | err = usbd_get_device_desc(dev, &dev->ddesc); | 1270 | err = usbd_get_device_desc(dev, &dev->ddesc); | |
1276 | if (err) | 1271 | if (err) | |
1277 | return (err); | 1272 | return (err); | |
1278 | 1273 | |||
1279 | /* Figure out what's wrong with this device. */ | 1274 | /* Figure out what's wrong with this device. */ | |
1280 | dev->quirks = usbd_find_quirk(&dev->ddesc); | 1275 | dev->quirks = usbd_find_quirk(&dev->ddesc); | |
1281 | 1276 | |||
1282 | return (USBD_NORMAL_COMPLETION); | 1277 | return (USBD_NORMAL_COMPLETION); | |
1283 | } | 1278 | } | |
1284 | 1279 | |||
1285 | void | 1280 | void | |
1286 | usbd_remove_device(usbd_device_handle dev, struct usbd_port *up) | 1281 | usbd_remove_device(usbd_device_handle dev, struct usbd_port *up) | |
1287 | { | 1282 | { | |
1288 | DPRINTF(("usbd_remove_device: %p\n", dev)); | 1283 | DPRINTF(("usbd_remove_device: %p\n", dev)); | |
1289 | 1284 | |||
1290 | if (dev->default_pipe != NULL) | 1285 | if (dev->default_pipe != NULL) | |
1291 | usbd_kill_pipe(dev->default_pipe); | 1286 | usbd_kill_pipe(dev->default_pipe); | |
1292 | up->device = NULL; | 1287 | up->device = NULL; | |
1293 | dev->bus->devices[dev->address] = NULL; | 1288 | dev->bus->devices[dev->address] = NULL; | |
1294 | 1289 | |||
1295 | free(dev, M_USB); | 1290 | free(dev, M_USB); | |
1296 | } | 1291 | } | |
1297 | 1292 | |||
1298 | int | 1293 | int | |
1299 | usbd_print(void *aux, const char *pnp) | 1294 | usbd_print(void *aux, const char *pnp) | |
1300 | { | 1295 | { | |
1301 | struct usb_attach_arg *uaa = aux; | 1296 | struct usb_attach_arg *uaa = aux; | |
1302 | 1297 | |||
1303 | DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); | 1298 | DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); | |
1304 | if (pnp) { | 1299 | if (pnp) { | |
1305 | #define USB_DEVINFO 1024 | 1300 | #define USB_DEVINFO 1024 | |
1306 | char *devinfo; | 1301 | char *devinfo; | |
1307 | if (!uaa->usegeneric) | 1302 | if (!uaa->usegeneric) | |
1308 | return (QUIET); | 1303 | return (QUIET); | |
1309 | devinfo = malloc(USB_DEVINFO, M_TEMP, M_WAITOK); | 1304 | devinfo = malloc(USB_DEVINFO, M_TEMP, M_WAITOK); | |
1310 | usbd_devinfo(uaa->device, 1, devinfo, USB_DEVINFO); | 1305 | usbd_devinfo(uaa->device, 1, devinfo, USB_DEVINFO); | |
1311 | aprint_normal("%s, %s", devinfo, pnp); | 1306 | aprint_normal("%s, %s", devinfo, pnp); | |
1312 | free(devinfo, M_TEMP); | 1307 | free(devinfo, M_TEMP); | |
1313 | } | 1308 | } | |
1314 | aprint_normal(" port %d", uaa->port); | 1309 | aprint_normal(" port %d", uaa->port); | |
1315 | #if 0 | 1310 | #if 0 | |
1316 | /* | 1311 | /* | |
1317 | * It gets very crowded with these locators on the attach line. | 1312 | * It gets very crowded with these locators on the attach line. | |
1318 | * They are not really needed since they are printed in the clear | 1313 | * They are not really needed since they are printed in the clear | |
1319 | * by each driver. | 1314 | * by each driver. | |
1320 | */ | 1315 | */ | |
1321 | if (uaa->vendor != UHUB_UNK_VENDOR) | 1316 | if (uaa->vendor != UHUB_UNK_VENDOR) | |
1322 | aprint_normal(" vendor 0x%04x", uaa->vendor); | 1317 | aprint_normal(" vendor 0x%04x", uaa->vendor); | |
1323 | if (uaa->product != UHUB_UNK_PRODUCT) | 1318 | if (uaa->product != UHUB_UNK_PRODUCT) | |
1324 | aprint_normal(" product 0x%04x", uaa->product); | 1319 | aprint_normal(" product 0x%04x", uaa->product); | |
1325 | if (uaa->release != UHUB_UNK_RELEASE) | 1320 | if (uaa->release != UHUB_UNK_RELEASE) | |
1326 | aprint_normal(" release 0x%04x", uaa->release); | 1321 | aprint_normal(" release 0x%04x", uaa->release); | |
1327 | #endif | 1322 | #endif | |
1328 | return (UNCONF); | 1323 | return (UNCONF); | |
1329 | } | 1324 | } | |
1330 | 1325 | |||
1331 | int | 1326 | int | |
1332 | usbd_ifprint(void *aux, const char *pnp) | 1327 | usbd_ifprint(void *aux, const char *pnp) | |
1333 | { | 1328 | { | |
1334 | struct usbif_attach_arg *uaa = aux; | 1329 | struct usbif_attach_arg *uaa = aux; | |
1335 | 1330 | |||
1336 | DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); | 1331 | DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); | |
1337 | if (pnp) | 1332 | if (pnp) | |
1338 | return (QUIET); | 1333 | return (QUIET); | |
1339 | aprint_normal(" port %d", uaa->port); | 1334 | aprint_normal(" port %d", uaa->port); | |
1340 | aprint_normal(" configuration %d", uaa->configno); | 1335 | aprint_normal(" configuration %d", uaa->configno); | |
1341 | aprint_normal(" interface %d", uaa->ifaceno); | 1336 | aprint_normal(" interface %d", uaa->ifaceno); | |
1342 | #if 0 | 1337 | #if 0 | |
1343 | /* | 1338 | /* | |
1344 | * It gets very crowded with these locators on the attach line. | 1339 | * It gets very crowded with these locators on the attach line. | |
1345 | * They are not really needed since they are printed in the clear | 1340 | * They are not really needed since they are printed in the clear | |
1346 | * by each driver. | 1341 | * by each driver. | |
1347 | */ | 1342 | */ | |
1348 | if (uaa->vendor != UHUB_UNK_VENDOR) | 1343 | if (uaa->vendor != UHUB_UNK_VENDOR) | |
1349 | aprint_normal(" vendor 0x%04x", uaa->vendor); | 1344 | aprint_normal(" vendor 0x%04x", uaa->vendor); | |
1350 | if (uaa->product != UHUB_UNK_PRODUCT) | 1345 | if (uaa->product != UHUB_UNK_PRODUCT) | |
1351 | aprint_normal(" product 0x%04x", uaa->product); | 1346 | aprint_normal(" product 0x%04x", uaa->product); | |
1352 | if (uaa->release != UHUB_UNK_RELEASE) | 1347 | if (uaa->release != UHUB_UNK_RELEASE) | |
1353 | aprint_normal(" release 0x%04x", uaa->release); | 1348 | aprint_normal(" release 0x%04x", uaa->release); | |
1354 | #endif | 1349 | #endif | |
1355 | return (UNCONF); | 1350 | return (UNCONF); | |
1356 | } | 1351 | } | |
1357 | 1352 | |||
1358 | void | 1353 | void | |
1359 | usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di, | 1354 | usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di, | |
1360 | int usedev) | 1355 | int usedev) | |
1361 | { | 1356 | { | |
1362 | struct usbd_port *p; | 1357 | struct usbd_port *p; | |
1363 | int i, j, err, s; | 1358 | int i, j, err, s; | |
1364 | 1359 | |||
1365 | di->udi_bus = device_unit(dev->bus->usbctl); | 1360 | di->udi_bus = device_unit(dev->bus->usbctl); | |
1366 | di->udi_addr = dev->address; | 1361 | di->udi_addr = dev->address; | |
1367 | di->udi_cookie = dev->cookie; | 1362 | di->udi_cookie = dev->cookie; | |
1368 | usbd_devinfo_vp(dev, di->udi_vendor, sizeof(di->udi_vendor), | 1363 | usbd_devinfo_vp(dev, di->udi_vendor, sizeof(di->udi_vendor), | |
1369 | di->udi_product, sizeof(di->udi_product), usedev, 1); | 1364 | di->udi_product, sizeof(di->udi_product), usedev, 1); | |
1370 | usbd_printBCD(di->udi_release, sizeof(di->udi_release), | 1365 | usbd_printBCD(di->udi_release, sizeof(di->udi_release), | |
1371 | UGETW(dev->ddesc.bcdDevice)); | 1366 | UGETW(dev->ddesc.bcdDevice)); | |
1372 | di->udi_serial[0] = 0; | 1367 | di->udi_serial[0] = 0; | |
1373 | if (usedev) | 1368 | if (usedev) | |
1374 | (void)usbd_get_string(dev, dev->ddesc.iSerialNumber, | 1369 | (void)usbd_get_string(dev, dev->ddesc.iSerialNumber, | |
1375 | di->udi_serial); | 1370 | di->udi_serial); | |
1376 | di->udi_vendorNo = UGETW(dev->ddesc.idVendor); | 1371 | di->udi_vendorNo = UGETW(dev->ddesc.idVendor); | |
1377 | di->udi_productNo = UGETW(dev->ddesc.idProduct); | 1372 | di->udi_productNo = UGETW(dev->ddesc.idProduct); | |
1378 | di->udi_releaseNo = UGETW(dev->ddesc.bcdDevice); | 1373 | di->udi_releaseNo = UGETW(dev->ddesc.bcdDevice); | |
1379 | di->udi_class = dev->ddesc.bDeviceClass; | 1374 | di->udi_class = dev->ddesc.bDeviceClass; | |
1380 | di->udi_subclass = dev->ddesc.bDeviceSubClass; | 1375 | di->udi_subclass = dev->ddesc.bDeviceSubClass; | |
1381 | di->udi_protocol = dev->ddesc.bDeviceProtocol; | 1376 | di->udi_protocol = dev->ddesc.bDeviceProtocol; | |
1382 | di->udi_config = dev->config; | 1377 | di->udi_config = dev->config; | |
1383 | di->udi_power = dev->self_powered ? 0 : dev->power; | 1378 | di->udi_power = dev->self_powered ? 0 : dev->power; | |
1384 | di->udi_speed = dev->speed; | 1379 | di->udi_speed = dev->speed; | |
1385 | 1380 | |||
1386 | if (dev->subdevlen > 0) { | 1381 | if (dev->subdevlen > 0) { | |
1387 | for (i = 0, j = 0; i < dev->subdevlen && | 1382 | for (i = 0, j = 0; i < dev->subdevlen && | |
1388 | j < USB_MAX_DEVNAMES; i++) { | 1383 | j < USB_MAX_DEVNAMES; i++) { | |
1389 | if (!dev->subdevs[i]) | 1384 | if (!dev->subdevs[i]) | |
1390 | continue; | 1385 | continue; | |
1391 | strncpy(di->udi_devnames[j], | 1386 | strncpy(di->udi_devnames[j], | |
1392 | device_xname(dev->subdevs[i]), USB_MAX_DEVNAMELEN); | 1387 | device_xname(dev->subdevs[i]), USB_MAX_DEVNAMELEN); | |
1393 | di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; | 1388 | di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; | |
1394 | j++; | 1389 | j++; | |
1395 | } | 1390 | } | |
1396 | } else { | 1391 | } else { | |
1397 | j = 0; | 1392 | j = 0; | |
1398 | } | 1393 | } | |
1399 | for (/* j is set */; j < USB_MAX_DEVNAMES; j++) | 1394 | for (/* j is set */; j < USB_MAX_DEVNAMES; j++) | |
1400 | di->udi_devnames[j][0] = 0; /* empty */ | 1395 | di->udi_devnames[j][0] = 0; /* empty */ | |
1401 | 1396 | |||
1402 | if (dev->hub) { | 1397 | if (dev->hub) { | |
1403 | for (i = 0; | 1398 | for (i = 0; | |
1404 | i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) && | 1399 | i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) && | |
1405 | i < dev->hub->hubdesc.bNbrPorts; | 1400 | i < dev->hub->hubdesc.bNbrPorts; | |
1406 | i++) { | 1401 | i++) { | |
1407 | p = &dev->hub->ports[i]; | 1402 | p = &dev->hub->ports[i]; | |
1408 | if (p->device) | 1403 | if (p->device) | |
1409 | err = p->device->address; | 1404 | err = p->device->address; | |
1410 | else { | 1405 | else { | |
1411 | s = UGETW(p->status.wPortStatus); | 1406 | s = UGETW(p->status.wPortStatus); | |
1412 | if (s & UPS_PORT_ENABLED) | 1407 | if (s & UPS_PORT_ENABLED) | |
1413 | err = USB_PORT_ENABLED; | 1408 | err = USB_PORT_ENABLED; | |
1414 | else if (s & UPS_SUSPEND) | 1409 | else if (s & UPS_SUSPEND) | |
1415 | err = USB_PORT_SUSPENDED; | 1410 | err = USB_PORT_SUSPENDED; | |
1416 | else if (s & UPS_PORT_POWER) | 1411 | else if (s & UPS_PORT_POWER) | |
1417 | err = USB_PORT_POWERED; | 1412 | err = USB_PORT_POWERED; | |
1418 | else | 1413 | else | |
1419 | err = USB_PORT_DISABLED; | 1414 | err = USB_PORT_DISABLED; | |
1420 | } | 1415 | } | |
1421 | di->udi_ports[i] = err; | 1416 | di->udi_ports[i] = err; | |
1422 | } | 1417 | } | |
1423 | di->udi_nports = dev->hub->hubdesc.bNbrPorts; | 1418 | di->udi_nports = dev->hub->hubdesc.bNbrPorts; | |
1424 | } else | 1419 | } else | |
1425 | di->udi_nports = 0; | 1420 | di->udi_nports = 0; | |
1426 | } | 1421 | } | |
1427 | 1422 | |||
1428 | #ifdef COMPAT_30 | 1423 | #ifdef COMPAT_30 | |
1429 | void | 1424 | void | |
1430 | usbd_fill_deviceinfo_old(usbd_device_handle dev, struct usb_device_info_old *di, | 1425 | usbd_fill_deviceinfo_old(usbd_device_handle dev, struct usb_device_info_old *di, | |
1431 | int usedev) | 1426 | int usedev) | |
1432 | { | 1427 | { | |
1433 | struct usbd_port *p; | 1428 | struct usbd_port *p; | |
1434 | int i, j, err, s; | 1429 | int i, j, err, s; | |
1435 | 1430 | |||
1436 | di->udi_bus = device_unit(dev->bus->usbctl); | 1431 | di->udi_bus = device_unit(dev->bus->usbctl); | |
1437 | di->udi_addr = dev->address; | 1432 | di->udi_addr = dev->address; | |
1438 | di->udi_cookie = dev->cookie; | 1433 | di->udi_cookie = dev->cookie; | |
1439 | usbd_devinfo_vp(dev, di->udi_vendor, sizeof(di->udi_vendor), | 1434 | usbd_devinfo_vp(dev, di->udi_vendor, sizeof(di->udi_vendor), | |
1440 | di->udi_product, sizeof(di->udi_product), usedev, 0); | 1435 | di->udi_product, sizeof(di->udi_product), usedev, 0); | |
1441 | usbd_printBCD(di->udi_release, sizeof(di->udi_release), | 1436 | usbd_printBCD(di->udi_release, sizeof(di->udi_release), | |
1442 | UGETW(dev->ddesc.bcdDevice)); | 1437 | UGETW(dev->ddesc.bcdDevice)); | |
1443 | di->udi_vendorNo = UGETW(dev->ddesc.idVendor); | 1438 | di->udi_vendorNo = UGETW(dev->ddesc.idVendor); | |
1444 | di->udi_productNo = UGETW(dev->ddesc.idProduct); | 1439 | di->udi_productNo = UGETW(dev->ddesc.idProduct); | |
1445 | di->udi_releaseNo = UGETW(dev->ddesc.bcdDevice); | 1440 | di->udi_releaseNo = UGETW(dev->ddesc.bcdDevice); | |
1446 | di->udi_class = dev->ddesc.bDeviceClass; | 1441 | di->udi_class = dev->ddesc.bDeviceClass; | |
1447 | di->udi_subclass = dev->ddesc.bDeviceSubClass; | 1442 | di->udi_subclass = dev->ddesc.bDeviceSubClass; | |
1448 | di->udi_protocol = dev->ddesc.bDeviceProtocol; | 1443 | di->udi_protocol = dev->ddesc.bDeviceProtocol; | |
1449 | di->udi_config = dev->config; | 1444 | di->udi_config = dev->config; | |
1450 | di->udi_power = dev->self_powered ? 0 : dev->power; | 1445 | di->udi_power = dev->self_powered ? 0 : dev->power; | |
1451 | di->udi_speed = dev->speed; | 1446 | di->udi_speed = dev->speed; | |
1452 | 1447 | |||
1453 | if (dev->subdevlen > 0) { | 1448 | if (dev->subdevlen > 0) { | |
1454 | for (i = 0, j = 0; i < dev->subdevlen && | 1449 | for (i = 0, j = 0; i < dev->subdevlen && | |
1455 | j < USB_MAX_DEVNAMES; i++) { | 1450 | j < USB_MAX_DEVNAMES; i++) { | |
1456 | if (!dev->subdevs[i]) | 1451 | if (!dev->subdevs[i]) | |
1457 | continue; | 1452 | continue; | |
1458 | strncpy(di->udi_devnames[j], | 1453 | strncpy(di->udi_devnames[j], | |
1459 | device_xname(dev->subdevs[i]), USB_MAX_DEVNAMELEN); | 1454 | device_xname(dev->subdevs[i]), USB_MAX_DEVNAMELEN); | |
1460 | di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; | 1455 | di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; | |
1461 | j++; | 1456 | j++; | |
1462 | } | 1457 | } | |
1463 | } else { | 1458 | } else { | |
1464 | j = 0; | 1459 | j = 0; | |
1465 | } | 1460 | } | |
1466 | for (/* j is set */; j < USB_MAX_DEVNAMES; j++) | 1461 | for (/* j is set */; j < USB_MAX_DEVNAMES; j++) | |
1467 | di->udi_devnames[j][0] = 0; /* empty */ | 1462 | di->udi_devnames[j][0] = 0; /* empty */ | |
1468 | 1463 | |||
1469 | if (dev->hub) { | 1464 | if (dev->hub) { | |
1470 | for (i = 0; | 1465 | for (i = 0; | |
1471 | i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) && | 1466 | i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) && | |
1472 | i < dev->hub->hubdesc.bNbrPorts; | 1467 | i < dev->hub->hubdesc.bNbrPorts; | |
1473 | i++) { | 1468 | i++) { | |
1474 | p = &dev->hub->ports[i]; | 1469 | p = &dev->hub->ports[i]; | |
1475 | if (p->device) | 1470 | if (p->device) | |
1476 | err = p->device->address; | 1471 | err = p->device->address; | |
1477 | else { | 1472 | else { | |
1478 | s = UGETW(p->status.wPortStatus); | 1473 | s = UGETW(p->status.wPortStatus); | |
1479 | if (s & UPS_PORT_ENABLED) | 1474 | if (s & UPS_PORT_ENABLED) | |
1480 | err = USB_PORT_ENABLED; | 1475 | err = USB_PORT_ENABLED; | |
1481 | else if (s & UPS_SUSPEND) | 1476 | else if (s & UPS_SUSPEND) | |
1482 | err = USB_PORT_SUSPENDED; | 1477 | err = USB_PORT_SUSPENDED; | |
1483 | else if (s & UPS_PORT_POWER) | 1478 | else if (s & UPS_PORT_POWER) | |
1484 | err = USB_PORT_POWERED; | 1479 | err = USB_PORT_POWERED; | |
1485 | else | 1480 | else | |
1486 | err = USB_PORT_DISABLED; | 1481 | err = USB_PORT_DISABLED; | |
1487 | } | 1482 | } | |
1488 | di->udi_ports[i] = err; | 1483 | di->udi_ports[i] = err; | |
1489 | } | 1484 | } | |
1490 | di->udi_nports = dev->hub->hubdesc.bNbrPorts; | 1485 | di->udi_nports = dev->hub->hubdesc.bNbrPorts; | |
1491 | } else | 1486 | } else | |
1492 | di->udi_nports = 0; | 1487 | di->udi_nports = 0; | |
1493 | } | 1488 | } | |
1494 | #endif | 1489 | #endif | |
1495 | 1490 | |||
1496 | 1491 | |||
1497 | void | 1492 | void | |
1498 | usb_free_device(usbd_device_handle dev) | 1493 | usb_free_device(usbd_device_handle dev) | |
1499 | { | 1494 | { | |
1500 | int ifcidx, nifc; | 1495 | int ifcidx, nifc; | |
1501 | 1496 | |||
1502 | if (dev->default_pipe != NULL) | 1497 | if (dev->default_pipe != NULL) | |
1503 | usbd_kill_pipe(dev->default_pipe); | 1498 | usbd_kill_pipe(dev->default_pipe); | |
1504 | if (dev->ifaces != NULL) { | 1499 | if (dev->ifaces != NULL) { | |
1505 | nifc = dev->cdesc->bNumInterface; | 1500 | nifc = dev->cdesc->bNumInterface; | |
1506 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) | 1501 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) | |
1507 | usbd_free_iface_data(dev, ifcidx); | 1502 | usbd_free_iface_data(dev, ifcidx); | |
1508 | free(dev->ifaces, M_USB); | 1503 | free(dev->ifaces, M_USB); | |
1509 | } | 1504 | } | |
1510 | if (dev->cdesc != NULL) | 1505 | if (dev->cdesc != NULL) | |
1511 | free(dev->cdesc, M_USB); | 1506 | free(dev->cdesc, M_USB); | |
1512 | if (dev->subdevlen > 0) { | 1507 | if (dev->subdevlen > 0) { | |
1513 | free(dev->subdevs, M_USB); | 1508 | free(dev->subdevs, M_USB); | |
1514 | dev->subdevlen = 0; | 1509 | dev->subdevlen = 0; | |
1515 | } | 1510 | } | |
1516 | free(dev, M_USB); | 1511 | free(dev, M_USB); | |
1517 | } | 1512 | } | |
1518 | 1513 | |||
1519 | /* | 1514 | /* | |
1520 | * The general mechanism for detaching drivers works as follows: Each | 1515 | * The general mechanism for detaching drivers works as follows: Each | |
1521 | * driver is responsible for maintaining a reference count on the | 1516 | * driver is responsible for maintaining a reference count on the | |
1522 | * number of outstanding references to its softc (e.g. from | 1517 | * number of outstanding references to its softc (e.g. from | |
1523 | * processing hanging in a read or write). The detach method of the | 1518 | * processing hanging in a read or write). The detach method of the | |
1524 | * driver decrements this counter and flags in the softc that the | 1519 | * driver decrements this counter and flags in the softc that the | |
1525 | * driver is dying and then wakes any sleepers. It then sleeps on the | 1520 | * driver is dying and then wakes any sleepers. It then sleeps on the | |
1526 | * softc. Each place that can sleep must maintain the reference | 1521 | * softc. Each place that can sleep must maintain the reference | |
1527 | * count. When the reference count drops to -1 (0 is the normal value | 1522 | * count. When the reference count drops to -1 (0 is the normal value | |
1528 | * of the reference count) the a wakeup on the softc is performed | 1523 | * of the reference count) the a wakeup on the softc is performed | |
1529 | * signaling to the detach waiter that all references are gone. | 1524 | * signaling to the detach waiter that all references are gone. | |
1530 | */ | 1525 | */ | |
1531 | 1526 | |||
1532 | /* | 1527 | /* | |
1533 | * Called from process context when we discover that a port has | 1528 | * Called from process context when we discover that a port has | |
1534 | * been disconnected. | 1529 | * been disconnected. | |
1535 | */ | 1530 | */ | |
1536 | int | 1531 | int | |
1537 | usb_disconnect_port(struct usbd_port *up, device_t parent, int flags) | 1532 | usb_disconnect_port(struct usbd_port *up, device_t parent, int flags) | |
1538 | { | 1533 | { | |
1539 | usbd_device_handle dev = up->device; | 1534 | usbd_device_handle dev = up->device; | |
1540 | device_t subdev; | 1535 | device_t subdev; | |
1541 | char subdevname[16]; | 1536 | char subdevname[16]; | |
1542 | const char *hubname = device_xname(parent); | 1537 | const char *hubname = device_xname(parent); | |
1543 | int i, rc; | 1538 | int i, rc; | |
1544 | 1539 | |||
1545 | DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n", | 1540 | DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n", | |
1546 | up, dev, up->portno)); | 1541 | up, dev, up->portno)); | |
1547 | 1542 | |||
1548 | if (dev == NULL) { | 1543 | if (dev == NULL) { | |
1549 | #ifdef DIAGNOSTIC | 1544 | #ifdef DIAGNOSTIC | |
1550 | printf("usb_disconnect_port: no device\n"); | 1545 | printf("usb_disconnect_port: no device\n"); | |
1551 | #endif | 1546 | #endif | |
1552 | return 0; | 1547 | return 0; | |
1553 | } | 1548 | } | |
1554 | 1549 | |||
1555 | if (dev->subdevlen > 0) { | 1550 | if (dev->subdevlen > 0) { | |
1556 | DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n")); | 1551 | DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n")); | |
1557 | for (i = 0; i < dev->subdevlen; i++) { | 1552 | for (i = 0; i < dev->subdevlen; i++) { | |
1558 | if ((subdev = dev->subdevs[i]) == NULL) | 1553 | if ((subdev = dev->subdevs[i]) == NULL) | |
1559 | continue; | 1554 | continue; | |
1560 | strlcpy(subdevname, device_xname(subdev), | 1555 | strlcpy(subdevname, device_xname(subdev), | |
1561 | sizeof(subdevname)); | 1556 | sizeof(subdevname)); | |
1562 | if ((rc = config_detach(subdev, flags)) != 0) | 1557 | if ((rc = config_detach(subdev, flags)) != 0) | |
1563 | return rc; | 1558 | return rc; | |
1564 | printf("%s: at %s", subdevname, hubname); | 1559 | printf("%s: at %s", subdevname, hubname); | |
1565 | if (up->portno != 0) | 1560 | if (up->portno != 0) | |
1566 | printf(" port %d", up->portno); | 1561 | printf(" port %d", up->portno); | |
1567 | printf(" (addr %d) disconnected\n", dev->address); | 1562 | printf(" (addr %d) disconnected\n", dev->address); | |
1568 | } | 1563 | } | |
1569 | KASSERT(!dev->nifaces_claimed); | 1564 | KASSERT(!dev->nifaces_claimed); | |
1570 | } | 1565 | } | |
1571 | 1566 | |||
1572 | usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev); | 1567 | usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev); | |
1573 | dev->bus->devices[dev->address] = NULL; | 1568 | dev->bus->devices[dev->address] = NULL; | |
1574 | up->device = NULL; | 1569 | up->device = NULL; | |
1575 | usb_free_device(dev); | 1570 | usb_free_device(dev); | |
1576 | return 0; | 1571 | return 0; | |
1577 | } | 1572 | } |
--- src/sys/dev/usb/usbdi.c 2011/12/04 13:23:17 1.134.2.1
+++ src/sys/dev/usb/usbdi.c 2011/12/08 02:51:08 1.134.2.2
@@ -1,1258 +1,1260 @@ | @@ -1,1258 +1,1260 @@ | |||
1 | /* $NetBSD: usbdi.c,v 1.134.2.1 2011/12/04 13:23:17 jmcneill Exp $ */ | 1 | /* $NetBSD: usbdi.c,v 1.134.2.2 2011/12/08 02:51:08 mrg Exp $ */ | |
2 | /* $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $ */ | 2 | /* $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | 5 | * Copyright (c) 1998 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 | #include <sys/cdefs.h> | 34 | #include <sys/cdefs.h> | |
35 | __KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.134.2.1 2011/12/04 13:23:17 jmcneill Exp $"); | 35 | __KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.134.2.2 2011/12/08 02:51:08 mrg Exp $"); | |
36 | 36 | |||
37 | #include "opt_compat_netbsd.h" | 37 | #include "opt_compat_netbsd.h" | |
38 | #include "opt_usb.h" | 38 | #include "opt_usb.h" | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/systm.h> | 41 | #include <sys/systm.h> | |
42 | #include <sys/kernel.h> | 42 | #include <sys/kernel.h> | |
43 | #include <sys/device.h> | 43 | #include <sys/device.h> | |
44 | #include <sys/malloc.h> | 44 | #include <sys/malloc.h> | |
45 | #include <sys/proc.h> | 45 | #include <sys/proc.h> | |
46 | 46 | |||
47 | #include <sys/bus.h> | 47 | #include <sys/bus.h> | |
48 | 48 | |||
49 | #include <dev/usb/usb.h> | 49 | #include <dev/usb/usb.h> | |
50 | #include <dev/usb/usbdi.h> | 50 | #include <dev/usb/usbdi.h> | |
51 | #include <dev/usb/usbdi_util.h> | 51 | #include <dev/usb/usbdi_util.h> | |
52 | #include <dev/usb/usbdivar.h> | 52 | #include <dev/usb/usbdivar.h> | |
53 | #include <dev/usb/usb_mem.h> | 53 | #include <dev/usb/usb_mem.h> | |
54 | #include <dev/usb/usb_quirks.h> | 54 | #include <dev/usb/usb_quirks.h> | |
55 | 55 | |||
56 | /* UTF-8 encoding stuff */ | 56 | /* UTF-8 encoding stuff */ | |
57 | #include <fs/unicode.h> | 57 | #include <fs/unicode.h> | |
58 | 58 | |||
59 | #ifdef USB_DEBUG | 59 | #ifdef USB_DEBUG | |
60 | #define DPRINTF(x) if (usbdebug) printf x | 60 | #define DPRINTF(x) if (usbdebug) printf x | |
61 | #define DPRINTFN(n,x) if (usbdebug>(n)) printf x | 61 | #define DPRINTFN(n,x) if (usbdebug>(n)) printf x | |
62 | extern int usbdebug; | 62 | extern int usbdebug; | |
63 | #else | 63 | #else | |
64 | #define DPRINTF(x) | 64 | #define DPRINTF(x) | |
65 | #define DPRINTFN(n,x) | 65 | #define DPRINTFN(n,x) | |
66 | #endif | 66 | #endif | |
67 | 67 | |||
68 | Static usbd_status usbd_ar_pipe(usbd_pipe_handle pipe); | 68 | Static usbd_status usbd_ar_pipe(usbd_pipe_handle pipe); | |
69 | Static void usbd_do_request_async_cb | 69 | Static void usbd_do_request_async_cb | |
70 | (usbd_xfer_handle, usbd_private_handle, usbd_status); | 70 | (usbd_xfer_handle, usbd_private_handle, usbd_status); | |
71 | Static void usbd_start_next(usbd_pipe_handle pipe); | 71 | Static void usbd_start_next(usbd_pipe_handle pipe); | |
72 | Static usbd_status usbd_open_pipe_ival | 72 | Static usbd_status usbd_open_pipe_ival | |
73 | (usbd_interface_handle, u_int8_t, u_int8_t, usbd_pipe_handle *, int); | 73 | (usbd_interface_handle, u_int8_t, u_int8_t, usbd_pipe_handle *, int); | |
74 | 74 | |||
75 | static inline int | 75 | static inline int | |
76 | usbd_xfer_isread(usbd_xfer_handle xfer) | 76 | usbd_xfer_isread(usbd_xfer_handle xfer) | |
77 | { | 77 | { | |
78 | if (xfer->rqflags & URQ_REQUEST) | 78 | if (xfer->rqflags & URQ_REQUEST) | |
79 | return (xfer->request.bmRequestType & UT_READ); | 79 | return (xfer->request.bmRequestType & UT_READ); | |
80 | else | 80 | else | |
81 | return (xfer->pipe->endpoint->edesc->bEndpointAddress & | 81 | return (xfer->pipe->endpoint->edesc->bEndpointAddress & | |
82 | UE_DIR_IN); | 82 | UE_DIR_IN); | |
83 | } | 83 | } | |
84 | 84 | |||
85 | #if defined(USB_DEBUG) || defined(EHCI_DEBUG) | 85 | #if defined(USB_DEBUG) || defined(EHCI_DEBUG) | |
86 | void | 86 | void | |
87 | usbd_dump_iface(struct usbd_interface *iface) | 87 | usbd_dump_iface(struct usbd_interface *iface) | |
88 | { | 88 | { | |
89 | printf("usbd_dump_iface: iface=%p\n", iface); | 89 | printf("usbd_dump_iface: iface=%p\n", iface); | |
90 | if (iface == NULL) | 90 | if (iface == NULL) | |
91 | return; | 91 | return; | |
92 | printf(" device=%p idesc=%p index=%d altindex=%d priv=%p\n", | 92 | printf(" device=%p idesc=%p index=%d altindex=%d priv=%p\n", | |
93 | iface->device, iface->idesc, iface->index, iface->altindex, | 93 | iface->device, iface->idesc, iface->index, iface->altindex, | |
94 | iface->priv); | 94 | iface->priv); | |
95 | } | 95 | } | |
96 | 96 | |||
97 | void | 97 | void | |
98 | usbd_dump_device(struct usbd_device *dev) | 98 | usbd_dump_device(struct usbd_device *dev) | |
99 | { | 99 | { | |
100 | printf("usbd_dump_device: dev=%p\n", dev); | 100 | printf("usbd_dump_device: dev=%p\n", dev); | |
101 | if (dev == NULL) | 101 | if (dev == NULL) | |
102 | return; | 102 | return; | |
103 | printf(" bus=%p default_pipe=%p\n", dev->bus, dev->default_pipe); | 103 | printf(" bus=%p default_pipe=%p\n", dev->bus, dev->default_pipe); | |
104 | printf(" address=%d config=%d depth=%d speed=%d self_powered=%d " | 104 | printf(" address=%d config=%d depth=%d speed=%d self_powered=%d " | |
105 | "power=%d langid=%d\n", | 105 | "power=%d langid=%d\n", | |
106 | dev->address, dev->config, dev->depth, dev->speed, | 106 | dev->address, dev->config, dev->depth, dev->speed, | |
107 | dev->self_powered, dev->power, dev->langid); | 107 | dev->self_powered, dev->power, dev->langid); | |
108 | } | 108 | } | |
109 | 109 | |||
110 | void | 110 | void | |
111 | usbd_dump_endpoint(struct usbd_endpoint *endp) | 111 | usbd_dump_endpoint(struct usbd_endpoint *endp) | |
112 | { | 112 | { | |
113 | printf("usbd_dump_endpoint: endp=%p\n", endp); | 113 | printf("usbd_dump_endpoint: endp=%p\n", endp); | |
114 | if (endp == NULL) | 114 | if (endp == NULL) | |
115 | return; | 115 | return; | |
116 | printf(" edesc=%p refcnt=%d\n", endp->edesc, endp->refcnt); | 116 | printf(" edesc=%p refcnt=%d\n", endp->edesc, endp->refcnt); | |
117 | if (endp->edesc) | 117 | if (endp->edesc) | |
118 | printf(" bEndpointAddress=0x%02x\n", | 118 | printf(" bEndpointAddress=0x%02x\n", | |
119 | endp->edesc->bEndpointAddress); | 119 | endp->edesc->bEndpointAddress); | |
120 | } | 120 | } | |
121 | 121 | |||
122 | void | 122 | void | |
123 | usbd_dump_queue(usbd_pipe_handle pipe) | 123 | usbd_dump_queue(usbd_pipe_handle pipe) | |
124 | { | 124 | { | |
125 | usbd_xfer_handle xfer; | 125 | usbd_xfer_handle xfer; | |
126 | 126 | |||
127 | printf("usbd_dump_queue: pipe=%p\n", pipe); | 127 | printf("usbd_dump_queue: pipe=%p\n", pipe); | |
128 | SIMPLEQ_FOREACH(xfer, &pipe->queue, next) { | 128 | SIMPLEQ_FOREACH(xfer, &pipe->queue, next) { | |
129 | printf(" xfer=%p\n", xfer); | 129 | printf(" xfer=%p\n", xfer); | |
130 | } | 130 | } | |
131 | } | 131 | } | |
132 | 132 | |||
133 | void | 133 | void | |
134 | usbd_dump_pipe(usbd_pipe_handle pipe) | 134 | usbd_dump_pipe(usbd_pipe_handle pipe) | |
135 | { | 135 | { | |
136 | printf("usbd_dump_pipe: pipe=%p\n", pipe); | 136 | printf("usbd_dump_pipe: pipe=%p\n", pipe); | |
137 | if (pipe == NULL) | 137 | if (pipe == NULL) | |
138 | return; | 138 | return; | |
139 | usbd_dump_iface(pipe->iface); | 139 | usbd_dump_iface(pipe->iface); | |
140 | usbd_dump_device(pipe->device); | 140 | usbd_dump_device(pipe->device); | |
141 | usbd_dump_endpoint(pipe->endpoint); | 141 | usbd_dump_endpoint(pipe->endpoint); | |
142 | printf(" (usbd_dump_pipe:)\n refcnt=%d running=%d aborting=%d\n", | 142 | printf(" (usbd_dump_pipe:)\n refcnt=%d running=%d aborting=%d\n", | |
143 | pipe->refcnt, pipe->running, pipe->aborting); | 143 | pipe->refcnt, pipe->running, pipe->aborting); | |
144 | printf(" intrxfer=%p, repeat=%d, interval=%d\n", | 144 | printf(" intrxfer=%p, repeat=%d, interval=%d\n", | |
145 | pipe->intrxfer, pipe->repeat, pipe->interval); | 145 | pipe->intrxfer, pipe->repeat, pipe->interval); | |
146 | } | 146 | } | |
147 | #endif | 147 | #endif | |
148 | 148 | |||
149 | usbd_status | 149 | usbd_status | |
150 | usbd_open_pipe(usbd_interface_handle iface, u_int8_t address, | 150 | usbd_open_pipe(usbd_interface_handle iface, u_int8_t address, | |
151 | u_int8_t flags, usbd_pipe_handle *pipe) | 151 | u_int8_t flags, usbd_pipe_handle *pipe) | |
152 | { | 152 | { | |
153 | return (usbd_open_pipe_ival(iface, address, flags, pipe, | 153 | return (usbd_open_pipe_ival(iface, address, flags, pipe, | |
154 | USBD_DEFAULT_INTERVAL)); | 154 | USBD_DEFAULT_INTERVAL)); | |
155 | } | 155 | } | |
156 | 156 | |||
157 | usbd_status | 157 | usbd_status | |
158 | usbd_open_pipe_ival(usbd_interface_handle iface, u_int8_t address, | 158 | usbd_open_pipe_ival(usbd_interface_handle iface, u_int8_t address, | |
159 | u_int8_t flags, usbd_pipe_handle *pipe, int ival) | 159 | u_int8_t flags, usbd_pipe_handle *pipe, int ival) | |
160 | { | 160 | { | |
161 | usbd_pipe_handle p; | 161 | usbd_pipe_handle p; | |
162 | struct usbd_endpoint *ep; | 162 | struct usbd_endpoint *ep; | |
163 | usbd_status err; | 163 | usbd_status err; | |
164 | int i; | 164 | int i; | |
165 | 165 | |||
166 | DPRINTFN(3,("usbd_open_pipe: iface=%p address=0x%x flags=0x%x\n", | 166 | DPRINTFN(3,("usbd_open_pipe: iface=%p address=0x%x flags=0x%x\n", | |
167 | iface, address, flags)); | 167 | iface, address, flags)); | |
168 | 168 | |||
169 | for (i = 0; i < iface->idesc->bNumEndpoints; i++) { | 169 | for (i = 0; i < iface->idesc->bNumEndpoints; i++) { | |
170 | ep = &iface->endpoints[i]; | 170 | ep = &iface->endpoints[i]; | |
171 | if (ep->edesc == NULL) | 171 | if (ep->edesc == NULL) | |
172 | return (USBD_IOERROR); | 172 | return (USBD_IOERROR); | |
173 | if (ep->edesc->bEndpointAddress == address) | 173 | if (ep->edesc->bEndpointAddress == address) | |
174 | goto found; | 174 | goto found; | |
175 | } | 175 | } | |
176 | return (USBD_BAD_ADDRESS); | 176 | return (USBD_BAD_ADDRESS); | |
177 | found: | 177 | found: | |
178 | if ((flags & USBD_EXCLUSIVE_USE) && ep->refcnt != 0) | 178 | if ((flags & USBD_EXCLUSIVE_USE) && ep->refcnt != 0) | |
179 | return (USBD_IN_USE); | 179 | return (USBD_IN_USE); | |
180 | err = usbd_setup_pipe(iface->device, iface, ep, ival, &p); | 180 | err = usbd_setup_pipe(iface->device, iface, ep, ival, &p); | |
181 | if (err) | 181 | if (err) | |
182 | return (err); | 182 | return (err); | |
183 | LIST_INSERT_HEAD(&iface->pipes, p, next); | 183 | LIST_INSERT_HEAD(&iface->pipes, p, next); | |
184 | *pipe = p; | 184 | *pipe = p; | |
185 | return (USBD_NORMAL_COMPLETION); | 185 | return (USBD_NORMAL_COMPLETION); | |
186 | } | 186 | } | |
187 | 187 | |||
188 | usbd_status | 188 | usbd_status | |
189 | usbd_open_pipe_intr(usbd_interface_handle iface, u_int8_t address, | 189 | usbd_open_pipe_intr(usbd_interface_handle iface, u_int8_t address, | |
190 | u_int8_t flags, usbd_pipe_handle *pipe, | 190 | u_int8_t flags, usbd_pipe_handle *pipe, | |
191 | usbd_private_handle priv, void *buffer, u_int32_t len, | 191 | usbd_private_handle priv, void *buffer, u_int32_t len, | |
192 | usbd_callback cb, int ival) | 192 | usbd_callback cb, int ival) | |
193 | { | 193 | { | |
194 | usbd_status err; | 194 | usbd_status err; | |
195 | usbd_xfer_handle xfer; | 195 | usbd_xfer_handle xfer; | |
196 | usbd_pipe_handle ipipe; | 196 | usbd_pipe_handle ipipe; | |
197 | 197 | |||
198 | DPRINTFN(3,("usbd_open_pipe_intr: address=0x%x flags=0x%x len=%d\n", | 198 | DPRINTFN(3,("usbd_open_pipe_intr: address=0x%x flags=0x%x len=%d\n", | |
199 | address, flags, len)); | 199 | address, flags, len)); | |
200 | 200 | |||
201 | err = usbd_open_pipe_ival(iface, address, USBD_EXCLUSIVE_USE, | 201 | err = usbd_open_pipe_ival(iface, address, USBD_EXCLUSIVE_USE, | |
202 | &ipipe, ival); | 202 | &ipipe, ival); | |
203 | if (err) | 203 | if (err) | |
204 | return (err); | 204 | return (err); | |
205 | xfer = usbd_alloc_xfer(iface->device); | 205 | xfer = usbd_alloc_xfer(iface->device); | |
206 | if (xfer == NULL) { | 206 | if (xfer == NULL) { | |
207 | err = USBD_NOMEM; | 207 | err = USBD_NOMEM; | |
208 | goto bad1; | 208 | goto bad1; | |
209 | } | 209 | } | |
210 | usbd_setup_xfer(xfer, ipipe, priv, buffer, len, flags, | 210 | usbd_setup_xfer(xfer, ipipe, priv, buffer, len, flags, | |
211 | USBD_NO_TIMEOUT, cb); | 211 | USBD_NO_TIMEOUT, cb); | |
212 | ipipe->intrxfer = xfer; | 212 | ipipe->intrxfer = xfer; | |
213 | ipipe->repeat = 1; | 213 | ipipe->repeat = 1; | |
214 | err = usbd_transfer(xfer); | 214 | err = usbd_transfer(xfer); | |
215 | *pipe = ipipe; | 215 | *pipe = ipipe; | |
216 | if (err != USBD_IN_PROGRESS) | 216 | if (err != USBD_IN_PROGRESS) | |
217 | goto bad2; | 217 | goto bad2; | |
218 | return (USBD_NORMAL_COMPLETION); | 218 | return (USBD_NORMAL_COMPLETION); | |
219 | 219 | |||
220 | bad2: | 220 | bad2: | |
221 | ipipe->intrxfer = NULL; | 221 | ipipe->intrxfer = NULL; | |
222 | ipipe->repeat = 0; | 222 | ipipe->repeat = 0; | |
223 | usbd_free_xfer(xfer); | 223 | usbd_free_xfer(xfer); | |
224 | bad1: | 224 | bad1: | |
225 | usbd_close_pipe(ipipe); | 225 | usbd_close_pipe(ipipe); | |
226 | return (err); | 226 | return (err); | |
227 | } | 227 | } | |
228 | 228 | |||
229 | usbd_status | 229 | usbd_status | |
230 | usbd_close_pipe(usbd_pipe_handle pipe) | 230 | usbd_close_pipe(usbd_pipe_handle pipe) | |
231 | { | 231 | { | |
232 | #ifdef DIAGNOSTIC | 232 | #ifdef DIAGNOSTIC | |
233 | if (pipe == NULL) { | 233 | if (pipe == NULL) { | |
234 | printf("usbd_close_pipe: pipe==NULL\n"); | 234 | printf("usbd_close_pipe: pipe==NULL\n"); | |
235 | return (USBD_NORMAL_COMPLETION); | 235 | return (USBD_NORMAL_COMPLETION); | |
236 | } | 236 | } | |
237 | #endif | 237 | #endif | |
238 | 238 | |||
239 | if (--pipe->refcnt != 0) | 239 | if (--pipe->refcnt != 0) | |
240 | return (USBD_NORMAL_COMPLETION); | 240 | return (USBD_NORMAL_COMPLETION); | |
241 | if (! SIMPLEQ_EMPTY(&pipe->queue)) | 241 | if (! SIMPLEQ_EMPTY(&pipe->queue)) | |
242 | return (USBD_PENDING_REQUESTS); | 242 | return (USBD_PENDING_REQUESTS); | |
243 | LIST_REMOVE(pipe, next); | 243 | LIST_REMOVE(pipe, next); | |
244 | pipe->endpoint->refcnt--; | 244 | pipe->endpoint->refcnt--; | |
245 | pipe->methods->close(pipe); | 245 | pipe->methods->close(pipe); | |
246 | if (pipe->intrxfer != NULL) | 246 | if (pipe->intrxfer != NULL) | |
247 | usbd_free_xfer(pipe->intrxfer); | 247 | usbd_free_xfer(pipe->intrxfer); | |
248 | free(pipe, M_USB); | 248 | free(pipe, M_USB); | |
249 | return (USBD_NORMAL_COMPLETION); | 249 | return (USBD_NORMAL_COMPLETION); | |
250 | } | 250 | } | |
251 | 251 | |||
252 | usbd_status | 252 | usbd_status | |
253 | usbd_transfer(usbd_xfer_handle xfer) | 253 | usbd_transfer(usbd_xfer_handle xfer) | |
254 | { | 254 | { | |
255 | usbd_pipe_handle pipe = xfer->pipe; | 255 | usbd_pipe_handle pipe = xfer->pipe; | |
256 | usb_dma_t *dmap = &xfer->dmabuf; | 256 | usb_dma_t *dmap = &xfer->dmabuf; | |
257 | usbd_status err; | 257 | usbd_status err; | |
258 | unsigned int size, flags; | 258 | unsigned int size, flags; | |
259 | int s; | 259 | int s; | |
260 | 260 | |||
261 | DPRINTFN(5,("usbd_transfer: xfer=%p, flags=%#x, pipe=%p, running=%d\n", | 261 | DPRINTFN(5,("usbd_transfer: xfer=%p, flags=%#x, pipe=%p, running=%d\n", | |
262 | xfer, xfer->flags, pipe, pipe->running)); | 262 | xfer, xfer->flags, pipe, pipe->running)); | |
263 | 263 | |||
264 | #ifdef USB_DEBUG | 264 | #ifdef USB_DEBUG | |
265 | if (usbdebug > 5) | 265 | if (usbdebug > 5) | |
266 | usbd_dump_queue(pipe); | 266 | usbd_dump_queue(pipe); | |
267 | #endif | 267 | #endif | |
268 | xfer->done = 0; | 268 | xfer->done = 0; | |
269 | 269 | |||
270 | if (pipe->aborting) | 270 | if (pipe->aborting) | |
271 | return (USBD_CANCELLED); | 271 | return (USBD_CANCELLED); | |
272 | 272 | |||
273 | size = xfer->length; | 273 | size = xfer->length; | |
274 | /* If there is no buffer, allocate one. */ | 274 | /* If there is no buffer, allocate one. */ | |
275 | if (!(xfer->rqflags & URQ_DEV_DMABUF) && size != 0) { | 275 | if (!(xfer->rqflags & URQ_DEV_DMABUF) && size != 0) { | |
276 | struct usbd_bus *bus = pipe->device->bus; | 276 | struct usbd_bus *bus = pipe->device->bus; | |
277 | 277 | |||
278 | #ifdef DIAGNOSTIC | 278 | #ifdef DIAGNOSTIC | |
279 | if (xfer->rqflags & URQ_AUTO_DMABUF) | 279 | if (xfer->rqflags & URQ_AUTO_DMABUF) | |
280 | printf("usbd_transfer: has old buffer!\n"); | 280 | printf("usbd_transfer: has old buffer!\n"); | |
281 | #endif | 281 | #endif | |
282 | err = bus->methods->allocm(bus, dmap, size); | 282 | err = bus->methods->allocm(bus, dmap, size); | |
283 | if (err) | 283 | if (err) | |
284 | return (err); | 284 | return (err); | |
285 | xfer->rqflags |= URQ_AUTO_DMABUF; | 285 | xfer->rqflags |= URQ_AUTO_DMABUF; | |
286 | } | 286 | } | |
287 | 287 | |||
288 | flags = xfer->flags; | 288 | flags = xfer->flags; | |
289 | 289 | |||
290 | /* Copy data if going out. */ | 290 | /* Copy data if going out. */ | |
291 | if (!(flags & USBD_NO_COPY) && size != 0 && !usbd_xfer_isread(xfer)) | 291 | if (!(flags & USBD_NO_COPY) && size != 0 && !usbd_xfer_isread(xfer)) | |
292 | memcpy(KERNADDR(dmap, 0), xfer->buffer, size); | 292 | memcpy(KERNADDR(dmap, 0), xfer->buffer, size); | |
293 | 293 | |||
294 | /* xfer is not valid after the transfer method unless synchronous */ | 294 | /* xfer is not valid after the transfer method unless synchronous */ | |
295 | err = pipe->methods->transfer(xfer); | 295 | err = pipe->methods->transfer(xfer); | |
296 | 296 | |||
297 | if (err != USBD_IN_PROGRESS && err) { | 297 | if (err != USBD_IN_PROGRESS && err) { | |
298 | /* The transfer has not been queued, so free buffer. */ | 298 | /* The transfer has not been queued, so free buffer. */ | |
299 | if (xfer->rqflags & URQ_AUTO_DMABUF) { | 299 | if (xfer->rqflags & URQ_AUTO_DMABUF) { | |
300 | struct usbd_bus *bus = pipe->device->bus; | 300 | struct usbd_bus *bus = pipe->device->bus; | |
301 | 301 | |||
302 | bus->methods->freem(bus, &xfer->dmabuf); | 302 | bus->methods->freem(bus, &xfer->dmabuf); | |
303 | xfer->rqflags &= ~URQ_AUTO_DMABUF; | 303 | xfer->rqflags &= ~URQ_AUTO_DMABUF; | |
304 | } | 304 | } | |
305 | } | 305 | } | |
306 | 306 | |||
307 | if (!(flags & USBD_SYNCHRONOUS)) | 307 | if (!(flags & USBD_SYNCHRONOUS)) | |
308 | return (err); | 308 | return (err); | |
309 | 309 | |||
310 | /* Sync transfer, wait for completion. */ | 310 | /* Sync transfer, wait for completion. */ | |
311 | if (err != USBD_IN_PROGRESS) | 311 | if (err != USBD_IN_PROGRESS) | |
312 | return (err); | 312 | return (err); | |
313 | usbd_lock(pipe->lock); | 313 | usbd_lock_pipe(pipe); | |
314 | if (!xfer->done) { | 314 | if (!xfer->done) { | |
315 | if (pipe->device->bus->use_polling) | 315 | if (pipe->device->bus->use_polling) | |
316 | panic("usbd_transfer: not done"); | 316 | panic("usbd_transfer: not done"); | |
317 | if (pipe->lock) { | 317 | if (pipe->device->bus->lock) { | |
318 | cv_wait(&xfer->cv, pipe->lock); | 318 | cv_wait(&xfer->cv, pipe->device->bus->lock); | |
319 | } else { | 319 | } else { | |
320 | tsleep(xfer, PRIBIO, "usbsyn", 0); | 320 | tsleep(xfer, PRIBIO, "usbsyn", 0); | |
321 | } | 321 | } | |
322 | } | 322 | } | |
323 | usbd_unlock(pipe->lock); | 323 | usbd_unlock_pipe(pipe); | |
324 | return (xfer->status); | 324 | return (xfer->status); | |
325 | } | 325 | } | |
326 | 326 | |||
327 | /* Like usbd_transfer(), but waits for completion. */ | 327 | /* Like usbd_transfer(), but waits for completion. */ | |
328 | usbd_status | 328 | usbd_status | |
329 | usbd_sync_transfer(usbd_xfer_handle xfer) | 329 | usbd_sync_transfer(usbd_xfer_handle xfer) | |
330 | { | 330 | { | |
331 | xfer->flags |= USBD_SYNCHRONOUS; | 331 | xfer->flags |= USBD_SYNCHRONOUS; | |
332 | return (usbd_transfer(xfer)); | 332 | return (usbd_transfer(xfer)); | |
333 | } | 333 | } | |
334 | 334 | |||
335 | void * | 335 | void * | |
336 | usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size) | 336 | usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size) | |
337 | { | 337 | { | |
338 | struct usbd_bus *bus = xfer->device->bus; | 338 | struct usbd_bus *bus = xfer->device->bus; | |
339 | usbd_status err; | 339 | usbd_status err; | |
340 | 340 | |||
341 | #ifdef DIAGNOSTIC | 341 | #ifdef DIAGNOSTIC | |
342 | if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) | 342 | if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) | |
343 | printf("usbd_alloc_buffer: xfer already has a buffer\n"); | 343 | printf("usbd_alloc_buffer: xfer already has a buffer\n"); | |
344 | #endif | 344 | #endif | |
345 | err = bus->methods->allocm(bus, &xfer->dmabuf, size); | 345 | err = bus->methods->allocm(bus, &xfer->dmabuf, size); | |
346 | if (err) | 346 | if (err) | |
347 | return (NULL); | 347 | return (NULL); | |
348 | xfer->rqflags |= URQ_DEV_DMABUF; | 348 | xfer->rqflags |= URQ_DEV_DMABUF; | |
349 | return (KERNADDR(&xfer->dmabuf, 0)); | 349 | return (KERNADDR(&xfer->dmabuf, 0)); | |
350 | } | 350 | } | |
351 | 351 | |||
352 | void | 352 | void | |
353 | usbd_free_buffer(usbd_xfer_handle xfer) | 353 | usbd_free_buffer(usbd_xfer_handle xfer) | |
354 | { | 354 | { | |
355 | #ifdef DIAGNOSTIC | 355 | #ifdef DIAGNOSTIC | |
356 | if (!(xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))) { | 356 | if (!(xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))) { | |
357 | printf("usbd_free_buffer: no buffer\n"); | 357 | printf("usbd_free_buffer: no buffer\n"); | |
358 | return; | 358 | return; | |
359 | } | 359 | } | |
360 | #endif | 360 | #endif | |
361 | xfer->rqflags &= ~(URQ_DEV_DMABUF | URQ_AUTO_DMABUF); | 361 | xfer->rqflags &= ~(URQ_DEV_DMABUF | URQ_AUTO_DMABUF); | |
362 | xfer->device->bus->methods->freem(xfer->device->bus, &xfer->dmabuf); | 362 | xfer->device->bus->methods->freem(xfer->device->bus, &xfer->dmabuf); | |
363 | } | 363 | } | |
364 | 364 | |||
365 | void * | 365 | void * | |
366 | usbd_get_buffer(usbd_xfer_handle xfer) | 366 | usbd_get_buffer(usbd_xfer_handle xfer) | |
367 | { | 367 | { | |
368 | if (!(xfer->rqflags & URQ_DEV_DMABUF)) | 368 | if (!(xfer->rqflags & URQ_DEV_DMABUF)) | |
369 | return (0); | 369 | return (0); | |
370 | return (KERNADDR(&xfer->dmabuf, 0)); | 370 | return (KERNADDR(&xfer->dmabuf, 0)); | |
371 | } | 371 | } | |
372 | 372 | |||
373 | usbd_xfer_handle | 373 | usbd_xfer_handle | |
374 | usbd_alloc_xfer(usbd_device_handle dev) | 374 | usbd_alloc_xfer(usbd_device_handle dev) | |
375 | { | 375 | { | |
376 | usbd_xfer_handle xfer; | 376 | usbd_xfer_handle xfer; | |
377 | 377 | |||
378 | xfer = dev->bus->methods->allocx(dev->bus); | 378 | xfer = dev->bus->methods->allocx(dev->bus); | |
379 | if (xfer == NULL) | 379 | if (xfer == NULL) | |
380 | return (NULL); | 380 | return (NULL); | |
381 | xfer->device = dev; | 381 | xfer->device = dev; | |
382 | callout_init(&xfer->timeout_handle, 0); | 382 | callout_init(&xfer->timeout_handle, 0); | |
383 | cv_init(&xfer->cv, "usbxfer"); | 383 | cv_init(&xfer->cv, "usbxfer"); | |
384 | cv_init(&xfer->hccv, "usbhcxfer"); | 384 | cv_init(&xfer->hccv, "usbhcxfer"); | |
385 | DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer)); | 385 | DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer)); | |
386 | return (xfer); | 386 | return (xfer); | |
387 | } | 387 | } | |
388 | 388 | |||
389 | usbd_status | 389 | usbd_status | |
390 | usbd_free_xfer(usbd_xfer_handle xfer) | 390 | usbd_free_xfer(usbd_xfer_handle xfer) | |
391 | { | 391 | { | |
392 | DPRINTFN(5,("usbd_free_xfer: %p\n", xfer)); | 392 | DPRINTFN(5,("usbd_free_xfer: %p\n", xfer)); | |
393 | if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) | 393 | if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) | |
394 | usbd_free_buffer(xfer); | 394 | usbd_free_buffer(xfer); | |
395 | #if defined(DIAGNOSTIC) | 395 | #if defined(DIAGNOSTIC) | |
396 | if (callout_pending(&xfer->timeout_handle)) { | 396 | if (callout_pending(&xfer->timeout_handle)) { | |
397 | callout_stop(&xfer->timeout_handle); | 397 | callout_stop(&xfer->timeout_handle); | |
398 | printf("usbd_free_xfer: timout_handle pending"); | 398 | printf("usbd_free_xfer: timout_handle pending"); | |
399 | } | 399 | } | |
400 | #endif | 400 | #endif | |
401 | cv_destroy(&xfer->cv); | 401 | cv_destroy(&xfer->cv); | |
402 | cv_destroy(&xfer->hccv); | 402 | cv_destroy(&xfer->hccv); | |
403 | xfer->device->bus->methods->freex(xfer->device->bus, xfer); | 403 | xfer->device->bus->methods->freex(xfer->device->bus, xfer); | |
404 | return (USBD_NORMAL_COMPLETION); | 404 | return (USBD_NORMAL_COMPLETION); | |
405 | } | 405 | } | |
406 | 406 | |||
407 | void | 407 | void | |
408 | usbd_setup_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, | 408 | usbd_setup_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, | |
409 | usbd_private_handle priv, void *buffer, u_int32_t length, | 409 | usbd_private_handle priv, void *buffer, u_int32_t length, | |
410 | u_int16_t flags, u_int32_t timeout, | 410 | u_int16_t flags, u_int32_t timeout, | |
411 | usbd_callback callback) | 411 | usbd_callback callback) | |
412 | { | 412 | { | |
413 | xfer->pipe = pipe; | 413 | xfer->pipe = pipe; | |
414 | xfer->priv = priv; | 414 | xfer->priv = priv; | |
415 | xfer->buffer = buffer; | 415 | xfer->buffer = buffer; | |
416 | xfer->length = length; | 416 | xfer->length = length; | |
417 | xfer->actlen = 0; | 417 | xfer->actlen = 0; | |
418 | xfer->flags = flags; | 418 | xfer->flags = flags; | |
419 | xfer->timeout = timeout; | 419 | xfer->timeout = timeout; | |
420 | xfer->status = USBD_NOT_STARTED; | 420 | xfer->status = USBD_NOT_STARTED; | |
421 | xfer->callback = callback; | 421 | xfer->callback = callback; | |
422 | xfer->rqflags &= ~URQ_REQUEST; | 422 | xfer->rqflags &= ~URQ_REQUEST; | |
423 | xfer->nframes = 0; | 423 | xfer->nframes = 0; | |
424 | } | 424 | } | |
425 | 425 | |||
426 | void | 426 | void | |
427 | usbd_setup_default_xfer(usbd_xfer_handle xfer, usbd_device_handle dev, | 427 | usbd_setup_default_xfer(usbd_xfer_handle xfer, usbd_device_handle dev, | |
428 | usbd_private_handle priv, u_int32_t timeout, | 428 | usbd_private_handle priv, u_int32_t timeout, | |
429 | usb_device_request_t *req, void *buffer, | 429 | usb_device_request_t *req, void *buffer, | |
430 | u_int32_t length, u_int16_t flags, | 430 | u_int32_t length, u_int16_t flags, | |
431 | usbd_callback callback) | 431 | usbd_callback callback) | |
432 | { | 432 | { | |
433 | xfer->pipe = dev->default_pipe; | 433 | xfer->pipe = dev->default_pipe; | |
434 | xfer->priv = priv; | 434 | xfer->priv = priv; | |
435 | xfer->buffer = buffer; | 435 | xfer->buffer = buffer; | |
436 | xfer->length = length; | 436 | xfer->length = length; | |
437 | xfer->actlen = 0; | 437 | xfer->actlen = 0; | |
438 | xfer->flags = flags; | 438 | xfer->flags = flags; | |
439 | xfer->timeout = timeout; | 439 | xfer->timeout = timeout; | |
440 | xfer->status = USBD_NOT_STARTED; | 440 | xfer->status = USBD_NOT_STARTED; | |
441 | xfer->callback = callback; | 441 | xfer->callback = callback; | |
442 | xfer->request = *req; | 442 | xfer->request = *req; | |
443 | xfer->rqflags |= URQ_REQUEST; | 443 | xfer->rqflags |= URQ_REQUEST; | |
444 | xfer->nframes = 0; | 444 | xfer->nframes = 0; | |
445 | } | 445 | } | |
446 | 446 | |||
447 | void | 447 | void | |
448 | usbd_setup_isoc_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, | 448 | usbd_setup_isoc_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, | |
449 | usbd_private_handle priv, u_int16_t *frlengths, | 449 | usbd_private_handle priv, u_int16_t *frlengths, | |
450 | u_int32_t nframes, u_int16_t flags, usbd_callback callback) | 450 | u_int32_t nframes, u_int16_t flags, usbd_callback callback) | |
451 | { | 451 | { | |
452 | xfer->pipe = pipe; | 452 | xfer->pipe = pipe; | |
453 | xfer->priv = priv; | 453 | xfer->priv = priv; | |
454 | xfer->buffer = 0; | 454 | xfer->buffer = 0; | |
455 | xfer->length = 0; | 455 | xfer->length = 0; | |
456 | xfer->actlen = 0; | 456 | xfer->actlen = 0; | |
457 | xfer->flags = flags; | 457 | xfer->flags = flags; | |
458 | xfer->timeout = USBD_NO_TIMEOUT; | 458 | xfer->timeout = USBD_NO_TIMEOUT; | |
459 | xfer->status = USBD_NOT_STARTED; | 459 | xfer->status = USBD_NOT_STARTED; | |
460 | xfer->callback = callback; | 460 | xfer->callback = callback; | |
461 | xfer->rqflags &= ~URQ_REQUEST; | 461 | xfer->rqflags &= ~URQ_REQUEST; | |
462 | xfer->frlengths = frlengths; | 462 | xfer->frlengths = frlengths; | |
463 | xfer->nframes = nframes; | 463 | xfer->nframes = nframes; | |
464 | } | 464 | } | |
465 | 465 | |||
466 | void | 466 | void | |
467 | usbd_get_xfer_status(usbd_xfer_handle xfer, usbd_private_handle *priv, | 467 | usbd_get_xfer_status(usbd_xfer_handle xfer, usbd_private_handle *priv, | |
468 | void **buffer, u_int32_t *count, usbd_status *status) | 468 | void **buffer, u_int32_t *count, usbd_status *status) | |
469 | { | 469 | { | |
470 | if (priv != NULL) | 470 | if (priv != NULL) | |
471 | *priv = xfer->priv; | 471 | *priv = xfer->priv; | |
472 | if (buffer != NULL) | 472 | if (buffer != NULL) | |
473 | *buffer = xfer->buffer; | 473 | *buffer = xfer->buffer; | |
474 | if (count != NULL) | 474 | if (count != NULL) | |
475 | *count = xfer->actlen; | 475 | *count = xfer->actlen; | |
476 | if (status != NULL) | 476 | if (status != NULL) | |
477 | *status = xfer->status; | 477 | *status = xfer->status; | |
478 | } | 478 | } | |
479 | 479 | |||
480 | usb_config_descriptor_t * | 480 | usb_config_descriptor_t * | |
481 | usbd_get_config_descriptor(usbd_device_handle dev) | 481 | usbd_get_config_descriptor(usbd_device_handle dev) | |
482 | { | 482 | { | |
483 | #ifdef DIAGNOSTIC | 483 | #ifdef DIAGNOSTIC | |
484 | if (dev == NULL) { | 484 | if (dev == NULL) { | |
485 | printf("usbd_get_config_descriptor: dev == NULL\n"); | 485 | printf("usbd_get_config_descriptor: dev == NULL\n"); | |
486 | return (NULL); | 486 | return (NULL); | |
487 | } | 487 | } | |
488 | #endif | 488 | #endif | |
489 | return (dev->cdesc); | 489 | return (dev->cdesc); | |
490 | } | 490 | } | |
491 | 491 | |||
492 | usb_interface_descriptor_t * | 492 | usb_interface_descriptor_t * | |
493 | usbd_get_interface_descriptor(usbd_interface_handle iface) | 493 | usbd_get_interface_descriptor(usbd_interface_handle iface) | |
494 | { | 494 | { | |
495 | #ifdef DIAGNOSTIC | 495 | #ifdef DIAGNOSTIC | |
496 | if (iface == NULL) { | 496 | if (iface == NULL) { | |
497 | printf("usbd_get_interface_descriptor: dev == NULL\n"); | 497 | printf("usbd_get_interface_descriptor: dev == NULL\n"); | |
498 | return (NULL); | 498 | return (NULL); | |
499 | } | 499 | } | |
500 | #endif | 500 | #endif | |
501 | return (iface->idesc); | 501 | return (iface->idesc); | |
502 | } | 502 | } | |
503 | 503 | |||
504 | usb_device_descriptor_t * | 504 | usb_device_descriptor_t * | |
505 | usbd_get_device_descriptor(usbd_device_handle dev) | 505 | usbd_get_device_descriptor(usbd_device_handle dev) | |
506 | { | 506 | { | |
507 | return (&dev->ddesc); | 507 | return (&dev->ddesc); | |
508 | } | 508 | } | |
509 | 509 | |||
510 | usb_endpoint_descriptor_t * | 510 | usb_endpoint_descriptor_t * | |
511 | usbd_interface2endpoint_descriptor(usbd_interface_handle iface, u_int8_t index) | 511 | usbd_interface2endpoint_descriptor(usbd_interface_handle iface, u_int8_t index) | |
512 | { | 512 | { | |
513 | if (index >= iface->idesc->bNumEndpoints) | 513 | if (index >= iface->idesc->bNumEndpoints) | |
514 | return (0); | 514 | return (0); | |
515 | return (iface->endpoints[index].edesc); | 515 | return (iface->endpoints[index].edesc); | |
516 | } | 516 | } | |
517 | 517 | |||
518 | /* Some drivers may wish to abort requests on the default pipe, * | 518 | /* Some drivers may wish to abort requests on the default pipe, * | |
519 | * but there is no mechanism for getting a handle on it. */ | 519 | * but there is no mechanism for getting a handle on it. */ | |
520 | usbd_status | 520 | usbd_status | |
521 | usbd_abort_default_pipe(struct usbd_device *device) | 521 | usbd_abort_default_pipe(struct usbd_device *device) | |
522 | { | 522 | { | |
523 | 523 | |||
524 | return usbd_abort_pipe(device->default_pipe); | 524 | return usbd_abort_pipe(device->default_pipe); | |
525 | } | 525 | } | |
526 | 526 | |||
527 | usbd_status | 527 | usbd_status | |
528 | usbd_abort_pipe(usbd_pipe_handle pipe) | 528 | usbd_abort_pipe(usbd_pipe_handle pipe) | |
529 | { | 529 | { | |
530 | usbd_status err; | 530 | usbd_status err; | |
531 | int s; | 531 | int s; | |
532 | usbd_xfer_handle intrxfer = pipe->intrxfer; | 532 | usbd_xfer_handle intrxfer = pipe->intrxfer; | |
533 | 533 | |||
534 | #ifdef DIAGNOSTIC | 534 | #ifdef DIAGNOSTIC | |
535 | if (pipe == NULL) { | 535 | if (pipe == NULL) { | |
536 | printf("usbd_abort_pipe: pipe==NULL\n"); | 536 | printf("usbd_abort_pipe: pipe==NULL\n"); | |
537 | return (USBD_NORMAL_COMPLETION); | 537 | return (USBD_NORMAL_COMPLETION); | |
538 | } | 538 | } | |
539 | #endif | 539 | #endif | |
540 | usbd_lock(pipe->lock); | 540 | usbd_lock_pipe(pipe); | |
541 | err = usbd_ar_pipe(pipe); | 541 | err = usbd_ar_pipe(pipe); | |
542 | usbd_unlock(pipe->lock); | 542 | usbd_unlock_pipe(pipe); | |
543 | if (pipe->intrxfer != intrxfer) | 543 | if (pipe->intrxfer != intrxfer) | |
544 | usbd_free_xfer(intrxfer); | 544 | usbd_free_xfer(intrxfer); | |
545 | return (err); | 545 | return (err); | |
546 | } | 546 | } | |
547 | 547 | |||
548 | usbd_status | 548 | usbd_status | |
549 | usbd_clear_endpoint_stall(usbd_pipe_handle pipe) | 549 | usbd_clear_endpoint_stall(usbd_pipe_handle pipe) | |
550 | { | 550 | { | |
551 | usbd_device_handle dev = pipe->device; | 551 | usbd_device_handle dev = pipe->device; | |
552 | usb_device_request_t req; | 552 | usb_device_request_t req; | |
553 | usbd_status err; | 553 | usbd_status err; | |
554 | 554 | |||
555 | DPRINTFN(8, ("usbd_clear_endpoint_stall\n")); | 555 | DPRINTFN(8, ("usbd_clear_endpoint_stall\n")); | |
556 | 556 | |||
557 | /* | 557 | /* | |
558 | * Clearing en endpoint stall resets the endpoint toggle, so | 558 | * Clearing en endpoint stall resets the endpoint toggle, so | |
559 | * do the same to the HC toggle. | 559 | * do the same to the HC toggle. | |
560 | */ | 560 | */ | |
561 | pipe->methods->cleartoggle(pipe); | 561 | pipe->methods->cleartoggle(pipe); | |
562 | 562 | |||
563 | req.bmRequestType = UT_WRITE_ENDPOINT; | 563 | req.bmRequestType = UT_WRITE_ENDPOINT; | |
564 | req.bRequest = UR_CLEAR_FEATURE; | 564 | req.bRequest = UR_CLEAR_FEATURE; | |
565 | USETW(req.wValue, UF_ENDPOINT_HALT); | 565 | USETW(req.wValue, UF_ENDPOINT_HALT); | |
566 | USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); | 566 | USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); | |
567 | USETW(req.wLength, 0); | 567 | USETW(req.wLength, 0); | |
568 | err = usbd_do_request(dev, &req, 0); | 568 | err = usbd_do_request(dev, &req, 0); | |
569 | #if 0 | 569 | #if 0 | |
570 | XXX should we do this? | 570 | XXX should we do this? | |
571 | if (!err) { | 571 | if (!err) { | |
572 | pipe->state = USBD_PIPE_ACTIVE; | 572 | pipe->state = USBD_PIPE_ACTIVE; | |
573 | /* XXX activate pipe */ | 573 | /* XXX activate pipe */ | |
574 | } | 574 | } | |
575 | #endif | 575 | #endif | |
576 | return (err); | 576 | return (err); | |
577 | } | 577 | } | |
578 | 578 | |||
579 | usbd_status | 579 | usbd_status | |
580 | usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe) | 580 | usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe) | |
581 | { | 581 | { | |
582 | usbd_device_handle dev = pipe->device; | 582 | usbd_device_handle dev = pipe->device; | |
583 | usb_device_request_t req; | 583 | usb_device_request_t req; | |
584 | usbd_status err; | 584 | usbd_status err; | |
585 | 585 | |||
586 | pipe->methods->cleartoggle(pipe); | 586 | pipe->methods->cleartoggle(pipe); | |
587 | 587 | |||
588 | req.bmRequestType = UT_WRITE_ENDPOINT; | 588 | req.bmRequestType = UT_WRITE_ENDPOINT; | |
589 | req.bRequest = UR_CLEAR_FEATURE; | 589 | req.bRequest = UR_CLEAR_FEATURE; | |
590 | USETW(req.wValue, UF_ENDPOINT_HALT); | 590 | USETW(req.wValue, UF_ENDPOINT_HALT); | |
591 | USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); | 591 | USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); | |
592 | USETW(req.wLength, 0); | 592 | USETW(req.wLength, 0); | |
593 | err = usbd_do_request_async(dev, &req, 0); | 593 | err = usbd_do_request_async(dev, &req, 0); | |
594 | return (err); | 594 | return (err); | |
595 | } | 595 | } | |
596 | 596 | |||
597 | void | 597 | void | |
598 | usbd_clear_endpoint_toggle(usbd_pipe_handle pipe) | 598 | usbd_clear_endpoint_toggle(usbd_pipe_handle pipe) | |
599 | { | 599 | { | |
600 | pipe->methods->cleartoggle(pipe); | 600 | pipe->methods->cleartoggle(pipe); | |
601 | } | 601 | } | |
602 | 602 | |||
603 | usbd_status | 603 | usbd_status | |
604 | usbd_endpoint_count(usbd_interface_handle iface, u_int8_t *count) | 604 | usbd_endpoint_count(usbd_interface_handle iface, u_int8_t *count) | |
605 | { | 605 | { | |
606 | #ifdef DIAGNOSTIC | 606 | #ifdef DIAGNOSTIC | |
607 | if (iface == NULL || iface->idesc == NULL) { | 607 | if (iface == NULL || iface->idesc == NULL) { | |
608 | printf("usbd_endpoint_count: NULL pointer\n"); | 608 | printf("usbd_endpoint_count: NULL pointer\n"); | |
609 | return (USBD_INVAL); | 609 | return (USBD_INVAL); | |
610 | } | 610 | } | |
611 | #endif | 611 | #endif | |
612 | *count = iface->idesc->bNumEndpoints; | 612 | *count = iface->idesc->bNumEndpoints; | |
613 | return (USBD_NORMAL_COMPLETION); | 613 | return (USBD_NORMAL_COMPLETION); | |
614 | } | 614 | } | |
615 | 615 | |||
616 | usbd_status | 616 | usbd_status | |
617 | usbd_interface_count(usbd_device_handle dev, u_int8_t *count) | 617 | usbd_interface_count(usbd_device_handle dev, u_int8_t *count) | |
618 | { | 618 | { | |
619 | if (dev->cdesc == NULL) | 619 | if (dev->cdesc == NULL) | |
620 | return (USBD_NOT_CONFIGURED); | 620 | return (USBD_NOT_CONFIGURED); | |
621 | *count = dev->cdesc->bNumInterface; | 621 | *count = dev->cdesc->bNumInterface; | |
622 | return (USBD_NORMAL_COMPLETION); | 622 | return (USBD_NORMAL_COMPLETION); | |
623 | } | 623 | } | |
624 | 624 | |||
625 | void | 625 | void | |
626 | usbd_interface2device_handle(usbd_interface_handle iface, | 626 | usbd_interface2device_handle(usbd_interface_handle iface, | |
627 | usbd_device_handle *dev) | 627 | usbd_device_handle *dev) | |
628 | { | 628 | { | |
629 | *dev = iface->device; | 629 | *dev = iface->device; | |
630 | } | 630 | } | |
631 | 631 | |||
632 | usbd_status | 632 | usbd_status | |
633 | usbd_device2interface_handle(usbd_device_handle dev, | 633 | usbd_device2interface_handle(usbd_device_handle dev, | |
634 | u_int8_t ifaceno, usbd_interface_handle *iface) | 634 | u_int8_t ifaceno, usbd_interface_handle *iface) | |
635 | { | 635 | { | |
636 | if (dev->cdesc == NULL) | 636 | if (dev->cdesc == NULL) | |
637 | return (USBD_NOT_CONFIGURED); | 637 | return (USBD_NOT_CONFIGURED); | |
638 | if (ifaceno >= dev->cdesc->bNumInterface) | 638 | if (ifaceno >= dev->cdesc->bNumInterface) | |
639 | return (USBD_INVAL); | 639 | return (USBD_INVAL); | |
640 | *iface = &dev->ifaces[ifaceno]; | 640 | *iface = &dev->ifaces[ifaceno]; | |
641 | return (USBD_NORMAL_COMPLETION); | 641 | return (USBD_NORMAL_COMPLETION); | |
642 | } | 642 | } | |
643 | 643 | |||
644 | usbd_device_handle | 644 | usbd_device_handle | |
645 | usbd_pipe2device_handle(usbd_pipe_handle pipe) | 645 | usbd_pipe2device_handle(usbd_pipe_handle pipe) | |
646 | { | 646 | { | |
647 | return (pipe->device); | 647 | return (pipe->device); | |
648 | } | 648 | } | |
649 | 649 | |||
650 | /* XXXX use altno */ | 650 | /* XXXX use altno */ | |
651 | usbd_status | 651 | usbd_status | |
652 | usbd_set_interface(usbd_interface_handle iface, int altidx) | 652 | usbd_set_interface(usbd_interface_handle iface, int altidx) | |
653 | { | 653 | { | |
654 | usb_device_request_t req; | 654 | usb_device_request_t req; | |
655 | usbd_status err; | 655 | usbd_status err; | |
656 | void *endpoints; | 656 | void *endpoints; | |
657 | 657 | |||
658 | if (LIST_FIRST(&iface->pipes) != 0) | 658 | if (LIST_FIRST(&iface->pipes) != 0) | |
659 | return (USBD_IN_USE); | 659 | return (USBD_IN_USE); | |
660 | 660 | |||
661 | endpoints = iface->endpoints; | 661 | endpoints = iface->endpoints; | |
662 | err = usbd_fill_iface_data(iface->device, iface->index, altidx); | 662 | err = usbd_fill_iface_data(iface->device, iface->index, altidx); | |
663 | if (err) | 663 | if (err) | |
664 | return (err); | 664 | return (err); | |
665 | 665 | |||
666 | /* new setting works, we can free old endpoints */ | 666 | /* new setting works, we can free old endpoints */ | |
667 | if (endpoints != NULL) | 667 | if (endpoints != NULL) | |
668 | free(endpoints, M_USB); | 668 | free(endpoints, M_USB); | |
669 | 669 | |||
670 | #ifdef DIAGNOSTIC | 670 | #ifdef DIAGNOSTIC | |
671 | if (iface->idesc == NULL) { | 671 | if (iface->idesc == NULL) { | |
672 | printf("usbd_set_interface: NULL pointer\n"); | 672 | printf("usbd_set_interface: NULL pointer\n"); | |
673 | return (USBD_INVAL); | 673 | return (USBD_INVAL); | |
674 | } | 674 | } | |
675 | #endif | 675 | #endif | |
676 | 676 | |||
677 | req.bmRequestType = UT_WRITE_INTERFACE; | 677 | req.bmRequestType = UT_WRITE_INTERFACE; | |
678 | req.bRequest = UR_SET_INTERFACE; | 678 | req.bRequest = UR_SET_INTERFACE; | |
679 | USETW(req.wValue, iface->idesc->bAlternateSetting); | 679 | USETW(req.wValue, iface->idesc->bAlternateSetting); | |
680 | USETW(req.wIndex, iface->idesc->bInterfaceNumber); | 680 | USETW(req.wIndex, iface->idesc->bInterfaceNumber); | |
681 | USETW(req.wLength, 0); | 681 | USETW(req.wLength, 0); | |
682 | return (usbd_do_request(iface->device, &req, 0)); | 682 | return (usbd_do_request(iface->device, &req, 0)); | |
683 | } | 683 | } | |
684 | 684 | |||
685 | int | 685 | int | |
686 | usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno) | 686 | usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno) | |
687 | { | 687 | { | |
688 | char *p = (char *)cdesc; | 688 | char *p = (char *)cdesc; | |
689 | char *end = p + UGETW(cdesc->wTotalLength); | 689 | char *end = p + UGETW(cdesc->wTotalLength); | |
690 | usb_interface_descriptor_t *d; | 690 | usb_interface_descriptor_t *d; | |
691 | int n; | 691 | int n; | |
692 | 692 | |||
693 | for (n = 0; p < end; p += d->bLength) { | 693 | for (n = 0; p < end; p += d->bLength) { | |
694 | d = (usb_interface_descriptor_t *)p; | 694 | d = (usb_interface_descriptor_t *)p; | |
695 | if (p + d->bLength <= end && | 695 | if (p + d->bLength <= end && | |
696 | d->bDescriptorType == UDESC_INTERFACE && | 696 | d->bDescriptorType == UDESC_INTERFACE && | |
697 | d->bInterfaceNumber == ifaceno) | 697 | d->bInterfaceNumber == ifaceno) | |
698 | n++; | 698 | n++; | |
699 | } | 699 | } | |
700 | return (n); | 700 | return (n); | |
701 | } | 701 | } | |
702 | 702 | |||
703 | int | 703 | int | |
704 | usbd_get_interface_altindex(usbd_interface_handle iface) | 704 | usbd_get_interface_altindex(usbd_interface_handle iface) | |
705 | { | 705 | { | |
706 | return (iface->altindex); | 706 | return (iface->altindex); | |
707 | } | 707 | } | |
708 | 708 | |||
709 | usbd_status | 709 | usbd_status | |
710 | usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface) | 710 | usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface) | |
711 | { | 711 | { | |
712 | usb_device_request_t req; | 712 | usb_device_request_t req; | |
713 | 713 | |||
714 | req.bmRequestType = UT_READ_INTERFACE; | 714 | req.bmRequestType = UT_READ_INTERFACE; | |
715 | req.bRequest = UR_GET_INTERFACE; | 715 | req.bRequest = UR_GET_INTERFACE; | |
716 | USETW(req.wValue, 0); | 716 | USETW(req.wValue, 0); | |
717 | USETW(req.wIndex, iface->idesc->bInterfaceNumber); | 717 | USETW(req.wIndex, iface->idesc->bInterfaceNumber); | |
718 | USETW(req.wLength, 1); | 718 | USETW(req.wLength, 1); | |
719 | return (usbd_do_request(iface->device, &req, aiface)); | 719 | return (usbd_do_request(iface->device, &req, aiface)); | |
720 | } | 720 | } | |
721 | 721 | |||
722 | /*** Internal routines ***/ | 722 | /*** Internal routines ***/ | |
723 | 723 | |||
724 | /* Dequeue all pipe operations, called at splusb(). */ | 724 | /* Dequeue all pipe operations, called at splusb(). */ | |
725 | Static usbd_status | 725 | Static usbd_status | |
726 | usbd_ar_pipe(usbd_pipe_handle pipe) | 726 | usbd_ar_pipe(usbd_pipe_handle pipe) | |
727 | { | 727 | { | |
728 | usbd_xfer_handle xfer; | 728 | usbd_xfer_handle xfer; | |
729 | 729 | |||
730 | SPLUSBCHECK; | 730 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); | |
731 | KASSERT(pipe->lock == NULL || mutex_owned(pipe->lock)); | |||
732 | 731 | |||
733 | DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe)); | 732 | DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe)); | |
734 | #ifdef USB_DEBUG | 733 | #ifdef USB_DEBUG | |
735 | if (usbdebug > 5) | 734 | if (usbdebug > 5) | |
736 | usbd_dump_queue(pipe); | 735 | usbd_dump_queue(pipe); | |
737 | #endif | 736 | #endif | |
738 | pipe->repeat = 0; | 737 | pipe->repeat = 0; | |
739 | pipe->aborting = 1; | 738 | pipe->aborting = 1; | |
740 | while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) { | 739 | while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) { | |
741 | DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n", | 740 | DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n", | |
742 | pipe, xfer, pipe->methods)); | 741 | pipe, xfer, pipe->methods)); | |
743 | /* Make the HC abort it (and invoke the callback). */ | 742 | /* Make the HC abort it (and invoke the callback). */ | |
744 | if (pipe->lock) | 743 | if (pipe->device->bus->lock) | |
745 | mutex_exit(pipe->lock); | 744 | mutex_exit(pipe->device->bus->lock); | |
746 | pipe->methods->abort(xfer); | 745 | pipe->methods->abort(xfer); | |
747 | if (pipe->lock) | 746 | if (pipe->device->bus->lock) | |
748 | mutex_enter(pipe->lock); | 747 | mutex_enter(pipe->device->bus->lock); | |
749 | /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */ | 748 | /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */ | |
750 | } | 749 | } | |
751 | pipe->aborting = 0; | 750 | pipe->aborting = 0; | |
752 | return (USBD_NORMAL_COMPLETION); | 751 | return (USBD_NORMAL_COMPLETION); | |
753 | } | 752 | } | |
754 | 753 | |||
755 | /* Called at splusb() */ | 754 | /* Called at splusb() */ | |
756 | void | 755 | void | |
757 | usb_transfer_complete(usbd_xfer_handle xfer) | 756 | usb_transfer_complete(usbd_xfer_handle xfer) | |
758 | { | 757 | { | |
759 | usbd_pipe_handle pipe = xfer->pipe; | 758 | usbd_pipe_handle pipe = xfer->pipe; | |
760 | usb_dma_t *dmap = &xfer->dmabuf; | 759 | usb_dma_t *dmap = &xfer->dmabuf; | |
761 | int sync = xfer->flags & USBD_SYNCHRONOUS; | 760 | int sync = xfer->flags & USBD_SYNCHRONOUS; | |
762 | int erred = xfer->status == USBD_CANCELLED || | 761 | int erred = xfer->status == USBD_CANCELLED || | |
763 | xfer->status == USBD_TIMEOUT; | 762 | xfer->status == USBD_TIMEOUT; | |
764 | int repeat, polling; | 763 | int repeat, polling; | |
765 | 764 | |||
766 | SPLUSBCHECK; | |||
767 | 765 | |||
768 | DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d " | 766 | DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d " | |
769 | "actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen)); | 767 | "actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen)); | |
770 | 768 | |||
771 | KASSERT(pipe->lock == NULL || mutex_owned(pipe->lock)); | 769 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); | |
772 | 770 | |||
773 | #ifdef DIAGNOSTIC | 771 | #ifdef DIAGNOSTIC | |
774 | if (xfer->busy_free != XFER_ONQU) { | 772 | if (xfer->busy_free != XFER_ONQU) { | |
775 | printf("usb_transfer_complete: xfer=%p not busy 0x%08x\n", | 773 | printf("usb_transfer_complete: xfer=%p not busy 0x%08x\n", | |
776 | xfer, xfer->busy_free); | 774 | xfer, xfer->busy_free); | |
777 | } | 775 | } | |
778 | #endif | 776 | #endif | |
779 | 777 | |||
780 | #ifdef DIAGNOSTIC | 778 | #ifdef DIAGNOSTIC | |
781 | if (pipe == NULL) { | 779 | if (pipe == NULL) { | |
782 | printf("usbd_transfer_cb: pipe==0, xfer=%p\n", xfer); | 780 | printf("usbd_transfer_cb: pipe==0, xfer=%p\n", xfer); | |
783 | return; | 781 | return; | |
784 | } | 782 | } | |
785 | #endif | 783 | #endif | |
786 | repeat = pipe->repeat; | 784 | repeat = pipe->repeat; | |
787 | polling = pipe->device->bus->use_polling; | 785 | polling = pipe->device->bus->use_polling; | |
788 | /* XXXX */ | 786 | /* XXXX */ | |
789 | if (polling) | 787 | if (polling) | |
790 | pipe->running = 0; | 788 | pipe->running = 0; | |
791 | 789 | |||
792 | if (!(xfer->flags & USBD_NO_COPY) && xfer->actlen != 0 && | 790 | if (!(xfer->flags & USBD_NO_COPY) && xfer->actlen != 0 && | |
793 | usbd_xfer_isread(xfer)) { | 791 | usbd_xfer_isread(xfer)) { | |
794 | #ifdef DIAGNOSTIC | 792 | #ifdef DIAGNOSTIC | |
795 | if (xfer->actlen > xfer->length) { | 793 | if (xfer->actlen > xfer->length) { | |
796 | printf("usb_transfer_complete: actlen > len %d > %d\n", | 794 | printf("usb_transfer_complete: actlen > len %d > %d\n", | |
797 | xfer->actlen, xfer->length); | 795 | xfer->actlen, xfer->length); | |
798 | xfer->actlen = xfer->length; | 796 | xfer->actlen = xfer->length; | |
799 | } | 797 | } | |
800 | #endif | 798 | #endif | |
801 | memcpy(xfer->buffer, KERNADDR(dmap, 0), xfer->actlen); | 799 | memcpy(xfer->buffer, KERNADDR(dmap, 0), xfer->actlen); | |
802 | } | 800 | } | |
803 | 801 | |||
804 | /* if we allocated the buffer in usbd_transfer() we free it here. */ | 802 | /* if we allocated the buffer in usbd_transfer() we free it here. */ | |
805 | if (xfer->rqflags & URQ_AUTO_DMABUF) { | 803 | if (xfer->rqflags & URQ_AUTO_DMABUF) { | |
806 | if (!repeat) { | 804 | if (!repeat) { | |
807 | struct usbd_bus *bus = pipe->device->bus; | 805 | struct usbd_bus *bus = pipe->device->bus; | |
808 | bus->methods->freem(bus, dmap); | 806 | bus->methods->freem(bus, dmap); | |
809 | xfer->rqflags &= ~URQ_AUTO_DMABUF; | 807 | xfer->rqflags &= ~URQ_AUTO_DMABUF; | |
810 | } | 808 | } | |
811 | } | 809 | } | |
812 | 810 | |||
813 | if (!repeat) { | 811 | if (!repeat) { | |
814 | /* Remove request from queue. */ | 812 | /* Remove request from queue. */ | |
815 | #ifdef DIAGNOSTIC | 813 | #ifdef DIAGNOSTIC | |
816 | if (xfer != SIMPLEQ_FIRST(&pipe->queue)) | 814 | if (xfer != SIMPLEQ_FIRST(&pipe->queue)) | |
817 | printf("usb_transfer_complete: bad dequeue %p != %p\n", | 815 | printf("usb_transfer_complete: bad dequeue %p != %p\n", | |
818 | xfer, SIMPLEQ_FIRST(&pipe->queue)); | 816 | xfer, SIMPLEQ_FIRST(&pipe->queue)); | |
819 | xfer->busy_free = XFER_BUSY; | 817 | xfer->busy_free = XFER_BUSY; | |
820 | #endif | 818 | #endif | |
821 | SIMPLEQ_REMOVE_HEAD(&pipe->queue, next); | 819 | SIMPLEQ_REMOVE_HEAD(&pipe->queue, next); | |
822 | } | 820 | } | |
823 | DPRINTFN(5,("usb_transfer_complete: repeat=%d new head=%p\n", | 821 | DPRINTFN(5,("usb_transfer_complete: repeat=%d new head=%p\n", | |
824 | repeat, SIMPLEQ_FIRST(&pipe->queue))); | 822 | repeat, SIMPLEQ_FIRST(&pipe->queue))); | |
825 | 823 | |||
826 | /* Count completed transfers. */ | 824 | /* Count completed transfers. */ | |
827 | ++pipe->device->bus->stats.uds_requests | 825 | ++pipe->device->bus->stats.uds_requests | |
828 | [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE]; | 826 | [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE]; | |
829 | 827 | |||
830 | xfer->done = 1; | 828 | xfer->done = 1; | |
831 | if (!xfer->status && xfer->actlen < xfer->length && | 829 | if (!xfer->status && xfer->actlen < xfer->length && | |
832 | !(xfer->flags & USBD_SHORT_XFER_OK)) { | 830 | !(xfer->flags & USBD_SHORT_XFER_OK)) { | |
833 | DPRINTFN(-1,("usbd_transfer_cb: short transfer %d<%d\n", | 831 | DPRINTFN(-1,("usbd_transfer_cb: short transfer %d<%d\n", | |
834 | xfer->actlen, xfer->length)); | 832 | xfer->actlen, xfer->length)); | |
835 | xfer->status = USBD_SHORT_XFER; | 833 | xfer->status = USBD_SHORT_XFER; | |
836 | } | 834 | } | |
837 | 835 | |||
838 | if (repeat) { | 836 | if (repeat) { | |
839 | if (xfer->callback) { | 837 | if (xfer->callback) { | |
840 | if (pipe->lock) mutex_exit(pipe->lock); | 838 | if (pipe->device->bus->lock) | |
839 | mutex_exit(pipe->device->bus->lock); | |||
841 | xfer->callback(xfer, xfer->priv, xfer->status); | 840 | xfer->callback(xfer, xfer->priv, xfer->status); | |
842 | if (pipe->lock) mutex_enter(pipe->lock); | 841 | if (pipe->device->bus->lock) | |
842 | mutex_enter(pipe->device->bus->lock); | |||
843 | } | 843 | } | |
844 | pipe->methods->done(xfer); | 844 | pipe->methods->done(xfer); | |
845 | } else { | 845 | } else { | |
846 | pipe->methods->done(xfer); | 846 | pipe->methods->done(xfer); | |
847 | if (xfer->callback) { | 847 | if (xfer->callback) { | |
848 | if (pipe->lock) mutex_exit(pipe->lock); | 848 | if (pipe->device->bus->lock) | |
849 | mutex_exit(pipe->device->bus->lock); | |||
849 | xfer->callback(xfer, xfer->priv, xfer->status); | 850 | xfer->callback(xfer, xfer->priv, xfer->status); | |
850 | if (pipe->lock) mutex_enter(pipe->lock); | 851 | if (pipe->device->bus->lock) | |
852 | mutex_enter(pipe->device->bus->lock); | |||
851 | } | 853 | } | |
852 | } | 854 | } | |
853 | 855 | |||
854 | if (sync && !polling) { | 856 | if (sync && !polling) { | |
855 | if (pipe->lock) { | 857 | if (pipe->device->bus->lock) { | |
856 | cv_broadcast(&xfer->cv); | 858 | cv_broadcast(&xfer->cv); | |
857 | } else { | 859 | } else { | |
858 | wakeup(xfer); | 860 | wakeup(xfer); | |
859 | } | 861 | } | |
860 | } | 862 | } | |
861 | 863 | |||
862 | if (!repeat) { | 864 | if (!repeat) { | |
863 | /* XXX should we stop the queue on all errors? */ | 865 | /* XXX should we stop the queue on all errors? */ | |
864 | if (erred && pipe->iface != NULL) /* not control pipe */ | 866 | if (erred && pipe->iface != NULL) /* not control pipe */ | |
865 | pipe->running = 0; | 867 | pipe->running = 0; | |
866 | else | 868 | else | |
867 | usbd_start_next(pipe); | 869 | usbd_start_next(pipe); | |
868 | } | 870 | } | |
869 | } | 871 | } | |
870 | 872 | |||
871 | usbd_status | 873 | usbd_status | |
872 | usb_insert_transfer(usbd_xfer_handle xfer) | 874 | usb_insert_transfer(usbd_xfer_handle xfer) | |
873 | { | 875 | { | |
874 | usbd_pipe_handle pipe = xfer->pipe; | 876 | usbd_pipe_handle pipe = xfer->pipe; | |
875 | usbd_status err; | 877 | usbd_status err; | |
876 | int s; | 878 | int s; | |
877 | 879 | |||
878 | DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n", | 880 | DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n", | |
879 | pipe, pipe->running, xfer->timeout)); | 881 | pipe, pipe->running, xfer->timeout)); | |
880 | 882 | |||
881 | KASSERT(pipe->lock == NULL || mutex_owned(pipe->lock)); | 883 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); | |
882 | 884 | |||
883 | #ifdef DIAGNOSTIC | 885 | #ifdef DIAGNOSTIC | |
884 | if (xfer->busy_free != XFER_BUSY) { | 886 | if (xfer->busy_free != XFER_BUSY) { | |
885 | printf("usb_insert_transfer: xfer=%p not busy 0x%08x\n", | 887 | printf("usb_insert_transfer: xfer=%p not busy 0x%08x\n", | |
886 | xfer, xfer->busy_free); | 888 | xfer, xfer->busy_free); | |
887 | return (USBD_INVAL); | 889 | return (USBD_INVAL); | |
888 | } | 890 | } | |
889 | xfer->busy_free = XFER_ONQU; | 891 | xfer->busy_free = XFER_ONQU; | |
890 | #endif | 892 | #endif | |
891 | s = splusb(); | 893 | s = splusb(); | |
892 | SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next); | 894 | SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next); | |
893 | if (pipe->running) | 895 | if (pipe->running) | |
894 | err = USBD_IN_PROGRESS; | 896 | err = USBD_IN_PROGRESS; | |
895 | else { | 897 | else { | |
896 | pipe->running = 1; | 898 | pipe->running = 1; | |
897 | err = USBD_NORMAL_COMPLETION; | 899 | err = USBD_NORMAL_COMPLETION; | |
898 | } | 900 | } | |
899 | splx(s); | 901 | splx(s); | |
900 | return (err); | 902 | return (err); | |
901 | } | 903 | } | |
902 | 904 | |||
903 | /* Called at splusb() */ | 905 | /* Called at splusb() */ | |
904 | void | 906 | void | |
905 | usbd_start_next(usbd_pipe_handle pipe) | 907 | usbd_start_next(usbd_pipe_handle pipe) | |
906 | { | 908 | { | |
907 | usbd_xfer_handle xfer; | 909 | usbd_xfer_handle xfer; | |
908 | usbd_status err; | 910 | usbd_status err; | |
909 | 911 | |||
910 | SPLUSBCHECK; | 912 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); | |
911 | 913 | |||
912 | #ifdef DIAGNOSTIC | 914 | #ifdef DIAGNOSTIC | |
913 | if (pipe == NULL) { | 915 | if (pipe == NULL) { | |
914 | printf("usbd_start_next: pipe == NULL\n"); | 916 | printf("usbd_start_next: pipe == NULL\n"); | |
915 | return; | 917 | return; | |
916 | } | 918 | } | |
917 | if (pipe->methods == NULL || pipe->methods->start == NULL) { | 919 | if (pipe->methods == NULL || pipe->methods->start == NULL) { | |
918 | printf("usbd_start_next: pipe=%p no start method\n", pipe); | 920 | printf("usbd_start_next: pipe=%p no start method\n", pipe); | |
919 | return; | 921 | return; | |
920 | } | 922 | } | |
921 | #endif | 923 | #endif | |
922 | 924 | |||
923 | KASSERT(pipe->lock == NULL || mutex_owned(pipe->lock)); | 925 | KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock)); | |
924 | 926 | |||
925 | /* Get next request in queue. */ | 927 | /* Get next request in queue. */ | |
926 | xfer = SIMPLEQ_FIRST(&pipe->queue); | 928 | xfer = SIMPLEQ_FIRST(&pipe->queue); | |
927 | DPRINTFN(5, ("usbd_start_next: pipe=%p, xfer=%p\n", pipe, xfer)); | 929 | DPRINTFN(5, ("usbd_start_next: pipe=%p, xfer=%p\n", pipe, xfer)); | |
928 | if (xfer == NULL) { | 930 | if (xfer == NULL) { | |
929 | pipe->running = 0; | 931 | pipe->running = 0; | |
930 | } else { | 932 | } else { | |
931 | if (pipe->lock) | 933 | if (pipe->device->bus->lock) | |
932 | mutex_exit(pipe->lock); | 934 | mutex_exit(pipe->device->bus->lock); | |
933 | err = pipe->methods->start(xfer); | 935 | err = pipe->methods->start(xfer); | |
934 | if (pipe->lock) | 936 | if (pipe->device->bus->lock) | |
935 | mutex_enter(pipe->lock); | 937 | mutex_enter(pipe->device->bus->lock); | |
936 | if (err != USBD_IN_PROGRESS) { | 938 | if (err != USBD_IN_PROGRESS) { | |
937 | printf("usbd_start_next: error=%d\n", err); | 939 | printf("usbd_start_next: error=%d\n", err); | |
938 | pipe->running = 0; | 940 | pipe->running = 0; | |
939 | /* XXX do what? */ | 941 | /* XXX do what? */ | |
940 | } | 942 | } | |
941 | } | 943 | } | |
942 | } | 944 | } | |
943 | 945 | |||
944 | usbd_status | 946 | usbd_status | |
945 | usbd_do_request(usbd_device_handle dev, usb_device_request_t *req, void *data) | 947 | usbd_do_request(usbd_device_handle dev, usb_device_request_t *req, void *data) | |
946 | { | 948 | { | |
947 | return (usbd_do_request_flags(dev, req, data, 0, 0, | 949 | return (usbd_do_request_flags(dev, req, data, 0, 0, | |
948 | USBD_DEFAULT_TIMEOUT)); | 950 | USBD_DEFAULT_TIMEOUT)); | |
949 | } | 951 | } | |
950 | 952 | |||
951 | usbd_status | 953 | usbd_status | |
952 | usbd_do_request_flags(usbd_device_handle dev, usb_device_request_t *req, | 954 | usbd_do_request_flags(usbd_device_handle dev, usb_device_request_t *req, | |
953 | void *data, u_int16_t flags, int *actlen, u_int32_t timo) | 955 | void *data, u_int16_t flags, int *actlen, u_int32_t timo) | |
954 | { | 956 | { | |
955 | return (usbd_do_request_flags_pipe(dev, dev->default_pipe, req, | 957 | return (usbd_do_request_flags_pipe(dev, dev->default_pipe, req, | |
956 | data, flags, actlen, timo)); | 958 | data, flags, actlen, timo)); | |
957 | } | 959 | } | |
958 | 960 | |||
959 | usbd_status | 961 | usbd_status | |
960 | usbd_do_request_flags_pipe(usbd_device_handle dev, usbd_pipe_handle pipe, | 962 | usbd_do_request_flags_pipe(usbd_device_handle dev, usbd_pipe_handle pipe, | |
961 | usb_device_request_t *req, void *data, u_int16_t flags, int *actlen, | 963 | usb_device_request_t *req, void *data, u_int16_t flags, int *actlen, | |
962 | u_int32_t timeout) | 964 | u_int32_t timeout) | |
963 | { | 965 | { | |
964 | usbd_xfer_handle xfer; | 966 | usbd_xfer_handle xfer; | |
965 | usbd_status err; | 967 | usbd_status err; | |
966 | 968 | |||
967 | #ifdef DIAGNOSTIC | 969 | #ifdef DIAGNOSTIC | |
968 | if (dev->bus->intr_context) { | 970 | if (dev->bus->intr_context) { | |
969 | printf("usbd_do_request: not in process context\n"); | 971 | printf("usbd_do_request: not in process context\n"); | |
970 | return (USBD_INVAL); | 972 | return (USBD_INVAL); | |
971 | } | 973 | } | |
972 | #endif | 974 | #endif | |
973 | 975 | |||
974 | xfer = usbd_alloc_xfer(dev); | 976 | xfer = usbd_alloc_xfer(dev); | |
975 | if (xfer == NULL) | 977 | if (xfer == NULL) | |
976 | return (USBD_NOMEM); | 978 | return (USBD_NOMEM); | |
977 | usbd_setup_default_xfer(xfer, dev, 0, timeout, req, | 979 | usbd_setup_default_xfer(xfer, dev, 0, timeout, req, | |
978 | data, UGETW(req->wLength), flags, 0); | 980 | data, UGETW(req->wLength), flags, 0); | |
979 | xfer->pipe = pipe; | 981 | xfer->pipe = pipe; | |
980 | err = usbd_sync_transfer(xfer); | 982 | err = usbd_sync_transfer(xfer); | |
981 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) | 983 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) | |
982 | if (xfer->actlen > xfer->length) { | 984 | if (xfer->actlen > xfer->length) { | |
983 | DPRINTF(("%s: overrun addr=%d type=0x%02x req=0x" | 985 | DPRINTF(("%s: overrun addr=%d type=0x%02x req=0x" | |
984 | "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", | 986 | "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", | |
985 | __func__, dev->address, xfer->request.bmRequestType, | 987 | __func__, dev->address, xfer->request.bmRequestType, | |
986 | xfer->request.bRequest, UGETW(xfer->request.wValue), | 988 | xfer->request.bRequest, UGETW(xfer->request.wValue), | |
987 | UGETW(xfer->request.wIndex), | 989 | UGETW(xfer->request.wIndex), | |
988 | UGETW(xfer->request.wLength), | 990 | UGETW(xfer->request.wLength), | |
989 | xfer->length, xfer->actlen)); | 991 | xfer->length, xfer->actlen)); | |
990 | } | 992 | } | |
991 | #endif | 993 | #endif | |
992 | if (actlen != NULL) | 994 | if (actlen != NULL) | |
993 | *actlen = xfer->actlen; | 995 | *actlen = xfer->actlen; | |
994 | if (err == USBD_STALLED) { | 996 | if (err == USBD_STALLED) { | |
995 | /* | 997 | /* | |
996 | * The control endpoint has stalled. Control endpoints | 998 | * The control endpoint has stalled. Control endpoints | |
997 | * should not halt, but some may do so anyway so clear | 999 | * should not halt, but some may do so anyway so clear | |
998 | * any halt condition. | 1000 | * any halt condition. | |
999 | */ | 1001 | */ | |
1000 | usb_device_request_t treq; | 1002 | usb_device_request_t treq; | |
1001 | usb_status_t status; | 1003 | usb_status_t status; | |
1002 | u_int16_t s; | 1004 | u_int16_t s; | |
1003 | usbd_status nerr; | 1005 | usbd_status nerr; | |
1004 | 1006 | |||
1005 | treq.bmRequestType = UT_READ_ENDPOINT; | 1007 | treq.bmRequestType = UT_READ_ENDPOINT; | |
1006 | treq.bRequest = UR_GET_STATUS; | 1008 | treq.bRequest = UR_GET_STATUS; | |
1007 | USETW(treq.wValue, 0); | 1009 | USETW(treq.wValue, 0); | |
1008 | USETW(treq.wIndex, 0); | 1010 | USETW(treq.wIndex, 0); | |
1009 | USETW(treq.wLength, sizeof(usb_status_t)); | 1011 | USETW(treq.wLength, sizeof(usb_status_t)); | |
1010 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, | 1012 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, | |
1011 | &treq, &status,sizeof(usb_status_t), | 1013 | &treq, &status,sizeof(usb_status_t), | |
1012 | 0, 0); | 1014 | 0, 0); | |
1013 | nerr = usbd_sync_transfer(xfer); | 1015 | nerr = usbd_sync_transfer(xfer); | |
1014 | if (nerr) | 1016 | if (nerr) | |
1015 | goto bad; | 1017 | goto bad; | |
1016 | s = UGETW(status.wStatus); | 1018 | s = UGETW(status.wStatus); | |
1017 | DPRINTF(("usbd_do_request: status = 0x%04x\n", s)); | 1019 | DPRINTF(("usbd_do_request: status = 0x%04x\n", s)); | |
1018 | if (!(s & UES_HALT)) | 1020 | if (!(s & UES_HALT)) | |
1019 | goto bad; | 1021 | goto bad; | |
1020 | treq.bmRequestType = UT_WRITE_ENDPOINT; | 1022 | treq.bmRequestType = UT_WRITE_ENDPOINT; | |
1021 | treq.bRequest = UR_CLEAR_FEATURE; | 1023 | treq.bRequest = UR_CLEAR_FEATURE; | |
1022 | USETW(treq.wValue, UF_ENDPOINT_HALT); | 1024 | USETW(treq.wValue, UF_ENDPOINT_HALT); | |
1023 | USETW(treq.wIndex, 0); | 1025 | USETW(treq.wIndex, 0); | |
1024 | USETW(treq.wLength, 0); | 1026 | USETW(treq.wLength, 0); | |
1025 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, | 1027 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, | |
1026 | &treq, &status, 0, 0, 0); | 1028 | &treq, &status, 0, 0, 0); | |
1027 | nerr = usbd_sync_transfer(xfer); | 1029 | nerr = usbd_sync_transfer(xfer); | |
1028 | if (nerr) | 1030 | if (nerr) | |
1029 | goto bad; | 1031 | goto bad; | |
1030 | } | 1032 | } | |
1031 | 1033 | |||
1032 | bad: | 1034 | bad: | |
1033 | if (err) { | 1035 | if (err) { | |
1034 | DPRINTF(("%s: returning err=%s\n", __func__, usbd_errstr(err))); | 1036 | DPRINTF(("%s: returning err=%s\n", __func__, usbd_errstr(err))); | |
1035 | } | 1037 | } | |
1036 | usbd_free_xfer(xfer); | 1038 | usbd_free_xfer(xfer); | |
1037 | return (err); | 1039 | return (err); | |
1038 | } | 1040 | } | |
1039 | 1041 | |||
1040 | void | 1042 | void | |
1041 | usbd_do_request_async_cb(usbd_xfer_handle xfer, | 1043 | usbd_do_request_async_cb(usbd_xfer_handle xfer, | |
1042 | usbd_private_handle priv, usbd_status status) | 1044 | usbd_private_handle priv, usbd_status status) | |
1043 | { | 1045 | { | |
1044 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) | 1046 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) | |
1045 | if (xfer->actlen > xfer->length) { | 1047 | if (xfer->actlen > xfer->length) { | |
1046 | DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x" | 1048 | DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x" | |
1047 | "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", | 1049 | "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", | |
1048 | xfer->pipe->device->address, | 1050 | xfer->pipe->device->address, | |
1049 | xfer->request.bmRequestType, | 1051 | xfer->request.bmRequestType, | |
1050 | xfer->request.bRequest, UGETW(xfer->request.wValue), | 1052 | xfer->request.bRequest, UGETW(xfer->request.wValue), | |
1051 | UGETW(xfer->request.wIndex), | 1053 | UGETW(xfer->request.wIndex), | |
1052 | UGETW(xfer->request.wLength), | 1054 | UGETW(xfer->request.wLength), | |
1053 | xfer->length, xfer->actlen)); | 1055 | xfer->length, xfer->actlen)); | |
1054 | } | 1056 | } | |
1055 | #endif | 1057 | #endif | |
1056 | usbd_free_xfer(xfer); | 1058 | usbd_free_xfer(xfer); | |
1057 | } | 1059 | } | |
1058 | 1060 | |||
1059 | /* | 1061 | /* | |
1060 | * Execute a request without waiting for completion. | 1062 | * Execute a request without waiting for completion. | |
1061 | * Can be used from interrupt context. | 1063 | * Can be used from interrupt context. | |
1062 | */ | 1064 | */ | |
1063 | usbd_status | 1065 | usbd_status | |
1064 | usbd_do_request_async(usbd_device_handle dev, usb_device_request_t *req, | 1066 | usbd_do_request_async(usbd_device_handle dev, usb_device_request_t *req, | |
1065 | void *data) | 1067 | void *data) | |
1066 | { | 1068 | { | |
1067 | usbd_xfer_handle xfer; | 1069 | usbd_xfer_handle xfer; | |
1068 | usbd_status err; | 1070 | usbd_status err; | |
1069 | 1071 | |||
1070 | xfer = usbd_alloc_xfer(dev); | 1072 | xfer = usbd_alloc_xfer(dev); | |
1071 | if (xfer == NULL) | 1073 | if (xfer == NULL) | |
1072 | return (USBD_NOMEM); | 1074 | return (USBD_NOMEM); | |
1073 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, req, | 1075 | usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, req, | |
1074 | data, UGETW(req->wLength), 0, usbd_do_request_async_cb); | 1076 | data, UGETW(req->wLength), 0, usbd_do_request_async_cb); | |
1075 | err = usbd_transfer(xfer); | 1077 | err = usbd_transfer(xfer); | |
1076 | if (err != USBD_IN_PROGRESS) { | 1078 | if (err != USBD_IN_PROGRESS) { | |
1077 | usbd_free_xfer(xfer); | 1079 | usbd_free_xfer(xfer); | |
1078 | return (err); | 1080 | return (err); | |
1079 | } | 1081 | } | |
1080 | return (USBD_NORMAL_COMPLETION); | 1082 | return (USBD_NORMAL_COMPLETION); | |
1081 | } | 1083 | } | |
1082 | 1084 | |||
1083 | const struct usbd_quirks * | 1085 | const struct usbd_quirks * | |
1084 | usbd_get_quirks(usbd_device_handle dev) | 1086 | usbd_get_quirks(usbd_device_handle dev) | |
1085 | { | 1087 | { | |
1086 | #ifdef DIAGNOSTIC | 1088 | #ifdef DIAGNOSTIC | |
1087 | if (dev == NULL) { | 1089 | if (dev == NULL) { | |
1088 | printf("usbd_get_quirks: dev == NULL\n"); | 1090 | printf("usbd_get_quirks: dev == NULL\n"); | |
1089 | return 0; | 1091 | return 0; | |
1090 | } | 1092 | } | |
1091 | #endif | 1093 | #endif | |
1092 | return (dev->quirks); | 1094 | return (dev->quirks); | |
1093 | } | 1095 | } | |
1094 | 1096 | |||
1095 | /* XXX do periodic free() of free list */ | 1097 | /* XXX do periodic free() of free list */ | |
1096 | 1098 | |||
1097 | /* | 1099 | /* | |
1098 | * Called from keyboard driver when in polling mode. | 1100 | * Called from keyboard driver when in polling mode. | |
1099 | */ | 1101 | */ | |
1100 | void | 1102 | void | |
1101 | usbd_dopoll(usbd_interface_handle iface) | 1103 | usbd_dopoll(usbd_interface_handle iface) | |
1102 | { | 1104 | { | |
1103 | iface->device->bus->methods->do_poll(iface->device->bus); | 1105 | iface->device->bus->methods->do_poll(iface->device->bus); | |
1104 | } | 1106 | } | |
1105 | 1107 | |||
1106 | void | 1108 | void | |
1107 | usbd_set_polling(usbd_device_handle dev, int on) | 1109 | usbd_set_polling(usbd_device_handle dev, int on) | |
1108 | { | 1110 | { | |
1109 | if (on) | 1111 | if (on) | |
1110 | dev->bus->use_polling++; | 1112 | dev->bus->use_polling++; | |
1111 | else | 1113 | else | |
1112 | dev->bus->use_polling--; | 1114 | dev->bus->use_polling--; | |
1113 | 1115 | |||
1114 | /* Kick the host controller when switching modes */ | 1116 | /* Kick the host controller when switching modes */ | |
1115 | dev->bus->methods->soft_intr(dev->bus); | 1117 | dev->bus->methods->soft_intr(dev->bus); | |
1116 | } | 1118 | } | |
1117 | 1119 | |||
1118 | 1120 | |||
1119 | usb_endpoint_descriptor_t * | 1121 | usb_endpoint_descriptor_t * | |
1120 | usbd_get_endpoint_descriptor(usbd_interface_handle iface, u_int8_t address) | 1122 | usbd_get_endpoint_descriptor(usbd_interface_handle iface, u_int8_t address) | |
1121 | { | 1123 | { | |
1122 | struct usbd_endpoint *ep; | 1124 | struct usbd_endpoint *ep; | |
1123 | int i; | 1125 | int i; | |
1124 | 1126 | |||
1125 | for (i = 0; i < iface->idesc->bNumEndpoints; i++) { | 1127 | for (i = 0; i < iface->idesc->bNumEndpoints; i++) { | |
1126 | ep = &iface->endpoints[i]; | 1128 | ep = &iface->endpoints[i]; | |
1127 | if (ep->edesc->bEndpointAddress == address) | 1129 | if (ep->edesc->bEndpointAddress == address) | |
1128 | return (iface->endpoints[i].edesc); | 1130 | return (iface->endpoints[i].edesc); | |
1129 | } | 1131 | } | |
1130 | return (0); | 1132 | return (0); | |
1131 | } | 1133 | } | |
1132 | 1134 | |||
1133 | /* | 1135 | /* | |
1134 | * usbd_ratecheck() can limit the number of error messages that occurs. | 1136 | * usbd_ratecheck() can limit the number of error messages that occurs. | |
1135 | * When a device is unplugged it may take up to 0.25s for the hub driver | 1137 | * When a device is unplugged it may take up to 0.25s for the hub driver | |
1136 | * to notice it. If the driver continuosly tries to do I/O operations | 1138 | * to notice it. If the driver continuosly tries to do I/O operations | |
1137 | * this can generate a large number of messages. | 1139 | * this can generate a large number of messages. | |
1138 | */ | 1140 | */ | |
1139 | int | 1141 | int | |
1140 | usbd_ratecheck(struct timeval *last) | 1142 | usbd_ratecheck(struct timeval *last) | |
1141 | { | 1143 | { | |
1142 | static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/ | 1144 | static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/ | |
1143 | 1145 | |||
1144 | return (ratecheck(last, &errinterval)); | 1146 | return (ratecheck(last, &errinterval)); | |
1145 | } | 1147 | } | |
1146 | 1148 | |||
1147 | /* | 1149 | /* | |
1148 | * Search for a vendor/product pair in an array. The item size is | 1150 | * Search for a vendor/product pair in an array. The item size is | |
1149 | * given as an argument. | 1151 | * given as an argument. | |
1150 | */ | 1152 | */ | |
1151 | const struct usb_devno * | 1153 | const struct usb_devno * | |
1152 | usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz, | 1154 | usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz, | |
1153 | u_int16_t vendor, u_int16_t product) | 1155 | u_int16_t vendor, u_int16_t product) | |
1154 | { | 1156 | { | |
1155 | while (nentries-- > 0) { | 1157 | while (nentries-- > 0) { | |
1156 | u_int16_t tproduct = tbl->ud_product; | 1158 | u_int16_t tproduct = tbl->ud_product; | |
1157 | if (tbl->ud_vendor == vendor && | 1159 | if (tbl->ud_vendor == vendor && | |
1158 | (tproduct == product || tproduct == USB_PRODUCT_ANY)) | 1160 | (tproduct == product || tproduct == USB_PRODUCT_ANY)) | |
1159 | return (tbl); | 1161 | return (tbl); | |
1160 | tbl = (const struct usb_devno *)((const char *)tbl + sz); | 1162 | tbl = (const struct usb_devno *)((const char *)tbl + sz); | |
1161 | } | 1163 | } | |
1162 | return (NULL); | 1164 | return (NULL); | |
1163 | } | 1165 | } | |
1164 | 1166 | |||
1165 | 1167 | |||
1166 | void | 1168 | void | |
1167 | usb_desc_iter_init(usbd_device_handle dev, usbd_desc_iter_t *iter) | 1169 | usb_desc_iter_init(usbd_device_handle dev, usbd_desc_iter_t *iter) | |
1168 | { | 1170 | { | |
1169 | const usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev); | 1171 | const usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev); | |
1170 | 1172 | |||
1171 | iter->cur = (const uByte *)cd; | 1173 | iter->cur = (const uByte *)cd; | |
1172 | iter->end = (const uByte *)cd + UGETW(cd->wTotalLength); | 1174 | iter->end = (const uByte *)cd + UGETW(cd->wTotalLength); | |
1173 | } | 1175 | } | |
1174 | 1176 | |||
1175 | const usb_descriptor_t * | 1177 | const usb_descriptor_t * | |
1176 | usb_desc_iter_next(usbd_desc_iter_t *iter) | 1178 | usb_desc_iter_next(usbd_desc_iter_t *iter) | |
1177 | { | 1179 | { | |
1178 | const usb_descriptor_t *desc; | 1180 | const usb_descriptor_t *desc; | |
1179 | 1181 | |||
1180 | if (iter->cur + sizeof(usb_descriptor_t) >= iter->end) { | 1182 | if (iter->cur + sizeof(usb_descriptor_t) >= iter->end) { | |
1181 | if (iter->cur != iter->end) | 1183 | if (iter->cur != iter->end) | |
1182 | printf("usb_desc_iter_next: bad descriptor\n"); | 1184 | printf("usb_desc_iter_next: bad descriptor\n"); | |
1183 | return NULL; | 1185 | return NULL; | |
1184 | } | 1186 | } | |
1185 | desc = (const usb_descriptor_t *)iter->cur; | 1187 | desc = (const usb_descriptor_t *)iter->cur; | |
1186 | if (desc->bLength == 0) { | 1188 | if (desc->bLength == 0) { | |
1187 | printf("usb_desc_iter_next: descriptor length = 0\n"); | 1189 | printf("usb_desc_iter_next: descriptor length = 0\n"); | |
1188 | return NULL; | 1190 | return NULL; | |
1189 | } | 1191 | } | |
1190 | iter->cur += desc->bLength; | 1192 | iter->cur += desc->bLength; | |
1191 | if (iter->cur > iter->end) { | 1193 | if (iter->cur > iter->end) { | |
1192 | printf("usb_desc_iter_next: descriptor length too large\n"); | 1194 | printf("usb_desc_iter_next: descriptor length too large\n"); | |
1193 | return NULL; | 1195 | return NULL; | |
1194 | } | 1196 | } | |
1195 | return desc; | 1197 | return desc; | |
1196 | } | 1198 | } | |
1197 | 1199 | |||
1198 | usbd_status | 1200 | usbd_status | |
1199 | usbd_get_string(usbd_device_handle dev, int si, char *buf) | 1201 | usbd_get_string(usbd_device_handle dev, int si, char *buf) | |
1200 | { | 1202 | { | |
1201 | return usbd_get_string0(dev, si, buf, 1); | 1203 | return usbd_get_string0(dev, si, buf, 1); | |
1202 | } | 1204 | } | |
1203 | 1205 | |||
1204 | usbd_status | 1206 | usbd_status | |
1205 | usbd_get_string0(usbd_device_handle dev, int si, char *buf, int unicode) | 1207 | usbd_get_string0(usbd_device_handle dev, int si, char *buf, int unicode) | |
1206 | { | 1208 | { | |
1207 | int swap = dev->quirks->uq_flags & UQ_SWAP_UNICODE; | 1209 | int swap = dev->quirks->uq_flags & UQ_SWAP_UNICODE; | |
1208 | usb_string_descriptor_t us; | 1210 | usb_string_descriptor_t us; | |
1209 | char *s; | 1211 | char *s; | |
1210 | int i, n; | 1212 | int i, n; | |
1211 | u_int16_t c; | 1213 | u_int16_t c; | |
1212 | usbd_status err; | 1214 | usbd_status err; | |
1213 | int size; | 1215 | int size; | |
1214 | 1216 | |||
1215 | buf[0] = '\0'; | 1217 | buf[0] = '\0'; | |
1216 | if (si == 0) | 1218 | if (si == 0) | |
1217 | return (USBD_INVAL); | 1219 | return (USBD_INVAL); | |
1218 | if (dev->quirks->uq_flags & UQ_NO_STRINGS) | 1220 | if (dev->quirks->uq_flags & UQ_NO_STRINGS) | |
1219 | return (USBD_STALLED); | 1221 | return (USBD_STALLED); | |
1220 | if (dev->langid == USBD_NOLANG) { | 1222 | if (dev->langid == USBD_NOLANG) { | |
1221 | /* Set up default language */ | 1223 | /* Set up default language */ | |
1222 | err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us, | 1224 | err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us, | |
1223 | &size); | 1225 | &size); | |
1224 | if (err || size < 4) { | 1226 | if (err || size < 4) { | |
1225 | DPRINTFN(-1,("usbd_get_string: getting lang failed, using 0\n")); | 1227 | DPRINTFN(-1,("usbd_get_string: getting lang failed, using 0\n")); | |
1226 | dev->langid = 0; /* Well, just pick something then */ | 1228 | dev->langid = 0; /* Well, just pick something then */ | |
1227 | } else { | 1229 | } else { | |
1228 | /* Pick the first language as the default. */ | 1230 | /* Pick the first language as the default. */ | |
1229 | dev->langid = UGETW(us.bString[0]); | 1231 | dev->langid = UGETW(us.bString[0]); | |
1230 | } | 1232 | } | |
1231 | } | 1233 | } | |
1232 | err = usbd_get_string_desc(dev, si, dev->langid, &us, &size); | 1234 | err = usbd_get_string_desc(dev, si, dev->langid, &us, &size); | |
1233 | if (err) | 1235 | if (err) | |
1234 | return (err); | 1236 | return (err); | |
1235 | s = buf; | 1237 | s = buf; | |
1236 | n = size / 2 - 1; | 1238 | n = size / 2 - 1; | |
1237 | if (unicode) { | 1239 | if (unicode) { | |
1238 | for (i = 0; i < n; i++) { | 1240 | for (i = 0; i < n; i++) { | |
1239 | c = UGETW(us.bString[i]); | 1241 | c = UGETW(us.bString[i]); | |
1240 | if (swap) | 1242 | if (swap) | |
1241 | c = (c >> 8) | (c << 8); | 1243 | c = (c >> 8) | (c << 8); | |
1242 | s += wput_utf8(s, 3, c); | 1244 | s += wput_utf8(s, 3, c); | |
1243 | } | 1245 | } | |
1244 | *s++ = 0; | 1246 | *s++ = 0; | |
1245 | } | 1247 | } | |
1246 | #ifdef COMPAT_30 | 1248 | #ifdef COMPAT_30 | |
1247 | else { | 1249 | else { | |
1248 | for (i = 0; i < n; i++) { | 1250 | for (i = 0; i < n; i++) { | |
1249 | c = UGETW(us.bString[i]); | 1251 | c = UGETW(us.bString[i]); | |
1250 | if (swap) | 1252 | if (swap) | |
1251 | c = (c >> 8) | (c << 8); | 1253 | c = (c >> 8) | (c << 8); | |
1252 | *s++ = (c < 0x80) ? c : '?'; | 1254 | *s++ = (c < 0x80) ? c : '?'; | |
1253 | } | 1255 | } | |
1254 | *s++ = 0; | 1256 | *s++ = 0; | |
1255 | } | 1257 | } | |
1256 | #endif | 1258 | #endif | |
1257 | return (USBD_NORMAL_COMPLETION); | 1259 | return (USBD_NORMAL_COMPLETION); | |
1258 | } | 1260 | } |
--- src/sys/dev/usb/usbdivar.h 2011/12/04 13:23:17 1.93.8.1
+++ src/sys/dev/usb/usbdivar.h 2011/12/08 02:51:08 1.93.8.2
@@ -1,285 +1,318 @@ | @@ -1,285 +1,318 @@ | |||
1 | /* $NetBSD: usbdivar.h,v 1.93.8.1 2011/12/04 13:23:17 jmcneill Exp $ */ | 1 | /* $NetBSD: usbdivar.h,v 1.93.8.2 2011/12/08 02:51:08 mrg Exp $ */ | |
2 | /* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */ | 2 | /* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | 5 | * Copyright (c) 1998 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 | #include <sys/callout.h> | 34 | #include <sys/callout.h> | |
35 | #include <sys/mutex.h> | 35 | #include <sys/mutex.h> | |
36 | 36 | |||
37 | /* | |||
38 | * Discussion about locking in the USB code: | |||
39 | * | |||
40 | * There are two locks presented by the host controller: the interrupt lock | |||
41 | * and the thread lock. The interrupt lock, either a spin or adaptive mutex, | |||
42 | * manages hardware state and anything else touched in an interrupt context. | |||
43 | * The thread lock has everything else. | |||
44 | * | |||
45 | * List of hardware interface methods, and which locks are held when each | |||
46 | * is called by this module: | |||
47 | * | |||
48 | * BUS METHOD INTR THREAD NOTES | |||
49 | * ----------------------- ------- ------- ------------------------- | |||
50 | * open_pipe - - might want to take thread lock? | |||
51 | * soft_intr - - intr lock is taken sometimes, thread lock taken often, but nothing demanded? | |||
52 | * do_poll - - might want to take thread lock? | |||
53 | * allocm - - | |||
54 | * freem - - | |||
55 | * allocx - - | |||
56 | * freex - - | |||
57 | * get_locks - - Called at attach time | |||
58 | * | |||
59 | * PIPE METHOD INTR THREAD NOTES | |||
60 | * ----------------------- ------- ------- ------------------------- | |||
61 | * transfer - - | |||
62 | * start - - | |||
63 | * abort - - | |||
64 | * close - - | |||
65 | * cleartoggle - - | |||
66 | * done - x | |||
67 | * | |||
68 | * The above semantics are likely to change. | |||
69 | * | |||
70 | */ | |||
71 | ||||
37 | /* From usb_mem.h */ | 72 | /* From usb_mem.h */ | |
38 | struct usb_dma_block; | 73 | struct usb_dma_block; | |
39 | typedef struct { | 74 | typedef struct { | |
40 | struct usb_dma_block *block; | 75 | struct usb_dma_block *block; | |
41 | u_int offs; | 76 | u_int offs; | |
42 | } usb_dma_t; | 77 | } usb_dma_t; | |
43 | 78 | |||
44 | struct usbd_xfer; | 79 | struct usbd_xfer; | |
45 | struct usbd_pipe; | 80 | struct usbd_pipe; | |
46 | 81 | |||
47 | struct usbd_endpoint { | 82 | struct usbd_endpoint { | |
48 | usb_endpoint_descriptor_t *edesc; | 83 | usb_endpoint_descriptor_t *edesc; | |
49 | int refcnt; | 84 | int refcnt; | |
50 | int datatoggle; | 85 | int datatoggle; | |
51 | }; | 86 | }; | |
52 | 87 | |||
53 | struct usbd_bus_methods { | 88 | struct usbd_bus_methods { | |
54 | usbd_status (*open_pipe)(struct usbd_pipe *pipe); | 89 | usbd_status (*open_pipe)(struct usbd_pipe *pipe); | |
55 | void (*soft_intr)(void *); | 90 | void (*soft_intr)(void *); | |
56 | void (*do_poll)(struct usbd_bus *); | 91 | void (*do_poll)(struct usbd_bus *); | |
57 | usbd_status (*allocm)(struct usbd_bus *, usb_dma_t *, | 92 | usbd_status (*allocm)(struct usbd_bus *, usb_dma_t *, | |
58 | u_int32_t bufsize); | 93 | u_int32_t bufsize); | |
59 | void (*freem)(struct usbd_bus *, usb_dma_t *); | 94 | void (*freem)(struct usbd_bus *, usb_dma_t *); | |
60 | struct usbd_xfer * (*allocx)(struct usbd_bus *); | 95 | struct usbd_xfer * (*allocx)(struct usbd_bus *); | |
61 | void (*freex)(struct usbd_bus *, struct usbd_xfer *); | 96 | void (*freex)(struct usbd_bus *, struct usbd_xfer *); | |
62 | void (*get_locks)(struct usbd_bus *, | 97 | void (*get_locks)(struct usbd_bus *, | |
63 | kmutex_t **, kmutex_t **); | 98 | kmutex_t **, kmutex_t **); | |
64 | }; | 99 | }; | |
65 | 100 | |||
66 | struct usbd_pipe_methods { | 101 | struct usbd_pipe_methods { | |
67 | usbd_status (*transfer)(usbd_xfer_handle xfer); | 102 | usbd_status (*transfer)(usbd_xfer_handle xfer); | |
68 | usbd_status (*start)(usbd_xfer_handle xfer); | 103 | usbd_status (*start)(usbd_xfer_handle xfer); | |
69 | void (*abort)(usbd_xfer_handle xfer); | 104 | void (*abort)(usbd_xfer_handle xfer); | |
70 | void (*close)(usbd_pipe_handle pipe); | 105 | void (*close)(usbd_pipe_handle pipe); | |
71 | void (*cleartoggle)(usbd_pipe_handle pipe); | 106 | void (*cleartoggle)(usbd_pipe_handle pipe); | |
72 | void (*done)(usbd_xfer_handle xfer); | 107 | void (*done)(usbd_xfer_handle xfer); | |
73 | }; | 108 | }; | |
74 | 109 | |||
75 | #if 0 /* notyet */ | 110 | #if 0 /* notyet */ | |
76 | struct usbd_tt { | 111 | struct usbd_tt { | |
77 | struct usbd_hub *hub; | 112 | struct usbd_hub *hub; | |
78 | }; | 113 | }; | |
79 | #endif | 114 | #endif | |
80 | 115 | |||
81 | struct usbd_port { | 116 | struct usbd_port { | |
82 | usb_port_status_t status; | 117 | usb_port_status_t status; | |
83 | u_int16_t power; /* mA of current on port */ | 118 | u_int16_t power; /* mA of current on port */ | |
84 | u_int8_t portno; | 119 | u_int8_t portno; | |
85 | u_int8_t restartcnt; | 120 | u_int8_t restartcnt; | |
86 | #define USBD_RESTART_MAX 5 | 121 | #define USBD_RESTART_MAX 5 | |
87 | u_int8_t reattach; | 122 | u_int8_t reattach; | |
88 | struct usbd_device *device; /* Connected device */ | 123 | struct usbd_device *device; /* Connected device */ | |
89 | struct usbd_device *parent; /* The ports hub */ | 124 | struct usbd_device *parent; /* The ports hub */ | |
90 | #if 0 | 125 | #if 0 | |
91 | struct usbd_tt *tt; /* Transaction translator (if any) */ | 126 | struct usbd_tt *tt; /* Transaction translator (if any) */ | |
92 | #endif | 127 | #endif | |
93 | }; | 128 | }; | |
94 | 129 | |||
95 | struct usbd_hub { | 130 | struct usbd_hub { | |
96 | usbd_status (*explore)(usbd_device_handle hub); | 131 | usbd_status (*explore)(usbd_device_handle hub); | |
97 | void *hubsoftc; | 132 | void *hubsoftc; | |
98 | usb_hub_descriptor_t hubdesc; | 133 | usb_hub_descriptor_t hubdesc; | |
99 | struct usbd_port ports[1]; | 134 | struct usbd_port ports[1]; | |
100 | }; | 135 | }; | |
101 | 136 | |||
102 | /*****/ | 137 | /*****/ | |
103 | 138 | |||
104 | struct usbd_bus { | 139 | struct usbd_bus { | |
105 | /* Filled by HC driver */ | 140 | /* Filled by HC driver */ | |
106 | void *hci_private; | 141 | void *hci_private; | |
107 | const struct usbd_bus_methods *methods; | 142 | const struct usbd_bus_methods *methods; | |
108 | u_int32_t pipe_size; /* size of a pipe struct */ | 143 | u_int32_t pipe_size; /* size of a pipe struct */ | |
109 | /* Filled by usb driver */ | 144 | /* Filled by usb driver */ | |
110 | struct usbd_device *root_hub; | 145 | kmutex_t *intr_lock; | |
146 | kmutex_t *lock; | |||
147 | struct usbd_device *root_hub; | |||
111 | usbd_device_handle devices[USB_MAX_DEVICES]; | 148 | usbd_device_handle devices[USB_MAX_DEVICES]; | |
112 | char needs_explore;/* a hub a signalled a change */ | 149 | char needs_explore;/* a hub a signalled a change */ | |
113 | char use_polling; | 150 | char use_polling; | |
114 | device_t usbctl; | 151 | device_t usbctl; | |
115 | struct usb_device_stats stats; | 152 | struct usb_device_stats stats; | |
116 | int intr_context; | 153 | int intr_context; | |
117 | u_int no_intrs; | 154 | u_int no_intrs; | |
118 | int usbrev; /* USB revision */ | 155 | int usbrev; /* USB revision */ | |
119 | #define USBREV_UNKNOWN 0 | 156 | #define USBREV_UNKNOWN 0 | |
120 | #define USBREV_PRE_1_0 1 | 157 | #define USBREV_PRE_1_0 1 | |
121 | #define USBREV_1_0 2 | 158 | #define USBREV_1_0 2 | |
122 | #define USBREV_1_1 3 | 159 | #define USBREV_1_1 3 | |
123 | #define USBREV_2_0 4 | 160 | #define USBREV_2_0 4 | |
124 | #define USBREV_STR { "unknown", "pre 1.0", "1.0", "1.1", "2.0" } | 161 | #define USBREV_STR { "unknown", "pre 1.0", "1.0", "1.1", "2.0" } | |
125 | 162 | |||
126 | void *soft; /* soft interrupt cookie */ | 163 | void *soft; /* soft interrupt cookie */ | |
127 | bus_dma_tag_t dmatag; /* DMA tag */ | 164 | bus_dma_tag_t dmatag; /* DMA tag */ | |
128 | }; | 165 | }; | |
129 | 166 | |||
130 | struct usbd_device { | 167 | struct usbd_device { | |
131 | struct usbd_bus *bus; /* our controller */ | 168 | struct usbd_bus *bus; /* our controller */ | |
132 | struct usbd_pipe *default_pipe; /* pipe 0 */ | 169 | struct usbd_pipe *default_pipe; /* pipe 0 */ | |
133 | u_int8_t address; /* device addess */ | 170 | u_int8_t address; /* device addess */ | |
134 | u_int8_t config; /* current configuration # */ | 171 | u_int8_t config; /* current configuration # */ | |
135 | u_int8_t depth; /* distance from root hub */ | 172 | u_int8_t depth; /* distance from root hub */ | |
136 | u_int8_t speed; /* low/full/high speed */ | 173 | u_int8_t speed; /* low/full/high speed */ | |
137 | u_int8_t self_powered; /* flag for self powered */ | 174 | u_int8_t self_powered; /* flag for self powered */ | |
138 | u_int16_t power; /* mA the device uses */ | 175 | u_int16_t power; /* mA the device uses */ | |
139 | int16_t langid; /* language for strings */ | 176 | int16_t langid; /* language for strings */ | |
140 | #define USBD_NOLANG (-1) | 177 | #define USBD_NOLANG (-1) | |
141 | usb_event_cookie_t cookie; /* unique connection id */ | 178 | usb_event_cookie_t cookie; /* unique connection id */ | |
142 | struct usbd_port *powersrc; /* upstream hub port, or 0 */ | 179 | struct usbd_port *powersrc; /* upstream hub port, or 0 */ | |
143 | struct usbd_device *myhub; /* upstream hub */ | 180 | struct usbd_device *myhub; /* upstream hub */ | |
144 | struct usbd_port *myhsport; /* closest high speed port */ | 181 | struct usbd_port *myhsport; /* closest high speed port */ | |
145 | struct usbd_endpoint def_ep; /* for pipe 0 */ | 182 | struct usbd_endpoint def_ep; /* for pipe 0 */ | |
146 | usb_endpoint_descriptor_t def_ep_desc; /* for pipe 0 */ | 183 | usb_endpoint_descriptor_t def_ep_desc; /* for pipe 0 */ | |
147 | struct usbd_interface *ifaces; /* array of all interfaces */ | 184 | struct usbd_interface *ifaces; /* array of all interfaces */ | |
148 | usb_device_descriptor_t ddesc; /* device descriptor */ | 185 | usb_device_descriptor_t ddesc; /* device descriptor */ | |
149 | usb_config_descriptor_t *cdesc; /* full config descr */ | 186 | usb_config_descriptor_t *cdesc; /* full config descr */ | |
150 | const struct usbd_quirks *quirks; /* device quirks, always set */ | 187 | const struct usbd_quirks *quirks; /* device quirks, always set */ | |
151 | struct usbd_hub *hub; /* only if this is a hub */ | 188 | struct usbd_hub *hub; /* only if this is a hub */ | |
152 | int subdevlen; /* array length of following */ | 189 | int subdevlen; /* array length of following */ | |
153 | device_t *subdevs; /* sub-devices */ | 190 | device_t *subdevs; /* sub-devices */ | |
154 | int nifaces_claimed; /* number of ifaces in use */ | 191 | int nifaces_claimed; /* number of ifaces in use */ | |
155 | }; | 192 | }; | |
156 | 193 | |||
157 | struct usbd_interface { | 194 | struct usbd_interface { | |
158 | struct usbd_device *device; | 195 | struct usbd_device *device; | |
159 | usb_interface_descriptor_t *idesc; | 196 | usb_interface_descriptor_t *idesc; | |
160 | int index; | 197 | int index; | |
161 | int altindex; | 198 | int altindex; | |
162 | struct usbd_endpoint *endpoints; | 199 | struct usbd_endpoint *endpoints; | |
163 | void *priv; | 200 | void *priv; | |
164 | LIST_HEAD(, usbd_pipe) pipes; | 201 | LIST_HEAD(, usbd_pipe) pipes; | |
165 | }; | 202 | }; | |
166 | 203 | |||
167 | struct usbd_pipe { | 204 | struct usbd_pipe { | |
168 | struct usbd_interface *iface; | 205 | struct usbd_interface *iface; | |
169 | struct usbd_device *device; | 206 | struct usbd_device *device; | |
170 | struct usbd_endpoint *endpoint; | 207 | struct usbd_endpoint *endpoint; | |
171 | int refcnt; | 208 | int refcnt; | |
172 | char running; | 209 | char running; | |
173 | char aborting; | 210 | char aborting; | |
174 | SIMPLEQ_HEAD(, usbd_xfer) queue; | 211 | SIMPLEQ_HEAD(, usbd_xfer) queue; | |
175 | LIST_ENTRY(usbd_pipe) next; | 212 | LIST_ENTRY(usbd_pipe) next; | |
176 | 213 | |||
177 | usbd_xfer_handle intrxfer; /* used for repeating requests */ | 214 | usbd_xfer_handle intrxfer; /* used for repeating requests */ | |
178 | char repeat; | 215 | char repeat; | |
179 | int interval; | 216 | int interval; | |
180 | 217 | |||
181 | kmutex_t *intr_lock; | |||
182 | kmutex_t *lock; | |||
183 | ||||
184 | /* Filled by HC driver. */ | 218 | /* Filled by HC driver. */ | |
185 | const struct usbd_pipe_methods *methods; | 219 | const struct usbd_pipe_methods *methods; | |
186 | }; | 220 | }; | |
187 | 221 | |||
188 | struct usbd_xfer { | 222 | struct usbd_xfer { | |
189 | struct usbd_pipe *pipe; | 223 | struct usbd_pipe *pipe; | |
190 | void *priv; | 224 | void *priv; | |
191 | void *buffer; | 225 | void *buffer; | |
192 | kcondvar_t cv; | 226 | kcondvar_t cv; | |
193 | u_int32_t length; | 227 | u_int32_t length; | |
194 | u_int32_t actlen; | 228 | u_int32_t actlen; | |
195 | u_int16_t flags; | 229 | u_int16_t flags; | |
196 | u_int32_t timeout; | 230 | u_int32_t timeout; | |
197 | usbd_status status; | 231 | usbd_status status; | |
198 | usbd_callback callback; | 232 | usbd_callback callback; | |
199 | volatile u_int8_t done; | 233 | volatile u_int8_t done; | |
200 | u_int8_t busy_free; /* used for DIAGNOSTIC */ | 234 | u_int8_t busy_free; /* used for DIAGNOSTIC */ | |
201 | #define XFER_FREE 0x46 | 235 | #define XFER_FREE 0x46 | |
202 | #define XFER_BUSY 0x55 | 236 | #define XFER_BUSY 0x55 | |
203 | #define XFER_ONQU 0x9e | 237 | #define XFER_ONQU 0x9e | |
204 | 238 | |||
205 | /* For control pipe */ | 239 | /* For control pipe */ | |
206 | usb_device_request_t request; | 240 | usb_device_request_t request; | |
207 | 241 | |||
208 | /* For isoc */ | 242 | /* For isoc */ | |
209 | u_int16_t *frlengths; | 243 | u_int16_t *frlengths; | |
210 | int nframes; | 244 | int nframes; | |
211 | 245 | |||
212 | /* For memory allocation */ | 246 | /* For memory allocation */ | |
213 | struct usbd_device *device; | 247 | struct usbd_device *device; | |
214 | usb_dma_t dmabuf; | 248 | usb_dma_t dmabuf; | |
215 | 249 | |||
216 | u_int8_t rqflags; | 250 | u_int8_t rqflags; | |
217 | #define URQ_REQUEST 0x01 | 251 | #define URQ_REQUEST 0x01 | |
218 | #define URQ_AUTO_DMABUF 0x10 | 252 | #define URQ_AUTO_DMABUF 0x10 | |
219 | #define URQ_DEV_DMABUF 0x20 | 253 | #define URQ_DEV_DMABUF 0x20 | |
220 | 254 | |||
221 | SIMPLEQ_ENTRY(usbd_xfer) next; | 255 | SIMPLEQ_ENTRY(usbd_xfer) next; | |
222 | 256 | |||
223 | void *hcpriv; /* private use by the HC driver */ | 257 | void *hcpriv; /* private use by the HC driver */ | |
224 | u_int8_t hcflags; /* private use by the HC driver */ | 258 | u_int8_t hcflags; /* private use by the HC driver */ | |
225 | #define UXFER_ABORTING 0x01 /* xfer is aborting. */ | 259 | #define UXFER_ABORTING 0x01 /* xfer is aborting. */ | |
226 | #define UXFER_ABORTWAIT 0x02 /* abort completion is being awaited. */ | 260 | #define UXFER_ABORTWAIT 0x02 /* abort completion is being awaited. */ | |
227 | kcondvar_t hccv; /* private use by the HC driver */ | 261 | kcondvar_t hccv; /* private use by the HC driver */ | |
228 | 262 | |||
229 | struct callout timeout_handle; | 263 | struct callout timeout_handle; | |
230 | }; | 264 | }; | |
231 | 265 | |||
232 | void usbd_init(void); | 266 | void usbd_init(void); | |
233 | void usbd_finish(void); | 267 | void usbd_finish(void); | |
234 | 268 | |||
235 | #if defined(USB_DEBUG) || defined(EHCI_DEBUG) | 269 | #if defined(USB_DEBUG) || defined(EHCI_DEBUG) | |
236 | void usbd_dump_iface(struct usbd_interface *iface); | 270 | void usbd_dump_iface(struct usbd_interface *iface); | |
237 | void usbd_dump_device(struct usbd_device *dev); | 271 | void usbd_dump_device(struct usbd_device *dev); | |
238 | void usbd_dump_endpoint(struct usbd_endpoint *endp); | 272 | void usbd_dump_endpoint(struct usbd_endpoint *endp); | |
239 | void usbd_dump_queue(usbd_pipe_handle pipe); | 273 | void usbd_dump_queue(usbd_pipe_handle pipe); | |
240 | void usbd_dump_pipe(usbd_pipe_handle pipe); | 274 | void usbd_dump_pipe(usbd_pipe_handle pipe); | |
241 | #endif | 275 | #endif | |
242 | 276 | |||
243 | /* Routines from usb_subr.c */ | 277 | /* Routines from usb_subr.c */ | |
244 | int usbctlprint(void *, const char *); | 278 | int usbctlprint(void *, const char *); | |
245 | void usb_delay_ms(usbd_bus_handle, u_int); | 279 | void usb_delay_ms(usbd_bus_handle, u_int); | |
246 | usbd_status usbd_reset_port(usbd_device_handle, int, usb_port_status_t *); | 280 | usbd_status usbd_reset_port(usbd_device_handle, int, usb_port_status_t *); | |
247 | usbd_status usbd_setup_pipe(usbd_device_handle dev, | 281 | usbd_status usbd_setup_pipe(usbd_device_handle dev, | |
248 | usbd_interface_handle iface, | 282 | usbd_interface_handle iface, | |
249 | struct usbd_endpoint *, int, | 283 | struct usbd_endpoint *, int, | |
250 | usbd_pipe_handle *pipe); | 284 | usbd_pipe_handle *pipe); | |
251 | usbd_status usbd_new_device(device_t, usbd_bus_handle, int, int, int, | 285 | usbd_status usbd_new_device(device_t, usbd_bus_handle, int, int, int, | |
252 | struct usbd_port *); | 286 | struct usbd_port *); | |
253 | usbd_status usbd_reattach_device(device_t, usbd_device_handle, | 287 | usbd_status usbd_reattach_device(device_t, usbd_device_handle, | |
254 | int, const int *); | 288 | int, const int *); | |
255 | 289 | |||
256 | void usbd_remove_device(usbd_device_handle, struct usbd_port *); | 290 | void usbd_remove_device(usbd_device_handle, struct usbd_port *); | |
257 | int usbd_printBCD(char *, size_t, int); | 291 | int usbd_printBCD(char *, size_t, int); | |
258 | usbd_status usbd_fill_iface_data(usbd_device_handle, int, int); | 292 | usbd_status usbd_fill_iface_data(usbd_device_handle, int, int); | |
259 | void usb_free_device(usbd_device_handle); | 293 | void usb_free_device(usbd_device_handle); | |
260 | 294 | |||
261 | usbd_status usb_insert_transfer(usbd_xfer_handle); | 295 | usbd_status usb_insert_transfer(usbd_xfer_handle); | |
262 | void usb_transfer_complete(usbd_xfer_handle); | 296 | void usb_transfer_complete(usbd_xfer_handle); | |
263 | int usb_disconnect_port(struct usbd_port *, device_t, int); | 297 | int usb_disconnect_port(struct usbd_port *, device_t, int); | |
264 | 298 | |||
265 | /* Routines from usb.c */ | 299 | /* Routines from usb.c */ | |
266 | void usb_needs_explore(usbd_device_handle); | 300 | void usb_needs_explore(usbd_device_handle); | |
267 | void usb_needs_reattach(usbd_device_handle); | 301 | void usb_needs_reattach(usbd_device_handle); | |
268 | void usb_schedsoftintr(struct usbd_bus *); | 302 | void usb_schedsoftintr(struct usbd_bus *); | |
269 | 303 | |||
270 | #define usbd_lock(m) if (m) { s = -1; mutex_enter(m); } else s = splusb() | 304 | #define usbd_lock_pipe(p) do { \ | |
271 | #define usbd_unlock(m) if (m) { s = -1; mutex_exit(m); } else splx(s) | 305 | if ((p)->device->bus->lock) { \ | |
272 | 306 | s = -1; \ | ||
273 | /* | 307 | mutex_enter((p)->device->bus->lock); \ | |
274 | * XXX This check is extremely bogus. Bad Bad Bad. | 308 | } else \ | |
275 | */ | 309 | s = splusb(); \ | |
276 | #if defined(DIAGNOSTIC) && 0 | 310 | } while (0) | |
277 | #define SPLUSBCHECK \ | 311 | ||
278 | do { int _s = splusb(), _su = splusb(); \ | 312 | #define usbd_unlock_pipe(p) do { \ | |
279 | if (!cold && _s != _su) printf("SPLUSBCHECK failed 0x%x!=0x%x, %s:%d\n", \ | 313 | if ((p)->device->bus->lock) { \ | |
280 | _s, _su, __FILE__, __LINE__); \ | 314 | s = -1; \ | |
281 | splx(_s); \ | 315 | mutex_exit((p)->device->bus->lock); \ | |
282 | } while (0) | 316 | } else \ | |
283 | #else | 317 | splx(s); \ | |
284 | #define SPLUSBCHECK | 318 | } while (0) | |
285 | #endif |