| @@ -1,1701 +1,1701 @@ | | | @@ -1,1701 +1,1701 @@ |
1 | /* $NetBSD: ohci.c,v 1.254.2.66 2016/04/01 14:13:29 skrll Exp $ */ | | 1 | /* $NetBSD: ohci.c,v 1.254.2.67 2016/04/01 14:17:24 skrll Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | | 8 | * by Lennart Augustsson (lennart@augustsson.net) at |
9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) | | 9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) |
10 | * and Matthew R. Green (mrg@eterna.com.au). | | 10 | * and Matthew R. Green (mrg@eterna.com.au). |
11 | * This code is derived from software contributed to The NetBSD Foundation | | 11 | * This code is derived from software contributed to The NetBSD Foundation |
12 | * by Charles M. Hannum. | | 12 | * by Charles M. Hannum. |
13 | * | | 13 | * |
14 | * Redistribution and use in source and binary forms, with or without | | 14 | * Redistribution and use in source and binary forms, with or without |
15 | * modification, are permitted provided that the following conditions | | 15 | * modification, are permitted provided that the following conditions |
16 | * are met: | | 16 | * are met: |
17 | * 1. Redistributions of source code must retain the above copyright | | 17 | * 1. Redistributions of source code must retain the above copyright |
18 | * notice, this list of conditions and the following disclaimer. | | 18 | * notice, this list of conditions and the following disclaimer. |
19 | * 2. Redistributions in binary form must reproduce the above copyright | | 19 | * 2. Redistributions in binary form must reproduce the above copyright |
20 | * notice, this list of conditions and the following disclaimer in the | | 20 | * notice, this list of conditions and the following disclaimer in the |
21 | * documentation and/or other materials provided with the distribution. | | 21 | * documentation and/or other materials provided with the distribution. |
22 | * | | 22 | * |
23 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 23 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
24 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 24 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
25 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 25 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
26 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 26 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
27 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 27 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
33 | * POSSIBILITY OF SUCH DAMAGE. | | 33 | * POSSIBILITY OF SUCH DAMAGE. |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | /* | | 36 | /* |
37 | * USB Open Host Controller driver. | | 37 | * USB Open Host Controller driver. |
38 | * | | 38 | * |
39 | * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html | | 39 | * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html |
40 | * USB spec: http://www.usb.org/developers/docs/ | | 40 | * USB spec: http://www.usb.org/developers/docs/ |
41 | */ | | 41 | */ |
42 | | | 42 | |
43 | #include <sys/cdefs.h> | | 43 | #include <sys/cdefs.h> |
44 | __KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.66 2016/04/01 14:13:29 skrll Exp $"); | | 44 | __KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.67 2016/04/01 14:17:24 skrll Exp $"); |
45 | | | 45 | |
46 | #include "opt_usb.h" | | 46 | #include "opt_usb.h" |
47 | | | 47 | |
48 | #include <sys/param.h> | | 48 | #include <sys/param.h> |
49 | | | 49 | |
50 | #include <sys/cpu.h> | | 50 | #include <sys/cpu.h> |
51 | #include <sys/device.h> | | 51 | #include <sys/device.h> |
52 | #include <sys/kernel.h> | | 52 | #include <sys/kernel.h> |
53 | #include <sys/kmem.h> | | 53 | #include <sys/kmem.h> |
54 | #include <sys/proc.h> | | 54 | #include <sys/proc.h> |
55 | #include <sys/queue.h> | | 55 | #include <sys/queue.h> |
56 | #include <sys/select.h> | | 56 | #include <sys/select.h> |
57 | #include <sys/sysctl.h> | | 57 | #include <sys/sysctl.h> |
58 | #include <sys/systm.h> | | 58 | #include <sys/systm.h> |
59 | | | 59 | |
60 | #include <machine/endian.h> | | 60 | #include <machine/endian.h> |
61 | | | 61 | |
62 | #include <dev/usb/usb.h> | | 62 | #include <dev/usb/usb.h> |
63 | #include <dev/usb/usbdi.h> | | 63 | #include <dev/usb/usbdi.h> |
64 | #include <dev/usb/usbdivar.h> | | 64 | #include <dev/usb/usbdivar.h> |
65 | #include <dev/usb/usb_mem.h> | | 65 | #include <dev/usb/usb_mem.h> |
66 | #include <dev/usb/usb_quirks.h> | | 66 | #include <dev/usb/usb_quirks.h> |
67 | | | 67 | |
68 | #include <dev/usb/ohcireg.h> | | 68 | #include <dev/usb/ohcireg.h> |
69 | #include <dev/usb/ohcivar.h> | | 69 | #include <dev/usb/ohcivar.h> |
70 | #include <dev/usb/usbroothub.h> | | 70 | #include <dev/usb/usbroothub.h> |
71 | #include <dev/usb/usbhist.h> | | 71 | #include <dev/usb/usbhist.h> |
72 | | | 72 | |
73 | #ifdef USB_DEBUG | | 73 | #ifdef USB_DEBUG |
74 | #ifndef OHCI_DEBUG | | 74 | #ifndef OHCI_DEBUG |
75 | #define ohcidebug 0 | | 75 | #define ohcidebug 0 |
76 | #else | | 76 | #else |
77 | static int ohcidebug = 10; | | 77 | static int ohcidebug = 10; |
78 | | | 78 | |
79 | SYSCTL_SETUP(sysctl_hw_ohci_setup, "sysctl hw.ohci setup") | | 79 | SYSCTL_SETUP(sysctl_hw_ohci_setup, "sysctl hw.ohci setup") |
80 | { | | 80 | { |
81 | int err; | | 81 | int err; |
82 | const struct sysctlnode *rnode; | | 82 | const struct sysctlnode *rnode; |
83 | const struct sysctlnode *cnode; | | 83 | const struct sysctlnode *cnode; |
84 | | | 84 | |
85 | err = sysctl_createv(clog, 0, NULL, &rnode, | | 85 | err = sysctl_createv(clog, 0, NULL, &rnode, |
86 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "ohci", | | 86 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "ohci", |
87 | SYSCTL_DESCR("ohci global controls"), | | 87 | SYSCTL_DESCR("ohci global controls"), |
88 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | | 88 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); |
89 | | | 89 | |
90 | if (err) | | 90 | if (err) |
91 | goto fail; | | 91 | goto fail; |
92 | | | 92 | |
93 | /* control debugging printfs */ | | 93 | /* control debugging printfs */ |
94 | err = sysctl_createv(clog, 0, &rnode, &cnode, | | 94 | err = sysctl_createv(clog, 0, &rnode, &cnode, |
95 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | | 95 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
96 | "debug", SYSCTL_DESCR("Enable debugging output"), | | 96 | "debug", SYSCTL_DESCR("Enable debugging output"), |
97 | NULL, 0, &ohcidebug, sizeof(ohcidebug), CTL_CREATE, CTL_EOL); | | 97 | NULL, 0, &ohcidebug, sizeof(ohcidebug), CTL_CREATE, CTL_EOL); |
98 | if (err) | | 98 | if (err) |
99 | goto fail; | | 99 | goto fail; |
100 | | | 100 | |
101 | return; | | 101 | return; |
102 | fail: | | 102 | fail: |
103 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | | 103 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); |
104 | } | | 104 | } |
105 | | | 105 | |
106 | #endif /* OHCI_DEBUG */ | | 106 | #endif /* OHCI_DEBUG */ |
107 | #endif /* USB_DEBUG */ | | 107 | #endif /* USB_DEBUG */ |
108 | | | 108 | |
109 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOG(ohcidebug,FMT,A,B,C,D) | | 109 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOG(ohcidebug,FMT,A,B,C,D) |
110 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(ohcidebug,N,FMT,A,B,C,D) | | 110 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(ohcidebug,N,FMT,A,B,C,D) |
111 | #define OHCIHIST_FUNC() USBHIST_FUNC() | | 111 | #define OHCIHIST_FUNC() USBHIST_FUNC() |
112 | #define OHCIHIST_CALLED(name) USBHIST_CALLED(ohcidebug) | | 112 | #define OHCIHIST_CALLED(name) USBHIST_CALLED(ohcidebug) |
113 | | | 113 | |
114 | #if BYTE_ORDER == BIG_ENDIAN | | 114 | #if BYTE_ORDER == BIG_ENDIAN |
115 | #define SWAP_ENDIAN OHCI_LITTLE_ENDIAN | | 115 | #define SWAP_ENDIAN OHCI_LITTLE_ENDIAN |
116 | #else | | 116 | #else |
117 | #define SWAP_ENDIAN OHCI_BIG_ENDIAN | | 117 | #define SWAP_ENDIAN OHCI_BIG_ENDIAN |
118 | #endif | | 118 | #endif |
119 | | | 119 | |
120 | #define O16TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap16(val) : val) | | 120 | #define O16TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap16(val) : val) |
121 | #define O32TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap32(val) : val) | | 121 | #define O32TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap32(val) : val) |
122 | #define HTOO16(val) O16TOH(val) | | 122 | #define HTOO16(val) O16TOH(val) |
123 | #define HTOO32(val) O32TOH(val) | | 123 | #define HTOO32(val) O32TOH(val) |
124 | | | 124 | |
125 | struct ohci_pipe; | | 125 | struct ohci_pipe; |
126 | | | 126 | |
127 | Static ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *); | | 127 | Static ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *); |
128 | Static void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *); | | 128 | Static void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *); |
129 | | | 129 | |
130 | Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *); | | 130 | Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *); |
131 | Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *); | | 131 | Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *); |
132 | Static void ohci_free_std_locked(ohci_softc_t *, ohci_soft_td_t *); | | 132 | Static void ohci_free_std_locked(ohci_softc_t *, ohci_soft_td_t *); |
133 | | | 133 | |
134 | Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *); | | 134 | Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *); |
135 | Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *); | | 135 | Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *); |
136 | Static void ohci_free_sitd_locked(ohci_softc_t *, | | 136 | Static void ohci_free_sitd_locked(ohci_softc_t *, |
137 | ohci_soft_itd_t *); | | 137 | ohci_soft_itd_t *); |
138 | | | 138 | |
139 | Static usbd_status ohci_alloc_std_chain(ohci_softc_t *, struct usbd_xfer *, | | 139 | Static usbd_status ohci_alloc_std_chain(ohci_softc_t *, struct usbd_xfer *, |
140 | int, int); | | 140 | int, int); |
141 | Static void ohci_free_stds(ohci_softc_t *, struct ohci_xfer *); | | 141 | Static void ohci_free_stds(ohci_softc_t *, struct ohci_xfer *); |
142 | | | 142 | |
143 | Static void ohci_reset_std_chain(ohci_softc_t *, struct usbd_xfer *, | | 143 | Static void ohci_reset_std_chain(ohci_softc_t *, struct usbd_xfer *, |
144 | int, int, ohci_soft_td_t *, ohci_soft_td_t **); | | 144 | int, int, ohci_soft_td_t *, ohci_soft_td_t **); |
145 | | | 145 | |
146 | Static usbd_status ohci_open(struct usbd_pipe *); | | 146 | Static usbd_status ohci_open(struct usbd_pipe *); |
147 | Static void ohci_poll(struct usbd_bus *); | | 147 | Static void ohci_poll(struct usbd_bus *); |
148 | Static void ohci_softintr(void *); | | 148 | Static void ohci_softintr(void *); |
149 | Static void ohci_waitintr(ohci_softc_t *, struct usbd_xfer *); | | 149 | Static void ohci_waitintr(ohci_softc_t *, struct usbd_xfer *); |
150 | Static void ohci_rhsc(ohci_softc_t *, struct usbd_xfer *); | | 150 | Static void ohci_rhsc(ohci_softc_t *, struct usbd_xfer *); |
151 | Static void ohci_rhsc_softint(void *); | | 151 | Static void ohci_rhsc_softint(void *); |
152 | | | 152 | |
153 | Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *, | | 153 | Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *, |
154 | ohci_soft_ed_t *); | | 154 | ohci_soft_ed_t *); |
155 | | | 155 | |
156 | Static void ohci_rem_ed(ohci_softc_t *, ohci_soft_ed_t *, | | 156 | Static void ohci_rem_ed(ohci_softc_t *, ohci_soft_ed_t *, |
157 | ohci_soft_ed_t *); | | 157 | ohci_soft_ed_t *); |
158 | Static void ohci_hash_add_td(ohci_softc_t *, ohci_soft_td_t *); | | 158 | Static void ohci_hash_add_td(ohci_softc_t *, ohci_soft_td_t *); |
159 | Static void ohci_hash_rem_td(ohci_softc_t *, ohci_soft_td_t *); | | 159 | Static void ohci_hash_rem_td(ohci_softc_t *, ohci_soft_td_t *); |
160 | Static ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, ohci_physaddr_t); | | 160 | Static ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, ohci_physaddr_t); |
161 | Static void ohci_hash_add_itd(ohci_softc_t *, ohci_soft_itd_t *); | | 161 | Static void ohci_hash_add_itd(ohci_softc_t *, ohci_soft_itd_t *); |
162 | Static void ohci_hash_rem_itd(ohci_softc_t *, ohci_soft_itd_t *); | | 162 | Static void ohci_hash_rem_itd(ohci_softc_t *, ohci_soft_itd_t *); |
163 | Static ohci_soft_itd_t *ohci_hash_find_itd(ohci_softc_t *, ohci_physaddr_t); | | 163 | Static ohci_soft_itd_t *ohci_hash_find_itd(ohci_softc_t *, ohci_physaddr_t); |
164 | | | 164 | |
165 | Static usbd_status ohci_setup_isoc(struct usbd_pipe *); | | 165 | Static usbd_status ohci_setup_isoc(struct usbd_pipe *); |
166 | Static void ohci_device_isoc_enter(struct usbd_xfer *); | | 166 | Static void ohci_device_isoc_enter(struct usbd_xfer *); |
167 | | | 167 | |
168 | Static struct usbd_xfer * | | 168 | Static struct usbd_xfer * |
169 | ohci_allocx(struct usbd_bus *, unsigned int); | | 169 | ohci_allocx(struct usbd_bus *, unsigned int); |
170 | Static void ohci_freex(struct usbd_bus *, struct usbd_xfer *); | | 170 | Static void ohci_freex(struct usbd_bus *, struct usbd_xfer *); |
171 | Static void ohci_get_lock(struct usbd_bus *, kmutex_t **); | | 171 | Static void ohci_get_lock(struct usbd_bus *, kmutex_t **); |
172 | Static int ohci_roothub_ctrl(struct usbd_bus *, | | 172 | Static int ohci_roothub_ctrl(struct usbd_bus *, |
173 | usb_device_request_t *, void *, int); | | 173 | usb_device_request_t *, void *, int); |
174 | | | 174 | |
175 | Static usbd_status ohci_root_intr_transfer(struct usbd_xfer *); | | 175 | Static usbd_status ohci_root_intr_transfer(struct usbd_xfer *); |
176 | Static usbd_status ohci_root_intr_start(struct usbd_xfer *); | | 176 | Static usbd_status ohci_root_intr_start(struct usbd_xfer *); |
177 | Static void ohci_root_intr_abort(struct usbd_xfer *); | | 177 | Static void ohci_root_intr_abort(struct usbd_xfer *); |
178 | Static void ohci_root_intr_close(struct usbd_pipe *); | | 178 | Static void ohci_root_intr_close(struct usbd_pipe *); |
179 | Static void ohci_root_intr_done(struct usbd_xfer *); | | 179 | Static void ohci_root_intr_done(struct usbd_xfer *); |
180 | | | 180 | |
181 | Static int ohci_device_ctrl_init(struct usbd_xfer *); | | 181 | Static int ohci_device_ctrl_init(struct usbd_xfer *); |
182 | Static void ohci_device_ctrl_fini(struct usbd_xfer *); | | 182 | Static void ohci_device_ctrl_fini(struct usbd_xfer *); |
183 | Static usbd_status ohci_device_ctrl_transfer(struct usbd_xfer *); | | 183 | Static usbd_status ohci_device_ctrl_transfer(struct usbd_xfer *); |
184 | Static usbd_status ohci_device_ctrl_start(struct usbd_xfer *); | | 184 | Static usbd_status ohci_device_ctrl_start(struct usbd_xfer *); |
185 | Static void ohci_device_ctrl_abort(struct usbd_xfer *); | | 185 | Static void ohci_device_ctrl_abort(struct usbd_xfer *); |
186 | Static void ohci_device_ctrl_close(struct usbd_pipe *); | | 186 | Static void ohci_device_ctrl_close(struct usbd_pipe *); |
187 | Static void ohci_device_ctrl_done(struct usbd_xfer *); | | 187 | Static void ohci_device_ctrl_done(struct usbd_xfer *); |
188 | | | 188 | |
189 | Static int ohci_device_bulk_init(struct usbd_xfer *); | | 189 | Static int ohci_device_bulk_init(struct usbd_xfer *); |
190 | Static void ohci_device_bulk_fini(struct usbd_xfer *); | | 190 | Static void ohci_device_bulk_fini(struct usbd_xfer *); |
191 | Static usbd_status ohci_device_bulk_transfer(struct usbd_xfer *); | | 191 | Static usbd_status ohci_device_bulk_transfer(struct usbd_xfer *); |
192 | Static usbd_status ohci_device_bulk_start(struct usbd_xfer *); | | 192 | Static usbd_status ohci_device_bulk_start(struct usbd_xfer *); |
193 | Static void ohci_device_bulk_abort(struct usbd_xfer *); | | 193 | Static void ohci_device_bulk_abort(struct usbd_xfer *); |
194 | Static void ohci_device_bulk_close(struct usbd_pipe *); | | 194 | Static void ohci_device_bulk_close(struct usbd_pipe *); |
195 | Static void ohci_device_bulk_done(struct usbd_xfer *); | | 195 | Static void ohci_device_bulk_done(struct usbd_xfer *); |
196 | | | 196 | |
197 | Static int ohci_device_intr_init(struct usbd_xfer *); | | 197 | Static int ohci_device_intr_init(struct usbd_xfer *); |
198 | Static void ohci_device_intr_fini(struct usbd_xfer *); | | 198 | Static void ohci_device_intr_fini(struct usbd_xfer *); |
199 | Static usbd_status ohci_device_intr_transfer(struct usbd_xfer *); | | 199 | Static usbd_status ohci_device_intr_transfer(struct usbd_xfer *); |
200 | Static usbd_status ohci_device_intr_start(struct usbd_xfer *); | | 200 | Static usbd_status ohci_device_intr_start(struct usbd_xfer *); |
201 | Static void ohci_device_intr_abort(struct usbd_xfer *); | | 201 | Static void ohci_device_intr_abort(struct usbd_xfer *); |
202 | Static void ohci_device_intr_close(struct usbd_pipe *); | | 202 | Static void ohci_device_intr_close(struct usbd_pipe *); |
203 | Static void ohci_device_intr_done(struct usbd_xfer *); | | 203 | Static void ohci_device_intr_done(struct usbd_xfer *); |
204 | | | 204 | |
205 | Static int ohci_device_isoc_init(struct usbd_xfer *); | | 205 | Static int ohci_device_isoc_init(struct usbd_xfer *); |
206 | Static void ohci_device_isoc_fini(struct usbd_xfer *); | | 206 | Static void ohci_device_isoc_fini(struct usbd_xfer *); |
207 | Static usbd_status ohci_device_isoc_transfer(struct usbd_xfer *); | | 207 | Static usbd_status ohci_device_isoc_transfer(struct usbd_xfer *); |
208 | Static void ohci_device_isoc_abort(struct usbd_xfer *); | | 208 | Static void ohci_device_isoc_abort(struct usbd_xfer *); |
209 | Static void ohci_device_isoc_close(struct usbd_pipe *); | | 209 | Static void ohci_device_isoc_close(struct usbd_pipe *); |
210 | Static void ohci_device_isoc_done(struct usbd_xfer *); | | 210 | Static void ohci_device_isoc_done(struct usbd_xfer *); |
211 | | | 211 | |
212 | Static usbd_status ohci_device_setintr(ohci_softc_t *, | | 212 | Static usbd_status ohci_device_setintr(ohci_softc_t *, |
213 | struct ohci_pipe *, int); | | 213 | struct ohci_pipe *, int); |
214 | | | 214 | |
215 | Static void ohci_timeout(void *); | | 215 | Static void ohci_timeout(void *); |
216 | Static void ohci_timeout_task(void *); | | 216 | Static void ohci_timeout_task(void *); |
217 | Static void ohci_rhsc_enable(void *); | | 217 | Static void ohci_rhsc_enable(void *); |
218 | | | 218 | |
219 | Static void ohci_close_pipe(struct usbd_pipe *, ohci_soft_ed_t *); | | 219 | Static void ohci_close_pipe(struct usbd_pipe *, ohci_soft_ed_t *); |
220 | Static void ohci_abort_xfer(struct usbd_xfer *, usbd_status); | | 220 | Static void ohci_abort_xfer(struct usbd_xfer *, usbd_status); |
221 | | | 221 | |
222 | Static void ohci_device_clear_toggle(struct usbd_pipe *); | | 222 | Static void ohci_device_clear_toggle(struct usbd_pipe *); |
223 | Static void ohci_noop(struct usbd_pipe *); | | 223 | Static void ohci_noop(struct usbd_pipe *); |
224 | | | 224 | |
225 | #ifdef OHCI_DEBUG | | 225 | #ifdef OHCI_DEBUG |
226 | Static void ohci_dumpregs(ohci_softc_t *); | | 226 | Static void ohci_dumpregs(ohci_softc_t *); |
227 | Static void ohci_dump_tds(ohci_softc_t *, ohci_soft_td_t *); | | 227 | Static void ohci_dump_tds(ohci_softc_t *, ohci_soft_td_t *); |
228 | Static void ohci_dump_td(ohci_softc_t *, ohci_soft_td_t *); | | 228 | Static void ohci_dump_td(ohci_softc_t *, ohci_soft_td_t *); |
229 | Static void ohci_dump_ed(ohci_softc_t *, ohci_soft_ed_t *); | | 229 | Static void ohci_dump_ed(ohci_softc_t *, ohci_soft_ed_t *); |
230 | Static void ohci_dump_itd(ohci_softc_t *, ohci_soft_itd_t *); | | 230 | Static void ohci_dump_itd(ohci_softc_t *, ohci_soft_itd_t *); |
231 | Static void ohci_dump_itds(ohci_softc_t *, ohci_soft_itd_t *); | | 231 | Static void ohci_dump_itds(ohci_softc_t *, ohci_soft_itd_t *); |
232 | #endif | | 232 | #endif |
233 | | | 233 | |
234 | #define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ | | 234 | #define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ |
235 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) | | 235 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) |
236 | #define OWRITE1(sc, r, x) \ | | 236 | #define OWRITE1(sc, r, x) \ |
237 | do { OBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | | 237 | do { OBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0) |
238 | #define OWRITE2(sc, r, x) \ | | 238 | #define OWRITE2(sc, r, x) \ |
239 | do { OBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | | 239 | do { OBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0) |
240 | #define OWRITE4(sc, r, x) \ | | 240 | #define OWRITE4(sc, r, x) \ |
241 | do { OBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | | 241 | do { OBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0) |
242 | | | 242 | |
243 | static __inline uint32_t | | 243 | static __inline uint32_t |
244 | OREAD4(ohci_softc_t *sc, bus_size_t r) | | 244 | OREAD4(ohci_softc_t *sc, bus_size_t r) |
245 | { | | 245 | { |
246 | | | 246 | |
247 | OBARR(sc); | | 247 | OBARR(sc); |
248 | return bus_space_read_4(sc->iot, sc->ioh, r); | | 248 | return bus_space_read_4(sc->iot, sc->ioh, r); |
249 | } | | 249 | } |
250 | | | 250 | |
251 | /* Reverse the bits in a value 0 .. 31 */ | | 251 | /* Reverse the bits in a value 0 .. 31 */ |
252 | Static uint8_t revbits[OHCI_NO_INTRS] = | | 252 | Static uint8_t revbits[OHCI_NO_INTRS] = |
253 | { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, | | 253 | { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, |
254 | 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, | | 254 | 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, |
255 | 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, | | 255 | 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, |
256 | 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; | | 256 | 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; |
257 | | | 257 | |
258 | struct ohci_pipe { | | 258 | struct ohci_pipe { |
259 | struct usbd_pipe pipe; | | 259 | struct usbd_pipe pipe; |
260 | ohci_soft_ed_t *sed; | | 260 | ohci_soft_ed_t *sed; |
261 | union { | | 261 | union { |
262 | ohci_soft_td_t *td; | | 262 | ohci_soft_td_t *td; |
263 | ohci_soft_itd_t *itd; | | 263 | ohci_soft_itd_t *itd; |
264 | } tail; | | 264 | } tail; |
265 | /* Info needed for different pipe kinds. */ | | 265 | /* Info needed for different pipe kinds. */ |
266 | union { | | 266 | union { |
267 | /* Control pipe */ | | 267 | /* Control pipe */ |
268 | struct { | | 268 | struct { |
269 | usb_dma_t reqdma; | | 269 | usb_dma_t reqdma; |
270 | } ctrl; | | 270 | } ctrl; |
271 | /* Interrupt pipe */ | | 271 | /* Interrupt pipe */ |
272 | struct { | | 272 | struct { |
273 | int nslots; | | 273 | int nslots; |
274 | int pos; | | 274 | int pos; |
275 | } intr; | | 275 | } intr; |
276 | /* Isochronous pipe */ | | 276 | /* Isochronous pipe */ |
277 | struct isoc { | | 277 | struct isoc { |
278 | int next, inuse; | | 278 | int next, inuse; |
279 | } isoc; | | 279 | } isoc; |
280 | }; | | 280 | }; |
281 | }; | | 281 | }; |
282 | | | 282 | |
283 | Static const struct usbd_bus_methods ohci_bus_methods = { | | 283 | Static const struct usbd_bus_methods ohci_bus_methods = { |
284 | .ubm_open = ohci_open, | | 284 | .ubm_open = ohci_open, |
285 | .ubm_softint = ohci_softintr, | | 285 | .ubm_softint = ohci_softintr, |
286 | .ubm_dopoll = ohci_poll, | | 286 | .ubm_dopoll = ohci_poll, |
287 | .ubm_allocx = ohci_allocx, | | 287 | .ubm_allocx = ohci_allocx, |
288 | .ubm_freex = ohci_freex, | | 288 | .ubm_freex = ohci_freex, |
289 | .ubm_getlock = ohci_get_lock, | | 289 | .ubm_getlock = ohci_get_lock, |
290 | .ubm_rhctrl = ohci_roothub_ctrl, | | 290 | .ubm_rhctrl = ohci_roothub_ctrl, |
291 | }; | | 291 | }; |
292 | | | 292 | |
293 | Static const struct usbd_pipe_methods ohci_root_intr_methods = { | | 293 | Static const struct usbd_pipe_methods ohci_root_intr_methods = { |
294 | .upm_transfer = ohci_root_intr_transfer, | | 294 | .upm_transfer = ohci_root_intr_transfer, |
295 | .upm_start = ohci_root_intr_start, | | 295 | .upm_start = ohci_root_intr_start, |
296 | .upm_abort = ohci_root_intr_abort, | | 296 | .upm_abort = ohci_root_intr_abort, |
297 | .upm_close = ohci_root_intr_close, | | 297 | .upm_close = ohci_root_intr_close, |
298 | .upm_cleartoggle = ohci_noop, | | 298 | .upm_cleartoggle = ohci_noop, |
299 | .upm_done = ohci_root_intr_done, | | 299 | .upm_done = ohci_root_intr_done, |
300 | }; | | 300 | }; |
301 | | | 301 | |
302 | Static const struct usbd_pipe_methods ohci_device_ctrl_methods = { | | 302 | Static const struct usbd_pipe_methods ohci_device_ctrl_methods = { |
303 | .upm_init = ohci_device_ctrl_init, | | 303 | .upm_init = ohci_device_ctrl_init, |
304 | .upm_fini = ohci_device_ctrl_fini, | | 304 | .upm_fini = ohci_device_ctrl_fini, |
305 | .upm_transfer = ohci_device_ctrl_transfer, | | 305 | .upm_transfer = ohci_device_ctrl_transfer, |
306 | .upm_start = ohci_device_ctrl_start, | | 306 | .upm_start = ohci_device_ctrl_start, |
307 | .upm_abort = ohci_device_ctrl_abort, | | 307 | .upm_abort = ohci_device_ctrl_abort, |
308 | .upm_close = ohci_device_ctrl_close, | | 308 | .upm_close = ohci_device_ctrl_close, |
309 | .upm_cleartoggle = ohci_noop, | | 309 | .upm_cleartoggle = ohci_noop, |
310 | .upm_done = ohci_device_ctrl_done, | | 310 | .upm_done = ohci_device_ctrl_done, |
311 | }; | | 311 | }; |
312 | | | 312 | |
313 | Static const struct usbd_pipe_methods ohci_device_intr_methods = { | | 313 | Static const struct usbd_pipe_methods ohci_device_intr_methods = { |
314 | .upm_init = ohci_device_intr_init, | | 314 | .upm_init = ohci_device_intr_init, |
315 | .upm_fini = ohci_device_intr_fini, | | 315 | .upm_fini = ohci_device_intr_fini, |
316 | .upm_transfer = ohci_device_intr_transfer, | | 316 | .upm_transfer = ohci_device_intr_transfer, |
317 | .upm_start = ohci_device_intr_start, | | 317 | .upm_start = ohci_device_intr_start, |
318 | .upm_abort = ohci_device_intr_abort, | | 318 | .upm_abort = ohci_device_intr_abort, |
319 | .upm_close = ohci_device_intr_close, | | 319 | .upm_close = ohci_device_intr_close, |
320 | .upm_cleartoggle = ohci_device_clear_toggle, | | 320 | .upm_cleartoggle = ohci_device_clear_toggle, |
321 | .upm_done = ohci_device_intr_done, | | 321 | .upm_done = ohci_device_intr_done, |
322 | }; | | 322 | }; |
323 | | | 323 | |
324 | Static const struct usbd_pipe_methods ohci_device_bulk_methods = { | | 324 | Static const struct usbd_pipe_methods ohci_device_bulk_methods = { |
325 | .upm_init = ohci_device_bulk_init, | | 325 | .upm_init = ohci_device_bulk_init, |
326 | .upm_fini = ohci_device_bulk_fini, | | 326 | .upm_fini = ohci_device_bulk_fini, |
327 | .upm_transfer = ohci_device_bulk_transfer, | | 327 | .upm_transfer = ohci_device_bulk_transfer, |
328 | .upm_start = ohci_device_bulk_start, | | 328 | .upm_start = ohci_device_bulk_start, |
329 | .upm_abort = ohci_device_bulk_abort, | | 329 | .upm_abort = ohci_device_bulk_abort, |
330 | .upm_close = ohci_device_bulk_close, | | 330 | .upm_close = ohci_device_bulk_close, |
331 | .upm_cleartoggle = ohci_device_clear_toggle, | | 331 | .upm_cleartoggle = ohci_device_clear_toggle, |
332 | .upm_done = ohci_device_bulk_done, | | 332 | .upm_done = ohci_device_bulk_done, |
333 | }; | | 333 | }; |
334 | | | 334 | |
335 | Static const struct usbd_pipe_methods ohci_device_isoc_methods = { | | 335 | Static const struct usbd_pipe_methods ohci_device_isoc_methods = { |
336 | .upm_init = ohci_device_isoc_init, | | 336 | .upm_init = ohci_device_isoc_init, |
337 | .upm_fini = ohci_device_isoc_fini, | | 337 | .upm_fini = ohci_device_isoc_fini, |
338 | .upm_transfer = ohci_device_isoc_transfer, | | 338 | .upm_transfer = ohci_device_isoc_transfer, |
339 | .upm_abort = ohci_device_isoc_abort, | | 339 | .upm_abort = ohci_device_isoc_abort, |
340 | .upm_close = ohci_device_isoc_close, | | 340 | .upm_close = ohci_device_isoc_close, |
341 | .upm_cleartoggle = ohci_noop, | | 341 | .upm_cleartoggle = ohci_noop, |
342 | .upm_done = ohci_device_isoc_done, | | 342 | .upm_done = ohci_device_isoc_done, |
343 | }; | | 343 | }; |
344 | | | 344 | |
345 | int | | 345 | int |
346 | ohci_activate(device_t self, enum devact act) | | 346 | ohci_activate(device_t self, enum devact act) |
347 | { | | 347 | { |
348 | struct ohci_softc *sc = device_private(self); | | 348 | struct ohci_softc *sc = device_private(self); |
349 | | | 349 | |
350 | switch (act) { | | 350 | switch (act) { |
351 | case DVACT_DEACTIVATE: | | 351 | case DVACT_DEACTIVATE: |
352 | sc->sc_dying = 1; | | 352 | sc->sc_dying = 1; |
353 | return 0; | | 353 | return 0; |
354 | default: | | 354 | default: |
355 | return EOPNOTSUPP; | | 355 | return EOPNOTSUPP; |
356 | } | | 356 | } |
357 | } | | 357 | } |
358 | | | 358 | |
359 | void | | 359 | void |
360 | ohci_childdet(device_t self, device_t child) | | 360 | ohci_childdet(device_t self, device_t child) |
361 | { | | 361 | { |
362 | struct ohci_softc *sc = device_private(self); | | 362 | struct ohci_softc *sc = device_private(self); |
363 | | | 363 | |
364 | KASSERT(sc->sc_child == child); | | 364 | KASSERT(sc->sc_child == child); |
365 | sc->sc_child = NULL; | | 365 | sc->sc_child = NULL; |
366 | } | | 366 | } |
367 | | | 367 | |
368 | int | | 368 | int |
369 | ohci_detach(struct ohci_softc *sc, int flags) | | 369 | ohci_detach(struct ohci_softc *sc, int flags) |
370 | { | | 370 | { |
371 | int rv = 0; | | 371 | int rv = 0; |
372 | | | 372 | |
373 | if (sc->sc_child != NULL) | | 373 | if (sc->sc_child != NULL) |
374 | rv = config_detach(sc->sc_child, flags); | | 374 | rv = config_detach(sc->sc_child, flags); |
375 | | | 375 | |
376 | if (rv != 0) | | 376 | if (rv != 0) |
377 | return rv; | | 377 | return rv; |
378 | | | 378 | |
379 | callout_halt(&sc->sc_tmo_rhsc, &sc->sc_lock); | | 379 | callout_halt(&sc->sc_tmo_rhsc, &sc->sc_lock); |
380 | | | 380 | |
381 | usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ | | 381 | usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ |
382 | callout_destroy(&sc->sc_tmo_rhsc); | | 382 | callout_destroy(&sc->sc_tmo_rhsc); |
383 | | | 383 | |
384 | softint_disestablish(sc->sc_rhsc_si); | | 384 | softint_disestablish(sc->sc_rhsc_si); |
385 | | | 385 | |
386 | cv_destroy(&sc->sc_softwake_cv); | | 386 | cv_destroy(&sc->sc_softwake_cv); |
387 | | | 387 | |
388 | mutex_destroy(&sc->sc_lock); | | 388 | mutex_destroy(&sc->sc_lock); |
389 | mutex_destroy(&sc->sc_intr_lock); | | 389 | mutex_destroy(&sc->sc_intr_lock); |
390 | | | 390 | |
391 | if (sc->sc_hcca != NULL) | | 391 | if (sc->sc_hcca != NULL) |
392 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | | 392 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); |
393 | pool_cache_destroy(sc->sc_xferpool); | | 393 | pool_cache_destroy(sc->sc_xferpool); |
394 | | | 394 | |
395 | return rv; | | 395 | return rv; |
396 | } | | 396 | } |
397 | | | 397 | |
398 | ohci_soft_ed_t * | | 398 | ohci_soft_ed_t * |
399 | ohci_alloc_sed(ohci_softc_t *sc) | | 399 | ohci_alloc_sed(ohci_softc_t *sc) |
400 | { | | 400 | { |
401 | ohci_soft_ed_t *sed; | | 401 | ohci_soft_ed_t *sed; |
402 | usbd_status err; | | 402 | usbd_status err; |
403 | int i, offs; | | 403 | int i, offs; |
404 | usb_dma_t dma; | | 404 | usb_dma_t dma; |
405 | | | 405 | |
406 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 406 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
407 | | | 407 | |
408 | mutex_enter(&sc->sc_lock); | | 408 | mutex_enter(&sc->sc_lock); |
409 | if (sc->sc_freeeds == NULL) { | | 409 | if (sc->sc_freeeds == NULL) { |
410 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); | | 410 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); |
411 | mutex_exit(&sc->sc_lock); | | 411 | mutex_exit(&sc->sc_lock); |
412 | | | 412 | |
413 | err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK, | | 413 | err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK, |
414 | OHCI_ED_ALIGN, &dma); | | 414 | OHCI_ED_ALIGN, &dma); |
415 | if (err) | | 415 | if (err) |
416 | return 0; | | 416 | return 0; |
417 | | | 417 | |
418 | mutex_enter(&sc->sc_lock); | | 418 | mutex_enter(&sc->sc_lock); |
419 | for (i = 0; i < OHCI_SED_CHUNK; i++) { | | 419 | for (i = 0; i < OHCI_SED_CHUNK; i++) { |
420 | offs = i * OHCI_SED_SIZE; | | 420 | offs = i * OHCI_SED_SIZE; |
421 | sed = KERNADDR(&dma, offs); | | 421 | sed = KERNADDR(&dma, offs); |
422 | sed->physaddr = DMAADDR(&dma, offs); | | 422 | sed->physaddr = DMAADDR(&dma, offs); |
423 | sed->dma = dma; | | 423 | sed->dma = dma; |
424 | sed->offs = offs; | | 424 | sed->offs = offs; |
425 | sed->next = sc->sc_freeeds; | | 425 | sed->next = sc->sc_freeeds; |
426 | sc->sc_freeeds = sed; | | 426 | sc->sc_freeeds = sed; |
427 | } | | 427 | } |
428 | } | | 428 | } |
429 | sed = sc->sc_freeeds; | | 429 | sed = sc->sc_freeeds; |
430 | sc->sc_freeeds = sed->next; | | 430 | sc->sc_freeeds = sed->next; |
431 | mutex_exit(&sc->sc_lock); | | 431 | mutex_exit(&sc->sc_lock); |
432 | | | 432 | |
433 | memset(&sed->ed, 0, sizeof(ohci_ed_t)); | | 433 | memset(&sed->ed, 0, sizeof(ohci_ed_t)); |
434 | sed->next = 0; | | 434 | sed->next = 0; |
435 | return sed; | | 435 | return sed; |
436 | } | | 436 | } |
437 | | | 437 | |
438 | static inline void | | 438 | static inline void |
439 | ohci_free_sed_locked(ohci_softc_t *sc, ohci_soft_ed_t *sed) | | 439 | ohci_free_sed_locked(ohci_softc_t *sc, ohci_soft_ed_t *sed) |
440 | { | | 440 | { |
441 | | | 441 | |
442 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 442 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
443 | | | 443 | |
444 | sed->next = sc->sc_freeeds; | | 444 | sed->next = sc->sc_freeeds; |
445 | sc->sc_freeeds = sed; | | 445 | sc->sc_freeeds = sed; |
446 | } | | 446 | } |
447 | | | 447 | |
448 | void | | 448 | void |
449 | ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed) | | 449 | ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed) |
450 | { | | 450 | { |
451 | | | 451 | |
452 | mutex_enter(&sc->sc_lock); | | 452 | mutex_enter(&sc->sc_lock); |
453 | ohci_free_sed_locked(sc, sed); | | 453 | ohci_free_sed_locked(sc, sed); |
454 | mutex_exit(&sc->sc_lock); | | 454 | mutex_exit(&sc->sc_lock); |
455 | } | | 455 | } |
456 | | | 456 | |
457 | ohci_soft_td_t * | | 457 | ohci_soft_td_t * |
458 | ohci_alloc_std(ohci_softc_t *sc) | | 458 | ohci_alloc_std(ohci_softc_t *sc) |
459 | { | | 459 | { |
460 | ohci_soft_td_t *std; | | 460 | ohci_soft_td_t *std; |
461 | usbd_status err; | | 461 | usbd_status err; |
462 | int i, offs; | | 462 | int i, offs; |
463 | usb_dma_t dma; | | 463 | usb_dma_t dma; |
464 | | | 464 | |
465 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 465 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
466 | | | 466 | |
467 | mutex_enter(&sc->sc_lock); | | 467 | mutex_enter(&sc->sc_lock); |
468 | if (sc->sc_freetds == NULL) { | | 468 | if (sc->sc_freetds == NULL) { |
469 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); | | 469 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); |
470 | mutex_exit(&sc->sc_lock); | | 470 | mutex_exit(&sc->sc_lock); |
471 | | | 471 | |
472 | err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK, | | 472 | err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK, |
473 | OHCI_TD_ALIGN, &dma); | | 473 | OHCI_TD_ALIGN, &dma); |
474 | if (err) | | 474 | if (err) |
475 | return NULL; | | 475 | return NULL; |
476 | | | 476 | |
477 | mutex_enter(&sc->sc_lock); | | 477 | mutex_enter(&sc->sc_lock); |
478 | for (i = 0; i < OHCI_STD_CHUNK; i++) { | | 478 | for (i = 0; i < OHCI_STD_CHUNK; i++) { |
479 | offs = i * OHCI_STD_SIZE; | | 479 | offs = i * OHCI_STD_SIZE; |
480 | std = KERNADDR(&dma, offs); | | 480 | std = KERNADDR(&dma, offs); |
481 | std->physaddr = DMAADDR(&dma, offs); | | 481 | std->physaddr = DMAADDR(&dma, offs); |
482 | std->dma = dma; | | 482 | std->dma = dma; |
483 | std->offs = offs; | | 483 | std->offs = offs; |
484 | std->nexttd = sc->sc_freetds; | | 484 | std->nexttd = sc->sc_freetds; |
485 | sc->sc_freetds = std; | | 485 | sc->sc_freetds = std; |
486 | } | | 486 | } |
487 | } | | 487 | } |
488 | | | 488 | |
489 | std = sc->sc_freetds; | | 489 | std = sc->sc_freetds; |
490 | sc->sc_freetds = std->nexttd; | | 490 | sc->sc_freetds = std->nexttd; |
491 | mutex_exit(&sc->sc_lock); | | 491 | mutex_exit(&sc->sc_lock); |
492 | | | 492 | |
493 | memset(&std->td, 0, sizeof(ohci_td_t)); | | 493 | memset(&std->td, 0, sizeof(ohci_td_t)); |
494 | std->nexttd = NULL; | | 494 | std->nexttd = NULL; |
495 | std->xfer = NULL; | | 495 | std->xfer = NULL; |
496 | | | 496 | |
497 | return std; | | 497 | return std; |
498 | } | | 498 | } |
499 | | | 499 | |
500 | void | | 500 | void |
501 | ohci_free_std_locked(ohci_softc_t *sc, ohci_soft_td_t *std) | | 501 | ohci_free_std_locked(ohci_softc_t *sc, ohci_soft_td_t *std) |
502 | { | | 502 | { |
503 | | | 503 | |
504 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 504 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
505 | | | 505 | |
506 | std->nexttd = sc->sc_freetds; | | 506 | std->nexttd = sc->sc_freetds; |
507 | sc->sc_freetds = std; | | 507 | sc->sc_freetds = std; |
508 | } | | 508 | } |
509 | | | 509 | |
510 | void | | 510 | void |
511 | ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std) | | 511 | ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std) |
512 | { | | 512 | { |
513 | | | 513 | |
514 | mutex_enter(&sc->sc_lock); | | 514 | mutex_enter(&sc->sc_lock); |
515 | ohci_free_std_locked(sc, std); | | 515 | ohci_free_std_locked(sc, std); |
516 | mutex_exit(&sc->sc_lock); | | 516 | mutex_exit(&sc->sc_lock); |
517 | } | | 517 | } |
518 | | | 518 | |
519 | Static usbd_status | | 519 | Static usbd_status |
520 | ohci_alloc_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, int alen, int rd) | | 520 | ohci_alloc_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, int alen, int rd) |
521 | { | | 521 | { |
522 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 522 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
523 | struct usbd_pipe *pipe = xfer->ux_pipe; | | 523 | struct usbd_pipe *pipe = xfer->ux_pipe; |
524 | ohci_soft_td_t *next, *cur; | | 524 | ohci_soft_td_t *next, *cur; |
525 | ohci_physaddr_t dataphys, dataphysend; | | 525 | ohci_physaddr_t dataphys, dataphysend; |
526 | int len = alen; | | 526 | int len = alen; |
527 | int curlen; | | 527 | int curlen; |
528 | usb_dma_t *dma = &xfer->ux_dmabuf; | | 528 | usb_dma_t *dma = &xfer->ux_dmabuf; |
529 | uint16_t flags = xfer->ux_flags; | | 529 | uint16_t flags = xfer->ux_flags; |
530 | | | 530 | |
531 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 531 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
532 | | | 532 | |
533 | DPRINTFN(8, "addr=%d endpt=%d len=%d speed=%d", | | 533 | DPRINTFN(8, "addr=%d endpt=%d len=%d speed=%d", |
534 | pipe->up_dev->ud_addr, | | 534 | pipe->up_dev->ud_addr, |
535 | UE_GET_ADDR(pipe->up_endpoint->ue_edesc->bEndpointAddress), | | 535 | UE_GET_ADDR(pipe->up_endpoint->ue_edesc->bEndpointAddress), |
536 | alen, pipe->up_dev->ud_speed); | | 536 | alen, pipe->up_dev->ud_speed); |
537 | | | 537 | |
538 | ASSERT_SLEEPABLE(); | | 538 | ASSERT_SLEEPABLE(); |
539 | | | 539 | |
540 | size_t nstd = (flags & USBD_FORCE_SHORT_XFER) ? 1 : 0; | | 540 | size_t nstd = (flags & USBD_FORCE_SHORT_XFER) ? 1 : 0; |
541 | nstd += ((len + OHCI_PAGE_SIZE - 1) / OHCI_PAGE_SIZE); | | 541 | nstd += ((len + OHCI_PAGE_SIZE - 1) / OHCI_PAGE_SIZE); |
542 | ox->ox_stds = kmem_zalloc(sizeof(ohci_soft_td_t *) * nstd, | | 542 | ox->ox_stds = kmem_zalloc(sizeof(ohci_soft_td_t *) * nstd, |
543 | KM_SLEEP); | | 543 | KM_SLEEP); |
544 | ox->ox_nstd = nstd; | | 544 | ox->ox_nstd = nstd; |
545 | int mps = UGETW(pipe->up_endpoint->ue_edesc->wMaxPacketSize); | | 545 | int mps = UGETW(pipe->up_endpoint->ue_edesc->wMaxPacketSize); |
546 | | | 546 | |
547 | DPRINTFN(8, "xfer %p nstd %d mps %d", xfer, nstd, mps, 0); | | 547 | DPRINTFN(8, "xfer %p nstd %d mps %d", xfer, nstd, mps, 0); |
548 | | | 548 | |
549 | len = alen; | | 549 | len = alen; |
550 | cur = ohci_alloc_std(sc); | | 550 | cur = ohci_alloc_std(sc); |
551 | if (cur == NULL) | | 551 | if (cur == NULL) |
552 | goto nomem; | | 552 | goto nomem; |
553 | | | 553 | |
554 | dataphys = DMAADDR(dma, 0); | | 554 | dataphys = DMAADDR(dma, 0); |
555 | dataphysend = OHCI_PAGE(dataphys + len - 1); | | 555 | dataphysend = OHCI_PAGE(dataphys + len - 1); |
556 | const uint32_t tdflags = HTOO32( | | 556 | const uint32_t tdflags = HTOO32( |
557 | (rd ? OHCI_TD_IN : OHCI_TD_OUT) | | | 557 | (rd ? OHCI_TD_IN : OHCI_TD_OUT) | |
558 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); | | 558 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); |
559 | | | 559 | |
560 | for (size_t j = 0;;) { | | 560 | for (size_t j = 0;;) { |
561 | ox->ox_stds[j++] = cur; | | 561 | ox->ox_stds[j++] = cur; |
562 | next = ohci_alloc_std(sc); | | 562 | next = ohci_alloc_std(sc); |
563 | if (next == NULL) | | 563 | if (next == NULL) |
564 | goto nomem; | | 564 | goto nomem; |
565 | | | 565 | |
566 | /* The OHCI hardware can handle at most one page crossing. */ | | 566 | /* The OHCI hardware can handle at most one page crossing. */ |
567 | if (OHCI_PAGE(dataphys) == dataphysend || | | 567 | if (OHCI_PAGE(dataphys) == dataphysend || |
568 | OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) { | | 568 | OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) { |
569 | /* we can handle it in this TD */ | | 569 | /* we can handle it in this TD */ |
570 | curlen = len; | | 570 | curlen = len; |
571 | } else { | | 571 | } else { |
572 | /* must use multiple TDs, fill as much as possible. */ | | 572 | /* must use multiple TDs, fill as much as possible. */ |
573 | curlen = 2 * OHCI_PAGE_SIZE - | | 573 | curlen = 2 * OHCI_PAGE_SIZE - |
574 | (dataphys & (OHCI_PAGE_SIZE - 1)); | | 574 | (dataphys & (OHCI_PAGE_SIZE - 1)); |
575 | /* the length must be a multiple of the max size */ | | 575 | /* the length must be a multiple of the max size */ |
576 | curlen -= curlen % mps; | | 576 | curlen -= curlen % mps; |
577 | KASSERT(curlen != 0); | | 577 | KASSERT(curlen != 0); |
578 | } | | 578 | } |
579 | DPRINTFN(4, "dataphys=0x%08x dataphysend=0x%08x " | | 579 | DPRINTFN(4, "dataphys=0x%08x dataphysend=0x%08x " |
580 | "len=%d curlen=%d", dataphys, dataphysend, len, curlen); | | 580 | "len=%d curlen=%d", dataphys, dataphysend, len, curlen); |
581 | len -= curlen; | | 581 | len -= curlen; |
582 | | | 582 | |
583 | cur->td.td_flags = tdflags; | | 583 | cur->td.td_flags = tdflags; |
584 | cur->td.td_cbp = HTOO32(dataphys); | | 584 | cur->td.td_cbp = HTOO32(dataphys); |
585 | cur->td.td_nexttd = HTOO32(next->physaddr); | | 585 | cur->td.td_nexttd = HTOO32(next->physaddr); |
586 | cur->td.td_be = HTOO32(dataphys + curlen - 1); | | 586 | cur->td.td_be = HTOO32(dataphys + curlen - 1); |
587 | cur->nexttd = next; | | 587 | cur->nexttd = next; |
588 | cur->len = curlen; | | 588 | cur->len = curlen; |
589 | cur->flags = OHCI_ADD_LEN; | | 589 | cur->flags = OHCI_ADD_LEN; |
590 | cur->xfer = xfer; | | 590 | cur->xfer = xfer; |
591 | | | 591 | |
592 | DPRINTFN(10, "cbp=0x%08x be=0x%08x", dataphys, | | 592 | DPRINTFN(10, "cbp=0x%08x be=0x%08x", dataphys, |
593 | dataphys + curlen - 1, 0, 0); | | 593 | dataphys + curlen - 1, 0, 0); |
594 | if (len == 0) | | 594 | if (len == 0) |
595 | break; | | 595 | break; |
596 | DPRINTFN(10, "extend chain", 0, 0, 0, 0); | | 596 | DPRINTFN(10, "extend chain", 0, 0, 0, 0); |
597 | dataphys += curlen; | | 597 | dataphys += curlen; |
598 | cur = next; | | 598 | cur = next; |
599 | } | | 599 | } |
600 | if (!rd && (flags & USBD_FORCE_SHORT_XFER) && | | 600 | if (!rd && (flags & USBD_FORCE_SHORT_XFER) && |
601 | alen % mps == 0) { | | 601 | alen % mps == 0) { |
602 | /* Force a 0 length transfer at the end. */ | | 602 | /* Force a 0 length transfer at the end. */ |
603 | | | 603 | |
604 | cur = next; | | 604 | cur = next; |
605 | next = ohci_alloc_std(sc); | | 605 | next = ohci_alloc_std(sc); |
606 | if (next == NULL) | | 606 | if (next == NULL) |
607 | goto nomem; | | 607 | goto nomem; |
608 | | | 608 | |
609 | cur->td.td_flags = tdflags; | | 609 | cur->td.td_flags = tdflags; |
610 | cur->td.td_cbp = 0; /* indicate 0 length packet */ | | 610 | cur->td.td_cbp = 0; /* indicate 0 length packet */ |
611 | cur->td.td_nexttd = HTOO32(next->physaddr); | | 611 | cur->td.td_nexttd = HTOO32(next->physaddr); |
612 | cur->td.td_be = ~0; | | 612 | cur->td.td_be = ~0; |
613 | cur->nexttd = next; | | 613 | cur->nexttd = next; |
614 | cur->len = 0; | | 614 | cur->len = 0; |
615 | cur->flags = 0; | | 615 | cur->flags = 0; |
616 | cur->xfer = xfer; | | 616 | cur->xfer = xfer; |
617 | | | 617 | |
618 | DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0); | | 618 | DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0); |
619 | } | | 619 | } |
620 | | | 620 | |
621 | return USBD_NORMAL_COMPLETION; | | 621 | return USBD_NORMAL_COMPLETION; |
622 | | | 622 | |
623 | nomem: | | 623 | nomem: |
624 | ohci_free_stds(sc, ox); | | 624 | ohci_free_stds(sc, ox); |
625 | | | 625 | |
626 | return USBD_NOMEM; | | 626 | return USBD_NOMEM; |
627 | } | | 627 | } |
628 | | | 628 | |
629 | Static void | | 629 | Static void |
630 | ohci_free_stds(ohci_softc_t *sc, struct ohci_xfer *ox) | | 630 | ohci_free_stds(ohci_softc_t *sc, struct ohci_xfer *ox) |
631 | { | | 631 | { |
632 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 632 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
633 | DPRINTF("ox=%p", ox, 0, 0, 0); | | 633 | DPRINTF("ox=%p", ox, 0, 0, 0); |
634 | | | 634 | |
635 | mutex_enter(&sc->sc_lock); | | 635 | mutex_enter(&sc->sc_lock); |
636 | for (size_t i = 0; i < ox->ox_nstd; i++) { | | 636 | for (size_t i = 0; i < ox->ox_nstd; i++) { |
637 | ohci_soft_td_t *std = ox->ox_stds[i]; | | 637 | ohci_soft_td_t *std = ox->ox_stds[i]; |
638 | if (std == NULL) | | 638 | if (std == NULL) |
639 | break; | | 639 | break; |
640 | ohci_free_std_locked(sc, std); | | 640 | ohci_free_std_locked(sc, std); |
641 | } | | 641 | } |
642 | mutex_exit(&sc->sc_lock); | | 642 | mutex_exit(&sc->sc_lock); |
643 | } | | 643 | } |
644 | | | 644 | |
645 | void | | 645 | void |
646 | ohci_reset_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, | | 646 | ohci_reset_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, |
647 | int alen, int rd, ohci_soft_td_t *sp, ohci_soft_td_t **ep) | | 647 | int alen, int rd, ohci_soft_td_t *sp, ohci_soft_td_t **ep) |
648 | { | | 648 | { |
649 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 649 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
650 | ohci_soft_td_t *next, *cur; | | 650 | ohci_soft_td_t *next, *cur; |
651 | ohci_physaddr_t dataphys, dataphysend; | | 651 | ohci_physaddr_t dataphys, dataphysend; |
652 | int len, curlen; | | 652 | int len, curlen; |
653 | usb_dma_t *dma = &xfer->ux_dmabuf; | | 653 | usb_dma_t *dma = &xfer->ux_dmabuf; |
654 | uint16_t flags = xfer->ux_flags; | | 654 | uint16_t flags = xfer->ux_flags; |
655 | | | 655 | |
656 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 656 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
657 | DPRINTF("start len=%d", alen, 0, 0, 0); | | 657 | DPRINTF("start len=%d", alen, 0, 0, 0); |
658 | | | 658 | |
659 | KASSERT(mutex_owned(&sc->sc_lock)); | | 659 | KASSERT(mutex_owned(&sc->sc_lock)); |
660 | | | 660 | |
661 | DPRINTFN(8, "addr=%d endpt=%d len=%d speed=%d", | | 661 | DPRINTFN(8, "addr=%d endpt=%d len=%d speed=%d", |
662 | xfer->ux_pipe->up_dev->ud_addr, | | 662 | xfer->ux_pipe->up_dev->ud_addr, |
663 | UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress), | | 663 | UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress), |
664 | alen, xfer->ux_pipe->up_dev->ud_speed); | | 664 | alen, xfer->ux_pipe->up_dev->ud_speed); |
665 | | | 665 | |
666 | KASSERT(sp); | | 666 | KASSERT(sp); |
667 | | | 667 | |
668 | int mps = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize); | | 668 | int mps = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize); |
669 | | | 669 | |
670 | len = alen; | | 670 | len = alen; |
671 | cur = sp; | | 671 | cur = sp; |
672 | | | 672 | |
673 | dataphys = DMAADDR(dma, 0); | | 673 | dataphys = DMAADDR(dma, 0); |
674 | dataphysend = OHCI_PAGE(dataphys + len - 1); | | 674 | dataphysend = OHCI_PAGE(dataphys + len - 1); |
675 | usb_syncmem(dma, 0, len, | | 675 | usb_syncmem(dma, 0, len, |
676 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | | 676 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); |
677 | const uint32_t tdflags = HTOO32( | | 677 | const uint32_t tdflags = HTOO32( |
678 | (rd ? OHCI_TD_IN : OHCI_TD_OUT) | | | 678 | (rd ? OHCI_TD_IN : OHCI_TD_OUT) | |
679 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); | | 679 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); |
680 | | | 680 | |
681 | for (size_t j = 1;;) { | | 681 | for (size_t j = 1;;) { |
682 | if (j == ox->ox_nstd) | | 682 | if (j == ox->ox_nstd) |
683 | next = NULL; | | 683 | next = NULL; |
684 | else | | 684 | else |
685 | next = ox->ox_stds[j++]; | | 685 | next = ox->ox_stds[j++]; |
686 | KASSERT(next != cur); | | 686 | KASSERT(next != cur); |
687 | | | 687 | |
688 | /* The OHCI hardware can handle at most one page crossing. */ | | 688 | /* The OHCI hardware can handle at most one page crossing. */ |
689 | if (OHCI_PAGE(dataphys) == dataphysend || | | 689 | if (OHCI_PAGE(dataphys) == dataphysend || |
690 | OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) { | | 690 | OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) { |
691 | /* we can handle it in this TD */ | | 691 | /* we can handle it in this TD */ |
692 | curlen = len; | | 692 | curlen = len; |
693 | } else { | | 693 | } else { |
694 | /* must use multiple TDs, fill as much as possible. */ | | 694 | /* must use multiple TDs, fill as much as possible. */ |
695 | curlen = 2 * OHCI_PAGE_SIZE - | | 695 | curlen = 2 * OHCI_PAGE_SIZE - |
696 | (dataphys & (OHCI_PAGE_SIZE - 1)); | | 696 | (dataphys & (OHCI_PAGE_SIZE - 1)); |
697 | /* the length must be a multiple of the max size */ | | 697 | /* the length must be a multiple of the max size */ |
698 | curlen -= curlen % mps; | | 698 | curlen -= curlen % mps; |
699 | KASSERT(curlen != 0); | | 699 | KASSERT(curlen != 0); |
700 | } | | 700 | } |
701 | DPRINTFN(4, "dataphys=0x%08x dataphysend=0x%08x " | | 701 | DPRINTFN(4, "dataphys=0x%08x dataphysend=0x%08x " |
702 | "len=%d curlen=%d", dataphys, dataphysend, len, curlen); | | 702 | "len=%d curlen=%d", dataphys, dataphysend, len, curlen); |
703 | len -= curlen; | | 703 | len -= curlen; |
704 | | | 704 | |
705 | cur->td.td_flags = tdflags; | | 705 | cur->td.td_flags = tdflags; |
706 | cur->td.td_cbp = HTOO32(dataphys); | | 706 | cur->td.td_cbp = HTOO32(dataphys); |
707 | cur->td.td_be = HTOO32(dataphys + curlen - 1); | | 707 | cur->td.td_be = HTOO32(dataphys + curlen - 1); |
708 | cur->td.td_nexttd = (next != NULL) ? HTOO32(next->physaddr) : 0; | | 708 | cur->td.td_nexttd = (next != NULL) ? HTOO32(next->physaddr) : 0; |
709 | cur->nexttd = next; | | 709 | cur->nexttd = next; |
710 | cur->len = curlen; | | 710 | cur->len = curlen; |
711 | cur->flags = OHCI_ADD_LEN; | | 711 | cur->flags = OHCI_ADD_LEN; |
712 | cur->xfer = xfer; | | 712 | cur->xfer = xfer; |
713 | ohci_hash_add_td(sc, cur); | | 713 | ohci_hash_add_td(sc, cur); |
714 | | | 714 | |
715 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), | | 715 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), |
716 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 716 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
717 | DPRINTFN(10, "cbp=0x%08x be=0x%08x", dataphys, | | 717 | DPRINTFN(10, "cbp=0x%08x be=0x%08x", dataphys, |
718 | dataphys + curlen - 1, 0, 0); | | 718 | dataphys + curlen - 1, 0, 0); |
719 | if (len == 0) | | 719 | if (len == 0) |
720 | break; | | 720 | break; |
721 | KASSERT(next != NULL); | | 721 | KASSERT(next != NULL); |
722 | DPRINTFN(10, "extend chain", 0, 0, 0, 0); | | 722 | DPRINTFN(10, "extend chain", 0, 0, 0, 0); |
723 | dataphys += curlen; | | 723 | dataphys += curlen; |
724 | cur = next; | | 724 | cur = next; |
725 | } | | 725 | } |
726 | cur->td.td_flags |= | | 726 | cur->td.td_flags |= |
727 | (xfer->ux_flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0); | | 727 | (xfer->ux_flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0); |
728 | | | 728 | |
729 | if (!rd && | | 729 | if (!rd && |
730 | (flags & USBD_FORCE_SHORT_XFER) && | | 730 | (flags & USBD_FORCE_SHORT_XFER) && |
731 | alen % mps == 0) { | | 731 | alen % mps == 0) { |
732 | /* Force a 0 length transfer at the end. */ | | 732 | /* Force a 0 length transfer at the end. */ |
733 | | | 733 | |
734 | KASSERT(next != NULL); | | 734 | KASSERT(next != NULL); |
735 | cur = next; | | 735 | cur = next; |
736 | | | 736 | |
737 | cur->td.td_flags = tdflags; | | 737 | cur->td.td_flags = tdflags; |
738 | cur->td.td_cbp = 0; /* indicate 0 length packet */ | | 738 | cur->td.td_cbp = 0; /* indicate 0 length packet */ |
739 | cur->td.td_nexttd = HTOO32(next->physaddr); | | 739 | cur->td.td_nexttd = HTOO32(next->physaddr); |
740 | cur->td.td_be = ~0; | | 740 | cur->td.td_be = ~0; |
741 | cur->nexttd = NULL; | | 741 | cur->nexttd = NULL; |
742 | cur->len = 0; | | 742 | cur->len = 0; |
743 | cur->flags = 0; | | 743 | cur->flags = 0; |
744 | cur->xfer = xfer; | | 744 | cur->xfer = xfer; |
745 | ohci_hash_add_td(sc, cur); | | 745 | ohci_hash_add_td(sc, cur); |
746 | | | 746 | |
747 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), | | 747 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), |
748 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 748 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
749 | DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0); | | 749 | DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0); |
750 | } | | 750 | } |
751 | *ep = cur; | | 751 | *ep = cur; |
752 | } | | 752 | } |
753 | | | 753 | |
754 | ohci_soft_itd_t * | | 754 | ohci_soft_itd_t * |
755 | ohci_alloc_sitd(ohci_softc_t *sc) | | 755 | ohci_alloc_sitd(ohci_softc_t *sc) |
756 | { | | 756 | { |
757 | ohci_soft_itd_t *sitd; | | 757 | ohci_soft_itd_t *sitd; |
758 | usbd_status err; | | 758 | usbd_status err; |
759 | int i, offs; | | 759 | int i, offs; |
760 | usb_dma_t dma; | | 760 | usb_dma_t dma; |
761 | | | 761 | |
762 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 762 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
763 | | | 763 | |
764 | mutex_enter(&sc->sc_lock); | | 764 | mutex_enter(&sc->sc_lock); |
765 | if (sc->sc_freeitds == NULL) { | | 765 | if (sc->sc_freeitds == NULL) { |
766 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); | | 766 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); |
767 | mutex_exit(&sc->sc_lock); | | 767 | mutex_exit(&sc->sc_lock); |
768 | | | 768 | |
769 | err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK, | | 769 | err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK, |
770 | OHCI_ITD_ALIGN, &dma); | | 770 | OHCI_ITD_ALIGN, &dma); |
771 | if (err) | | 771 | if (err) |
772 | return NULL; | | 772 | return NULL; |
773 | mutex_enter(&sc->sc_lock); | | 773 | mutex_enter(&sc->sc_lock); |
774 | for (i = 0; i < OHCI_SITD_CHUNK; i++) { | | 774 | for (i = 0; i < OHCI_SITD_CHUNK; i++) { |
775 | offs = i * OHCI_SITD_SIZE; | | 775 | offs = i * OHCI_SITD_SIZE; |
776 | sitd = KERNADDR(&dma, offs); | | 776 | sitd = KERNADDR(&dma, offs); |
777 | sitd->physaddr = DMAADDR(&dma, offs); | | 777 | sitd->physaddr = DMAADDR(&dma, offs); |
778 | sitd->dma = dma; | | 778 | sitd->dma = dma; |
779 | sitd->offs = offs; | | 779 | sitd->offs = offs; |
780 | sitd->nextitd = sc->sc_freeitds; | | 780 | sitd->nextitd = sc->sc_freeitds; |
781 | sc->sc_freeitds = sitd; | | 781 | sc->sc_freeitds = sitd; |
782 | } | | 782 | } |
783 | } | | 783 | } |
784 | | | 784 | |
785 | sitd = sc->sc_freeitds; | | 785 | sitd = sc->sc_freeitds; |
786 | sc->sc_freeitds = sitd->nextitd; | | 786 | sc->sc_freeitds = sitd->nextitd; |
787 | mutex_exit(&sc->sc_lock); | | 787 | mutex_exit(&sc->sc_lock); |
788 | | | 788 | |
789 | memset(&sitd->itd, 0, sizeof(ohci_itd_t)); | | 789 | memset(&sitd->itd, 0, sizeof(ohci_itd_t)); |
790 | sitd->nextitd = NULL; | | 790 | sitd->nextitd = NULL; |
791 | sitd->xfer = NULL; | | 791 | sitd->xfer = NULL; |
792 | | | 792 | |
793 | #ifdef DIAGNOSTIC | | 793 | #ifdef DIAGNOSTIC |
794 | sitd->isdone = true; | | 794 | sitd->isdone = true; |
795 | #endif | | 795 | #endif |
796 | | | 796 | |
797 | return sitd; | | 797 | return sitd; |
798 | } | | 798 | } |
799 | | | 799 | |
800 | Static void | | 800 | Static void |
801 | ohci_free_sitd_locked(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | | 801 | ohci_free_sitd_locked(ohci_softc_t *sc, ohci_soft_itd_t *sitd) |
802 | { | | 802 | { |
803 | | | 803 | |
804 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 804 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
805 | DPRINTFN(10, "sitd=%p", sitd, 0, 0, 0); | | 805 | DPRINTFN(10, "sitd=%p", sitd, 0, 0, 0); |
806 | | | 806 | |
807 | KASSERT(sitd->isdone); | | 807 | KASSERT(sitd->isdone); |
808 | #ifdef DIAGNOSTIC | | 808 | #ifdef DIAGNOSTIC |
809 | /* Warn double free */ | | 809 | /* Warn double free */ |
810 | sitd->isdone = false; | | 810 | sitd->isdone = false; |
811 | #endif | | 811 | #endif |
812 | | | 812 | |
813 | sitd->nextitd = sc->sc_freeitds; | | 813 | sitd->nextitd = sc->sc_freeitds; |
814 | sc->sc_freeitds = sitd; | | 814 | sc->sc_freeitds = sitd; |
815 | } | | 815 | } |
816 | | | 816 | |
817 | void | | 817 | void |
818 | ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | | 818 | ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) |
819 | { | | 819 | { |
820 | | | 820 | |
821 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 821 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
822 | | | 822 | |
823 | mutex_enter(&sc->sc_lock); | | 823 | mutex_enter(&sc->sc_lock); |
824 | ohci_free_sitd_locked(sc, sitd); | | 824 | ohci_free_sitd_locked(sc, sitd); |
825 | mutex_exit(&sc->sc_lock); | | 825 | mutex_exit(&sc->sc_lock); |
826 | } | | 826 | } |
827 | | | 827 | |
828 | int | | 828 | int |
829 | ohci_init(ohci_softc_t *sc) | | 829 | ohci_init(ohci_softc_t *sc) |
830 | { | | 830 | { |
831 | ohci_soft_ed_t *sed, *psed; | | 831 | ohci_soft_ed_t *sed, *psed; |
832 | usbd_status err; | | 832 | usbd_status err; |
833 | int i; | | 833 | int i; |
834 | uint32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca /*, descb */; | | 834 | uint32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca /*, descb */; |
835 | | | 835 | |
836 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 836 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
837 | | | 837 | |
838 | aprint_normal_dev(sc->sc_dev, ""); | | 838 | aprint_normal_dev(sc->sc_dev, ""); |
839 | | | 839 | |
840 | sc->sc_hcca = NULL; | | 840 | sc->sc_hcca = NULL; |
841 | callout_init(&sc->sc_tmo_rhsc, CALLOUT_MPSAFE); | | 841 | callout_init(&sc->sc_tmo_rhsc, CALLOUT_MPSAFE); |
842 | | | 842 | |
843 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | | 843 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); |
844 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | | 844 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); |
845 | cv_init(&sc->sc_softwake_cv, "ohciab"); | | 845 | cv_init(&sc->sc_softwake_cv, "ohciab"); |
846 | | | 846 | |
847 | sc->sc_rhsc_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | | 847 | sc->sc_rhsc_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, |
848 | ohci_rhsc_softint, sc); | | 848 | ohci_rhsc_softint, sc); |
849 | | | 849 | |
850 | for (i = 0; i < OHCI_HASH_SIZE; i++) | | 850 | for (i = 0; i < OHCI_HASH_SIZE; i++) |
851 | LIST_INIT(&sc->sc_hash_tds[i]); | | 851 | LIST_INIT(&sc->sc_hash_tds[i]); |
852 | for (i = 0; i < OHCI_HASH_SIZE; i++) | | 852 | for (i = 0; i < OHCI_HASH_SIZE; i++) |
853 | LIST_INIT(&sc->sc_hash_itds[i]); | | 853 | LIST_INIT(&sc->sc_hash_itds[i]); |
854 | | | 854 | |
855 | sc->sc_xferpool = pool_cache_init(sizeof(struct ohci_xfer), 0, 0, 0, | | 855 | sc->sc_xferpool = pool_cache_init(sizeof(struct ohci_xfer), 0, 0, 0, |
856 | "ohcixfer", NULL, IPL_USB, NULL, NULL, NULL); | | 856 | "ohcixfer", NULL, IPL_USB, NULL, NULL, NULL); |
857 | | | 857 | |
858 | rev = OREAD4(sc, OHCI_REVISION); | | 858 | rev = OREAD4(sc, OHCI_REVISION); |
859 | aprint_normal("OHCI version %d.%d%s\n", | | 859 | aprint_normal("OHCI version %d.%d%s\n", |
860 | OHCI_REV_HI(rev), OHCI_REV_LO(rev), | | 860 | OHCI_REV_HI(rev), OHCI_REV_LO(rev), |
861 | OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); | | 861 | OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); |
862 | | | 862 | |
863 | if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { | | 863 | if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { |
864 | aprint_error_dev(sc->sc_dev, "unsupported OHCI revision\n"); | | 864 | aprint_error_dev(sc->sc_dev, "unsupported OHCI revision\n"); |
865 | sc->sc_bus.ub_revision = USBREV_UNKNOWN; | | 865 | sc->sc_bus.ub_revision = USBREV_UNKNOWN; |
866 | return -1; | | 866 | return -1; |
867 | } | | 867 | } |
868 | sc->sc_bus.ub_revision = USBREV_1_0; | | 868 | sc->sc_bus.ub_revision = USBREV_1_0; |
869 | sc->sc_bus.ub_usedma = true; | | 869 | sc->sc_bus.ub_usedma = true; |
870 | | | 870 | |
871 | /* XXX determine alignment by R/W */ | | 871 | /* XXX determine alignment by R/W */ |
872 | /* Allocate the HCCA area. */ | | 872 | /* Allocate the HCCA area. */ |
873 | err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, | | 873 | err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, |
874 | OHCI_HCCA_ALIGN, &sc->sc_hccadma); | | 874 | OHCI_HCCA_ALIGN, &sc->sc_hccadma); |
875 | if (err) { | | 875 | if (err) { |
876 | sc->sc_hcca = NULL; | | 876 | sc->sc_hcca = NULL; |
877 | return err; | | 877 | return err; |
878 | } | | 878 | } |
879 | sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0); | | 879 | sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0); |
880 | memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE); | | 880 | memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE); |
881 | | | 881 | |
882 | sc->sc_eintrs = OHCI_NORMAL_INTRS; | | 882 | sc->sc_eintrs = OHCI_NORMAL_INTRS; |
883 | | | 883 | |
884 | /* Allocate dummy ED that starts the control list. */ | | 884 | /* Allocate dummy ED that starts the control list. */ |
885 | sc->sc_ctrl_head = ohci_alloc_sed(sc); | | 885 | sc->sc_ctrl_head = ohci_alloc_sed(sc); |
886 | if (sc->sc_ctrl_head == NULL) { | | 886 | if (sc->sc_ctrl_head == NULL) { |
887 | err = ENOMEM; | | 887 | err = ENOMEM; |
888 | goto bad1; | | 888 | goto bad1; |
889 | } | | 889 | } |
890 | sc->sc_ctrl_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 890 | sc->sc_ctrl_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
891 | | | 891 | |
892 | /* Allocate dummy ED that starts the bulk list. */ | | 892 | /* Allocate dummy ED that starts the bulk list. */ |
893 | sc->sc_bulk_head = ohci_alloc_sed(sc); | | 893 | sc->sc_bulk_head = ohci_alloc_sed(sc); |
894 | if (sc->sc_bulk_head == NULL) { | | 894 | if (sc->sc_bulk_head == NULL) { |
895 | err = ENOMEM; | | 895 | err = ENOMEM; |
896 | goto bad2; | | 896 | goto bad2; |
897 | } | | 897 | } |
898 | sc->sc_bulk_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 898 | sc->sc_bulk_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
899 | usb_syncmem(&sc->sc_bulk_head->dma, sc->sc_bulk_head->offs, | | 899 | usb_syncmem(&sc->sc_bulk_head->dma, sc->sc_bulk_head->offs, |
900 | sizeof(sc->sc_bulk_head->ed), | | 900 | sizeof(sc->sc_bulk_head->ed), |
901 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 901 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
902 | | | 902 | |
903 | /* Allocate dummy ED that starts the isochronous list. */ | | 903 | /* Allocate dummy ED that starts the isochronous list. */ |
904 | sc->sc_isoc_head = ohci_alloc_sed(sc); | | 904 | sc->sc_isoc_head = ohci_alloc_sed(sc); |
905 | if (sc->sc_isoc_head == NULL) { | | 905 | if (sc->sc_isoc_head == NULL) { |
906 | err = ENOMEM; | | 906 | err = ENOMEM; |
907 | goto bad3; | | 907 | goto bad3; |
908 | } | | 908 | } |
909 | sc->sc_isoc_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 909 | sc->sc_isoc_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
910 | usb_syncmem(&sc->sc_isoc_head->dma, sc->sc_isoc_head->offs, | | 910 | usb_syncmem(&sc->sc_isoc_head->dma, sc->sc_isoc_head->offs, |
911 | sizeof(sc->sc_isoc_head->ed), | | 911 | sizeof(sc->sc_isoc_head->ed), |
912 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 912 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
913 | | | 913 | |
914 | /* Allocate all the dummy EDs that make up the interrupt tree. */ | | 914 | /* Allocate all the dummy EDs that make up the interrupt tree. */ |
915 | for (i = 0; i < OHCI_NO_EDS; i++) { | | 915 | for (i = 0; i < OHCI_NO_EDS; i++) { |
916 | sed = ohci_alloc_sed(sc); | | 916 | sed = ohci_alloc_sed(sc); |
917 | if (sed == NULL) { | | 917 | if (sed == NULL) { |
918 | while (--i >= 0) | | 918 | while (--i >= 0) |
919 | ohci_free_sed(sc, sc->sc_eds[i]); | | 919 | ohci_free_sed(sc, sc->sc_eds[i]); |
920 | err = ENOMEM; | | 920 | err = ENOMEM; |
921 | goto bad4; | | 921 | goto bad4; |
922 | } | | 922 | } |
923 | /* All ED fields are set to 0. */ | | 923 | /* All ED fields are set to 0. */ |
924 | sc->sc_eds[i] = sed; | | 924 | sc->sc_eds[i] = sed; |
925 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 925 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
926 | if (i != 0) | | 926 | if (i != 0) |
927 | psed = sc->sc_eds[(i-1) / 2]; | | 927 | psed = sc->sc_eds[(i-1) / 2]; |
928 | else | | 928 | else |
929 | psed= sc->sc_isoc_head; | | 929 | psed= sc->sc_isoc_head; |
930 | sed->next = psed; | | 930 | sed->next = psed; |
931 | sed->ed.ed_nexted = HTOO32(psed->physaddr); | | 931 | sed->ed.ed_nexted = HTOO32(psed->physaddr); |
932 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 932 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
933 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 933 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
934 | } | | 934 | } |
935 | /* | | 935 | /* |
936 | * Fill HCCA interrupt table. The bit reversal is to get | | 936 | * Fill HCCA interrupt table. The bit reversal is to get |
937 | * the tree set up properly to spread the interrupts. | | 937 | * the tree set up properly to spread the interrupts. |
938 | */ | | 938 | */ |
939 | for (i = 0; i < OHCI_NO_INTRS; i++) | | 939 | for (i = 0; i < OHCI_NO_INTRS; i++) |
940 | sc->sc_hcca->hcca_interrupt_table[revbits[i]] = | | 940 | sc->sc_hcca->hcca_interrupt_table[revbits[i]] = |
941 | HTOO32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); | | 941 | HTOO32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); |
942 | usb_syncmem(&sc->sc_hccadma, 0, OHCI_HCCA_SIZE, | | 942 | usb_syncmem(&sc->sc_hccadma, 0, OHCI_HCCA_SIZE, |
943 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 943 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
944 | | | 944 | |
945 | #ifdef OHCI_DEBUG | | 945 | #ifdef OHCI_DEBUG |
946 | DPRINTFN(15, "--- dump start ---", 0, 0, 0 ,0); | | 946 | DPRINTFN(15, "--- dump start ---", 0, 0, 0 ,0); |
947 | if (ohcidebug >= 15) { | | 947 | if (ohcidebug >= 15) { |
948 | for (i = 0; i < OHCI_NO_EDS; i++) { | | 948 | for (i = 0; i < OHCI_NO_EDS; i++) { |
949 | DPRINTFN(15, "ed#%d ", i, 0, 0, 0); | | 949 | DPRINTFN(15, "ed#%d ", i, 0, 0, 0); |
950 | ohci_dump_ed(sc, sc->sc_eds[i]); | | 950 | ohci_dump_ed(sc, sc->sc_eds[i]); |
951 | } | | 951 | } |
952 | DPRINTFN(15, "iso", 0, 0, 0 ,0); | | 952 | DPRINTFN(15, "iso", 0, 0, 0 ,0); |
953 | ohci_dump_ed(sc, sc->sc_isoc_head); | | 953 | ohci_dump_ed(sc, sc->sc_isoc_head); |
954 | } | | 954 | } |
955 | DPRINTFN(15, "--- dump end ---", 0, 0, 0 ,0); | | 955 | DPRINTFN(15, "--- dump end ---", 0, 0, 0 ,0); |
956 | #endif | | 956 | #endif |
957 | | | 957 | |
958 | /* Preserve values programmed by SMM/BIOS but lost over reset. */ | | 958 | /* Preserve values programmed by SMM/BIOS but lost over reset. */ |
959 | ctl = OREAD4(sc, OHCI_CONTROL); | | 959 | ctl = OREAD4(sc, OHCI_CONTROL); |
960 | rwc = ctl & OHCI_RWC; | | 960 | rwc = ctl & OHCI_RWC; |
961 | fm = OREAD4(sc, OHCI_FM_INTERVAL); | | 961 | fm = OREAD4(sc, OHCI_FM_INTERVAL); |
962 | desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); | | 962 | desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); |
963 | /* descb = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); */ | | 963 | /* descb = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); */ |
964 | | | 964 | |
965 | /* Determine in what context we are running. */ | | 965 | /* Determine in what context we are running. */ |
966 | if (ctl & OHCI_IR) { | | 966 | if (ctl & OHCI_IR) { |
967 | /* SMM active, request change */ | | 967 | /* SMM active, request change */ |
968 | DPRINTF("SMM active, request owner change", 0, 0, 0, 0); | | 968 | DPRINTF("SMM active, request owner change", 0, 0, 0, 0); |
969 | if ((sc->sc_intre & (OHCI_OC | OHCI_MIE)) == | | 969 | if ((sc->sc_intre & (OHCI_OC | OHCI_MIE)) == |
970 | (OHCI_OC | OHCI_MIE)) | | 970 | (OHCI_OC | OHCI_MIE)) |
971 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_MIE); | | 971 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_MIE); |
972 | s = OREAD4(sc, OHCI_COMMAND_STATUS); | | 972 | s = OREAD4(sc, OHCI_COMMAND_STATUS); |
973 | OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR); | | 973 | OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR); |
974 | for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { | | 974 | for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { |
975 | usb_delay_ms(&sc->sc_bus, 1); | | 975 | usb_delay_ms(&sc->sc_bus, 1); |
976 | ctl = OREAD4(sc, OHCI_CONTROL); | | 976 | ctl = OREAD4(sc, OHCI_CONTROL); |
977 | } | | 977 | } |
978 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_MIE); | | 978 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_MIE); |
979 | if ((ctl & OHCI_IR) == 0) { | | 979 | if ((ctl & OHCI_IR) == 0) { |
980 | aprint_error_dev(sc->sc_dev, | | 980 | aprint_error_dev(sc->sc_dev, |
981 | "SMM does not respond, resetting\n"); | | 981 | "SMM does not respond, resetting\n"); |
982 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); | | 982 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); |
983 | goto reset; | | 983 | goto reset; |
984 | } | | 984 | } |
985 | #if 0 | | 985 | #if 0 |
986 | /* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */ | | 986 | /* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */ |
987 | } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { | | 987 | } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { |
988 | /* BIOS started controller. */ | | 988 | /* BIOS started controller. */ |
989 | DPRINTF("BIOS active", 0, 0, 0, 0); | | 989 | DPRINTF("BIOS active", 0, 0, 0, 0); |
990 | if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) { | | 990 | if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) { |
991 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL | rwc); | | 991 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL | rwc); |
992 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | | 992 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); |
993 | } | | 993 | } |
994 | #endif | | 994 | #endif |
995 | } else { | | 995 | } else { |
996 | DPRINTF("cold started", 0 ,0 ,0 ,0); | | 996 | DPRINTF("cold started", 0 ,0 ,0 ,0); |
997 | reset: | | 997 | reset: |
998 | /* Controller was cold started. */ | | 998 | /* Controller was cold started. */ |
999 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); | | 999 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); |
1000 | } | | 1000 | } |
1001 | | | 1001 | |
1002 | /* | | 1002 | /* |
1003 | * This reset should not be necessary according to the OHCI spec, but | | 1003 | * This reset should not be necessary according to the OHCI spec, but |
1004 | * without it some controllers do not start. | | 1004 | * without it some controllers do not start. |
1005 | */ | | 1005 | */ |
1006 | DPRINTF("sc %p: resetting", sc, 0, 0, 0); | | 1006 | DPRINTF("sc %p: resetting", sc, 0, 0, 0); |
1007 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); | | 1007 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); |
1008 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); | | 1008 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); |
1009 | | | 1009 | |
1010 | /* We now own the host controller and the bus has been reset. */ | | 1010 | /* We now own the host controller and the bus has been reset. */ |
1011 | | | 1011 | |
1012 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ | | 1012 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ |
1013 | /* Nominal time for a reset is 10 us. */ | | 1013 | /* Nominal time for a reset is 10 us. */ |
1014 | for (i = 0; i < 10; i++) { | | 1014 | for (i = 0; i < 10; i++) { |
1015 | delay(10); | | 1015 | delay(10); |
1016 | hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; | | 1016 | hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; |
1017 | if (!hcr) | | 1017 | if (!hcr) |
1018 | break; | | 1018 | break; |
1019 | } | | 1019 | } |
1020 | if (hcr) { | | 1020 | if (hcr) { |
1021 | aprint_error_dev(sc->sc_dev, "reset timeout\n"); | | 1021 | aprint_error_dev(sc->sc_dev, "reset timeout\n"); |
1022 | err = EIO; | | 1022 | err = EIO; |
1023 | goto bad5; | | 1023 | goto bad5; |
1024 | } | | 1024 | } |
1025 | #ifdef OHCI_DEBUG | | 1025 | #ifdef OHCI_DEBUG |
1026 | if (ohcidebug >= 15) | | 1026 | if (ohcidebug >= 15) |
1027 | ohci_dumpregs(sc); | | 1027 | ohci_dumpregs(sc); |
1028 | #endif | | 1028 | #endif |
1029 | | | 1029 | |
1030 | /* The controller is now in SUSPEND state, we have 2ms to finish. */ | | 1030 | /* The controller is now in SUSPEND state, we have 2ms to finish. */ |
1031 | | | 1031 | |
1032 | /* Set up HC registers. */ | | 1032 | /* Set up HC registers. */ |
1033 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); | | 1033 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); |
1034 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); | | 1034 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); |
1035 | OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); | | 1035 | OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); |
1036 | /* disable all interrupts and then switch on all desired interrupts */ | | 1036 | /* disable all interrupts and then switch on all desired interrupts */ |
1037 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); | | 1037 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); |
1038 | /* switch on desired functional features */ | | 1038 | /* switch on desired functional features */ |
1039 | ctl = OREAD4(sc, OHCI_CONTROL); | | 1039 | ctl = OREAD4(sc, OHCI_CONTROL); |
1040 | ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); | | 1040 | ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); |
1041 | ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | | | 1041 | ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | |
1042 | OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL | rwc; | | 1042 | OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL | rwc; |
1043 | /* And finally start it! */ | | 1043 | /* And finally start it! */ |
1044 | OWRITE4(sc, OHCI_CONTROL, ctl); | | 1044 | OWRITE4(sc, OHCI_CONTROL, ctl); |
1045 | | | 1045 | |
1046 | /* | | 1046 | /* |
1047 | * The controller is now OPERATIONAL. Set a some final | | 1047 | * The controller is now OPERATIONAL. Set a some final |
1048 | * registers that should be set earlier, but that the | | 1048 | * registers that should be set earlier, but that the |
1049 | * controller ignores when in the SUSPEND state. | | 1049 | * controller ignores when in the SUSPEND state. |
1050 | */ | | 1050 | */ |
1051 | ival = OHCI_GET_IVAL(fm); | | 1051 | ival = OHCI_GET_IVAL(fm); |
1052 | fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; | | 1052 | fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; |
1053 | fm |= OHCI_FSMPS(ival) | ival; | | 1053 | fm |= OHCI_FSMPS(ival) | ival; |
1054 | OWRITE4(sc, OHCI_FM_INTERVAL, fm); | | 1054 | OWRITE4(sc, OHCI_FM_INTERVAL, fm); |
1055 | per = OHCI_PERIODIC(ival); /* 90% periodic */ | | 1055 | per = OHCI_PERIODIC(ival); /* 90% periodic */ |
1056 | OWRITE4(sc, OHCI_PERIODIC_START, per); | | 1056 | OWRITE4(sc, OHCI_PERIODIC_START, per); |
1057 | | | 1057 | |
1058 | if (sc->sc_flags & OHCIF_SUPERIO) { | | 1058 | if (sc->sc_flags & OHCIF_SUPERIO) { |
1059 | /* no overcurrent protection */ | | 1059 | /* no overcurrent protection */ |
1060 | desca |= OHCI_NOCP; | | 1060 | desca |= OHCI_NOCP; |
1061 | /* | | 1061 | /* |
1062 | * Clear NoPowerSwitching and PowerOnToPowerGoodTime meaning | | 1062 | * Clear NoPowerSwitching and PowerOnToPowerGoodTime meaning |
1063 | * that | | 1063 | * that |
1064 | * - ports are always power switched | | 1064 | * - ports are always power switched |
1065 | * - don't wait for powered root hub port | | 1065 | * - don't wait for powered root hub port |
1066 | */ | | 1066 | */ |
1067 | desca &= ~(__SHIFTIN(0xff, OHCI_POTPGT_MASK) | OHCI_NPS); | | 1067 | desca &= ~(__SHIFTIN(0xff, OHCI_POTPGT_MASK) | OHCI_NPS); |
1068 | } | | 1068 | } |
1069 | | | 1069 | |
1070 | /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ | | 1070 | /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ |
1071 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); | | 1071 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); |
1072 | OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ | | 1072 | OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ |
1073 | usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY); | | 1073 | usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY); |
1074 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); | | 1074 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); |
1075 | | | 1075 | |
1076 | /* | | 1076 | /* |
1077 | * The AMD756 requires a delay before re-reading the register, | | 1077 | * The AMD756 requires a delay before re-reading the register, |
1078 | * otherwise it will occasionally report 0 ports. | | 1078 | * otherwise it will occasionally report 0 ports. |
1079 | */ | | 1079 | */ |
1080 | sc->sc_noport = 0; | | 1080 | sc->sc_noport = 0; |
1081 | for (i = 0; i < 10 && sc->sc_noport == 0; i++) { | | 1081 | for (i = 0; i < 10 && sc->sc_noport == 0; i++) { |
1082 | usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY); | | 1082 | usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY); |
1083 | sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); | | 1083 | sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); |
1084 | } | | 1084 | } |
1085 | | | 1085 | |
1086 | #ifdef OHCI_DEBUG | | 1086 | #ifdef OHCI_DEBUG |
1087 | if (ohcidebug >= 5) | | 1087 | if (ohcidebug >= 5) |
1088 | ohci_dumpregs(sc); | | 1088 | ohci_dumpregs(sc); |
1089 | #endif | | 1089 | #endif |
1090 | | | 1090 | |
1091 | /* Set up the bus struct. */ | | 1091 | /* Set up the bus struct. */ |
1092 | sc->sc_bus.ub_methods = &ohci_bus_methods; | | 1092 | sc->sc_bus.ub_methods = &ohci_bus_methods; |
1093 | sc->sc_bus.ub_pipesize = sizeof(struct ohci_pipe); | | 1093 | sc->sc_bus.ub_pipesize = sizeof(struct ohci_pipe); |
1094 | | | 1094 | |
1095 | sc->sc_control = sc->sc_intre = 0; | | 1095 | sc->sc_control = sc->sc_intre = 0; |
1096 | | | 1096 | |
1097 | /* Finally, turn on interrupts. */ | | 1097 | /* Finally, turn on interrupts. */ |
1098 | DPRINTF("enabling %#x", sc->sc_eintrs | OHCI_MIE, 0, 0, 0); | | 1098 | DPRINTF("enabling %#x", sc->sc_eintrs | OHCI_MIE, 0, 0, 0); |
1099 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); | | 1099 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); |
1100 | | | 1100 | |
1101 | return 0; | | 1101 | return 0; |
1102 | | | 1102 | |
1103 | bad5: | | 1103 | bad5: |
1104 | for (i = 0; i < OHCI_NO_EDS; i++) | | 1104 | for (i = 0; i < OHCI_NO_EDS; i++) |
1105 | ohci_free_sed(sc, sc->sc_eds[i]); | | 1105 | ohci_free_sed(sc, sc->sc_eds[i]); |
1106 | bad4: | | 1106 | bad4: |
1107 | ohci_free_sed(sc, sc->sc_isoc_head); | | 1107 | ohci_free_sed(sc, sc->sc_isoc_head); |
1108 | bad3: | | 1108 | bad3: |
1109 | ohci_free_sed(sc, sc->sc_bulk_head); | | 1109 | ohci_free_sed(sc, sc->sc_bulk_head); |
1110 | bad2: | | 1110 | bad2: |
1111 | ohci_free_sed(sc, sc->sc_ctrl_head); | | 1111 | ohci_free_sed(sc, sc->sc_ctrl_head); |
1112 | bad1: | | 1112 | bad1: |
1113 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | | 1113 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); |
1114 | sc->sc_hcca = NULL; | | 1114 | sc->sc_hcca = NULL; |
1115 | return err; | | 1115 | return err; |
1116 | } | | 1116 | } |
1117 | | | 1117 | |
1118 | struct usbd_xfer * | | 1118 | struct usbd_xfer * |
1119 | ohci_allocx(struct usbd_bus *bus, unsigned int nframes) | | 1119 | ohci_allocx(struct usbd_bus *bus, unsigned int nframes) |
1120 | { | | 1120 | { |
1121 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | | 1121 | ohci_softc_t *sc = OHCI_BUS2SC(bus); |
1122 | struct usbd_xfer *xfer; | | 1122 | struct usbd_xfer *xfer; |
1123 | | | 1123 | |
1124 | xfer = pool_cache_get(sc->sc_xferpool, PR_NOWAIT); | | 1124 | xfer = pool_cache_get(sc->sc_xferpool, PR_NOWAIT); |
1125 | if (xfer != NULL) { | | 1125 | if (xfer != NULL) { |
1126 | memset(xfer, 0, sizeof(struct ohci_xfer)); | | 1126 | memset(xfer, 0, sizeof(struct ohci_xfer)); |
1127 | #ifdef DIAGNOSTIC | | 1127 | #ifdef DIAGNOSTIC |
1128 | xfer->ux_state = XFER_BUSY; | | 1128 | xfer->ux_state = XFER_BUSY; |
1129 | #endif | | 1129 | #endif |
1130 | } | | 1130 | } |
1131 | return xfer; | | 1131 | return xfer; |
1132 | } | | 1132 | } |
1133 | | | 1133 | |
1134 | void | | 1134 | void |
1135 | ohci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | | 1135 | ohci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) |
1136 | { | | 1136 | { |
1137 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | | 1137 | ohci_softc_t *sc = OHCI_BUS2SC(bus); |
1138 | | | 1138 | |
1139 | KASSERTMSG(xfer->ux_state == XFER_BUSY, | | 1139 | KASSERTMSG(xfer->ux_state == XFER_BUSY, |
1140 | "xfer=%p not busy, 0x%08x\n", xfer, xfer->ux_state); | | 1140 | "xfer=%p not busy, 0x%08x\n", xfer, xfer->ux_state); |
1141 | #ifdef DIAGNOSTIC | | 1141 | #ifdef DIAGNOSTIC |
1142 | xfer->ux_state = XFER_FREE; | | 1142 | xfer->ux_state = XFER_FREE; |
1143 | #endif | | 1143 | #endif |
1144 | pool_cache_put(sc->sc_xferpool, xfer); | | 1144 | pool_cache_put(sc->sc_xferpool, xfer); |
1145 | } | | 1145 | } |
1146 | | | 1146 | |
1147 | Static void | | 1147 | Static void |
1148 | ohci_get_lock(struct usbd_bus *bus, kmutex_t **lock) | | 1148 | ohci_get_lock(struct usbd_bus *bus, kmutex_t **lock) |
1149 | { | | 1149 | { |
1150 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | | 1150 | ohci_softc_t *sc = OHCI_BUS2SC(bus); |
1151 | | | 1151 | |
1152 | *lock = &sc->sc_lock; | | 1152 | *lock = &sc->sc_lock; |
1153 | } | | 1153 | } |
1154 | | | 1154 | |
1155 | /* | | 1155 | /* |
1156 | * Shut down the controller when the system is going down. | | 1156 | * Shut down the controller when the system is going down. |
1157 | */ | | 1157 | */ |
1158 | bool | | 1158 | bool |
1159 | ohci_shutdown(device_t self, int flags) | | 1159 | ohci_shutdown(device_t self, int flags) |
1160 | { | | 1160 | { |
1161 | ohci_softc_t *sc = device_private(self); | | 1161 | ohci_softc_t *sc = device_private(self); |
1162 | | | 1162 | |
1163 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1163 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1164 | | | 1164 | |
1165 | DPRINTF("stopping the HC", 0, 0, 0, 0); | | 1165 | DPRINTF("stopping the HC", 0, 0, 0, 0); |
1166 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); | | 1166 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); |
1167 | return true; | | 1167 | return true; |
1168 | } | | 1168 | } |
1169 | | | 1169 | |
1170 | bool | | 1170 | bool |
1171 | ohci_resume(device_t dv, const pmf_qual_t *qual) | | 1171 | ohci_resume(device_t dv, const pmf_qual_t *qual) |
1172 | { | | 1172 | { |
1173 | ohci_softc_t *sc = device_private(dv); | | 1173 | ohci_softc_t *sc = device_private(dv); |
1174 | uint32_t ctl; | | 1174 | uint32_t ctl; |
1175 | | | 1175 | |
1176 | mutex_spin_enter(&sc->sc_intr_lock); | | 1176 | mutex_spin_enter(&sc->sc_intr_lock); |
1177 | sc->sc_bus.ub_usepolling++; | | 1177 | sc->sc_bus.ub_usepolling++; |
1178 | mutex_spin_exit(&sc->sc_intr_lock); | | 1178 | mutex_spin_exit(&sc->sc_intr_lock); |
1179 | | | 1179 | |
1180 | /* Some broken BIOSes do not recover these values */ | | 1180 | /* Some broken BIOSes do not recover these values */ |
1181 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); | | 1181 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); |
1182 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, | | 1182 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, |
1183 | sc->sc_ctrl_head->physaddr); | | 1183 | sc->sc_ctrl_head->physaddr); |
1184 | OWRITE4(sc, OHCI_BULK_HEAD_ED, | | 1184 | OWRITE4(sc, OHCI_BULK_HEAD_ED, |
1185 | sc->sc_bulk_head->physaddr); | | 1185 | sc->sc_bulk_head->physaddr); |
1186 | if (sc->sc_intre) | | 1186 | if (sc->sc_intre) |
1187 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_intre & | | 1187 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_intre & |
1188 | (OHCI_ALL_INTRS | OHCI_MIE)); | | 1188 | (OHCI_ALL_INTRS | OHCI_MIE)); |
1189 | if (sc->sc_control) | | 1189 | if (sc->sc_control) |
1190 | ctl = sc->sc_control; | | 1190 | ctl = sc->sc_control; |
1191 | else | | 1191 | else |
1192 | ctl = OREAD4(sc, OHCI_CONTROL); | | 1192 | ctl = OREAD4(sc, OHCI_CONTROL); |
1193 | ctl |= OHCI_HCFS_RESUME; | | 1193 | ctl |= OHCI_HCFS_RESUME; |
1194 | OWRITE4(sc, OHCI_CONTROL, ctl); | | 1194 | OWRITE4(sc, OHCI_CONTROL, ctl); |
1195 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | | 1195 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); |
1196 | ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL; | | 1196 | ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL; |
1197 | OWRITE4(sc, OHCI_CONTROL, ctl); | | 1197 | OWRITE4(sc, OHCI_CONTROL, ctl); |
1198 | usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); | | 1198 | usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY); |
1199 | sc->sc_control = sc->sc_intre = 0; | | 1199 | sc->sc_control = sc->sc_intre = 0; |
1200 | | | 1200 | |
1201 | mutex_spin_enter(&sc->sc_intr_lock); | | 1201 | mutex_spin_enter(&sc->sc_intr_lock); |
1202 | sc->sc_bus.ub_usepolling--; | | 1202 | sc->sc_bus.ub_usepolling--; |
1203 | mutex_spin_exit(&sc->sc_intr_lock); | | 1203 | mutex_spin_exit(&sc->sc_intr_lock); |
1204 | | | 1204 | |
1205 | return true; | | 1205 | return true; |
1206 | } | | 1206 | } |
1207 | | | 1207 | |
1208 | bool | | 1208 | bool |
1209 | ohci_suspend(device_t dv, const pmf_qual_t *qual) | | 1209 | ohci_suspend(device_t dv, const pmf_qual_t *qual) |
1210 | { | | 1210 | { |
1211 | ohci_softc_t *sc = device_private(dv); | | 1211 | ohci_softc_t *sc = device_private(dv); |
1212 | uint32_t ctl; | | 1212 | uint32_t ctl; |
1213 | | | 1213 | |
1214 | mutex_spin_enter(&sc->sc_intr_lock); | | 1214 | mutex_spin_enter(&sc->sc_intr_lock); |
1215 | sc->sc_bus.ub_usepolling++; | | 1215 | sc->sc_bus.ub_usepolling++; |
1216 | mutex_spin_exit(&sc->sc_intr_lock); | | 1216 | mutex_spin_exit(&sc->sc_intr_lock); |
1217 | | | 1217 | |
1218 | ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK; | | 1218 | ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK; |
1219 | if (sc->sc_control == 0) { | | 1219 | if (sc->sc_control == 0) { |
1220 | /* | | 1220 | /* |
1221 | * Preserve register values, in case that BIOS | | 1221 | * Preserve register values, in case that BIOS |
1222 | * does not recover them. | | 1222 | * does not recover them. |
1223 | */ | | 1223 | */ |
1224 | sc->sc_control = ctl; | | 1224 | sc->sc_control = ctl; |
1225 | sc->sc_intre = OREAD4(sc, | | 1225 | sc->sc_intre = OREAD4(sc, |
1226 | OHCI_INTERRUPT_ENABLE); | | 1226 | OHCI_INTERRUPT_ENABLE); |
1227 | } | | 1227 | } |
1228 | ctl |= OHCI_HCFS_SUSPEND; | | 1228 | ctl |= OHCI_HCFS_SUSPEND; |
1229 | OWRITE4(sc, OHCI_CONTROL, ctl); | | 1229 | OWRITE4(sc, OHCI_CONTROL, ctl); |
1230 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); | | 1230 | usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT); |
1231 | | | 1231 | |
1232 | mutex_spin_enter(&sc->sc_intr_lock); | | 1232 | mutex_spin_enter(&sc->sc_intr_lock); |
1233 | sc->sc_bus.ub_usepolling--; | | 1233 | sc->sc_bus.ub_usepolling--; |
1234 | mutex_spin_exit(&sc->sc_intr_lock); | | 1234 | mutex_spin_exit(&sc->sc_intr_lock); |
1235 | | | 1235 | |
1236 | return true; | | 1236 | return true; |
1237 | } | | 1237 | } |
1238 | | | 1238 | |
1239 | #ifdef OHCI_DEBUG | | 1239 | #ifdef OHCI_DEBUG |
1240 | void | | 1240 | void |
1241 | ohci_dumpregs(ohci_softc_t *sc) | | 1241 | ohci_dumpregs(ohci_softc_t *sc) |
1242 | { | | 1242 | { |
1243 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1243 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1244 | | | 1244 | |
1245 | DPRINTF("rev=0x%08x control=0x%08x command=0x%08x", | | 1245 | DPRINTF("rev=0x%08x control=0x%08x command=0x%08x", |
1246 | OREAD4(sc, OHCI_REVISION), | | 1246 | OREAD4(sc, OHCI_REVISION), |
1247 | OREAD4(sc, OHCI_CONTROL), | | 1247 | OREAD4(sc, OHCI_CONTROL), |
1248 | OREAD4(sc, OHCI_COMMAND_STATUS), 0); | | 1248 | OREAD4(sc, OHCI_COMMAND_STATUS), 0); |
1249 | DPRINTF(" intrstat=0x%08x intre=0x%08x intrd=0x%08x", | | 1249 | DPRINTF(" intrstat=0x%08x intre=0x%08x intrd=0x%08x", |
1250 | OREAD4(sc, OHCI_INTERRUPT_STATUS), | | 1250 | OREAD4(sc, OHCI_INTERRUPT_STATUS), |
1251 | OREAD4(sc, OHCI_INTERRUPT_ENABLE), | | 1251 | OREAD4(sc, OHCI_INTERRUPT_ENABLE), |
1252 | OREAD4(sc, OHCI_INTERRUPT_DISABLE), 0); | | 1252 | OREAD4(sc, OHCI_INTERRUPT_DISABLE), 0); |
1253 | DPRINTF(" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x", | | 1253 | DPRINTF(" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x", |
1254 | OREAD4(sc, OHCI_HCCA), | | 1254 | OREAD4(sc, OHCI_HCCA), |
1255 | OREAD4(sc, OHCI_PERIOD_CURRENT_ED), | | 1255 | OREAD4(sc, OHCI_PERIOD_CURRENT_ED), |
1256 | OREAD4(sc, OHCI_CONTROL_HEAD_ED), 0); | | 1256 | OREAD4(sc, OHCI_CONTROL_HEAD_ED), 0); |
1257 | DPRINTF(" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x", | | 1257 | DPRINTF(" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x", |
1258 | OREAD4(sc, OHCI_CONTROL_CURRENT_ED), | | 1258 | OREAD4(sc, OHCI_CONTROL_CURRENT_ED), |
1259 | OREAD4(sc, OHCI_BULK_HEAD_ED), | | 1259 | OREAD4(sc, OHCI_BULK_HEAD_ED), |
1260 | OREAD4(sc, OHCI_BULK_CURRENT_ED) ,0); | | 1260 | OREAD4(sc, OHCI_BULK_CURRENT_ED) ,0); |
1261 | DPRINTF(" done=0x%08x fmival=0x%08x fmrem=0x%08x", | | 1261 | DPRINTF(" done=0x%08x fmival=0x%08x fmrem=0x%08x", |
1262 | OREAD4(sc, OHCI_DONE_HEAD), | | 1262 | OREAD4(sc, OHCI_DONE_HEAD), |
1263 | OREAD4(sc, OHCI_FM_INTERVAL), | | 1263 | OREAD4(sc, OHCI_FM_INTERVAL), |
1264 | OREAD4(sc, OHCI_FM_REMAINING), 0); | | 1264 | OREAD4(sc, OHCI_FM_REMAINING), 0); |
1265 | DPRINTF(" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x", | | 1265 | DPRINTF(" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x", |
1266 | OREAD4(sc, OHCI_FM_NUMBER), | | 1266 | OREAD4(sc, OHCI_FM_NUMBER), |
1267 | OREAD4(sc, OHCI_PERIODIC_START), | | 1267 | OREAD4(sc, OHCI_PERIODIC_START), |
1268 | OREAD4(sc, OHCI_LS_THRESHOLD), 0); | | 1268 | OREAD4(sc, OHCI_LS_THRESHOLD), 0); |
1269 | DPRINTF(" desca=0x%08x descb=0x%08x stat=0x%08x", | | 1269 | DPRINTF(" desca=0x%08x descb=0x%08x stat=0x%08x", |
1270 | OREAD4(sc, OHCI_RH_DESCRIPTOR_A), | | 1270 | OREAD4(sc, OHCI_RH_DESCRIPTOR_A), |
1271 | OREAD4(sc, OHCI_RH_DESCRIPTOR_B), | | 1271 | OREAD4(sc, OHCI_RH_DESCRIPTOR_B), |
1272 | OREAD4(sc, OHCI_RH_STATUS), 0); | | 1272 | OREAD4(sc, OHCI_RH_STATUS), 0); |
1273 | DPRINTF(" port1=0x%08x port2=0x%08x", | | 1273 | DPRINTF(" port1=0x%08x port2=0x%08x", |
1274 | OREAD4(sc, OHCI_RH_PORT_STATUS(1)), | | 1274 | OREAD4(sc, OHCI_RH_PORT_STATUS(1)), |
1275 | OREAD4(sc, OHCI_RH_PORT_STATUS(2)), 0, 0); | | 1275 | OREAD4(sc, OHCI_RH_PORT_STATUS(2)), 0, 0); |
1276 | DPRINTF(" HCCA: frame_number=0x%04x done_head=0x%08x", | | 1276 | DPRINTF(" HCCA: frame_number=0x%04x done_head=0x%08x", |
1277 | O32TOH(sc->sc_hcca->hcca_frame_number), | | 1277 | O32TOH(sc->sc_hcca->hcca_frame_number), |
1278 | O32TOH(sc->sc_hcca->hcca_done_head), 0, 0); | | 1278 | O32TOH(sc->sc_hcca->hcca_done_head), 0, 0); |
1279 | } | | 1279 | } |
1280 | #endif | | 1280 | #endif |
1281 | | | 1281 | |
1282 | Static int ohci_intr1(ohci_softc_t *); | | 1282 | Static int ohci_intr1(ohci_softc_t *); |
1283 | | | 1283 | |
1284 | int | | 1284 | int |
1285 | ohci_intr(void *p) | | 1285 | ohci_intr(void *p) |
1286 | { | | 1286 | { |
1287 | ohci_softc_t *sc = p; | | 1287 | ohci_softc_t *sc = p; |
1288 | int ret = 0; | | 1288 | int ret = 0; |
1289 | | | 1289 | |
1290 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1290 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1291 | | | 1291 | |
1292 | if (sc == NULL) | | 1292 | if (sc == NULL) |
1293 | return 0; | | 1293 | return 0; |
1294 | | | 1294 | |
1295 | mutex_spin_enter(&sc->sc_intr_lock); | | 1295 | mutex_spin_enter(&sc->sc_intr_lock); |
1296 | | | 1296 | |
1297 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) | | 1297 | if (sc->sc_dying || !device_has_power(sc->sc_dev)) |
1298 | goto done; | | 1298 | goto done; |
1299 | | | 1299 | |
1300 | /* If we get an interrupt while polling, then just ignore it. */ | | 1300 | /* If we get an interrupt while polling, then just ignore it. */ |
1301 | if (sc->sc_bus.ub_usepolling) { | | 1301 | if (sc->sc_bus.ub_usepolling) { |
1302 | DPRINTFN(16, "ignored interrupt while polling", 0, 0, 0, 0); | | 1302 | DPRINTFN(16, "ignored interrupt while polling", 0, 0, 0, 0); |
1303 | /* for level triggered intrs, should do something to ack */ | | 1303 | /* for level triggered intrs, should do something to ack */ |
1304 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, | | 1304 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, |
1305 | OREAD4(sc, OHCI_INTERRUPT_STATUS)); | | 1305 | OREAD4(sc, OHCI_INTERRUPT_STATUS)); |
1306 | | | 1306 | |
1307 | goto done; | | 1307 | goto done; |
1308 | } | | 1308 | } |
1309 | | | 1309 | |
1310 | ret = ohci_intr1(sc); | | 1310 | ret = ohci_intr1(sc); |
1311 | | | 1311 | |
1312 | done: | | 1312 | done: |
1313 | mutex_spin_exit(&sc->sc_intr_lock); | | 1313 | mutex_spin_exit(&sc->sc_intr_lock); |
1314 | return ret; | | 1314 | return ret; |
1315 | } | | 1315 | } |
1316 | | | 1316 | |
1317 | Static int | | 1317 | Static int |
1318 | ohci_intr1(ohci_softc_t *sc) | | 1318 | ohci_intr1(ohci_softc_t *sc) |
1319 | { | | 1319 | { |
1320 | uint32_t intrs, eintrs; | | 1320 | uint32_t intrs, eintrs; |
1321 | | | 1321 | |
1322 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1322 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1323 | | | 1323 | |
1324 | /* In case the interrupt occurs before initialization has completed. */ | | 1324 | /* In case the interrupt occurs before initialization has completed. */ |
1325 | if (sc == NULL || sc->sc_hcca == NULL) { | | 1325 | if (sc == NULL || sc->sc_hcca == NULL) { |
1326 | #ifdef DIAGNOSTIC | | 1326 | #ifdef DIAGNOSTIC |
1327 | printf("ohci_intr: sc->sc_hcca == NULL\n"); | | 1327 | printf("ohci_intr: sc->sc_hcca == NULL\n"); |
1328 | #endif | | 1328 | #endif |
1329 | return 0; | | 1329 | return 0; |
1330 | } | | 1330 | } |
1331 | | | 1331 | |
1332 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | | 1332 | KASSERT(mutex_owned(&sc->sc_intr_lock)); |
1333 | | | 1333 | |
1334 | intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS); | | 1334 | intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS); |
1335 | if (!intrs) | | 1335 | if (!intrs) |
1336 | return 0; | | 1336 | return 0; |
1337 | | | 1337 | |
1338 | /* Acknowledge */ | | 1338 | /* Acknowledge */ |
1339 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs & ~(OHCI_MIE|OHCI_WDH)); | | 1339 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs & ~(OHCI_MIE|OHCI_WDH)); |
1340 | eintrs = intrs & sc->sc_eintrs; | | 1340 | eintrs = intrs & sc->sc_eintrs; |
1341 | DPRINTFN(7, "sc=%p", sc, 0, 0, 0); | | 1341 | DPRINTFN(7, "sc=%p", sc, 0, 0, 0); |
1342 | DPRINTFN(7, "intrs=%#x(%#x) eintrs=%#x(%#x)", | | 1342 | DPRINTFN(7, "intrs=%#x(%#x) eintrs=%#x(%#x)", |
1343 | intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS), eintrs, | | 1343 | intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS), eintrs, |
1344 | sc->sc_eintrs); | | 1344 | sc->sc_eintrs); |
1345 | | | 1345 | |
1346 | if (!eintrs) { | | 1346 | if (!eintrs) { |
1347 | return 0; | | 1347 | return 0; |
1348 | } | | 1348 | } |
1349 | | | 1349 | |
1350 | if (eintrs & OHCI_SO) { | | 1350 | if (eintrs & OHCI_SO) { |
1351 | sc->sc_overrun_cnt++; | | 1351 | sc->sc_overrun_cnt++; |
1352 | if (usbd_ratecheck(&sc->sc_overrun_ntc)) { | | 1352 | if (usbd_ratecheck(&sc->sc_overrun_ntc)) { |
1353 | printf("%s: %u scheduling overruns\n", | | 1353 | printf("%s: %u scheduling overruns\n", |
1354 | device_xname(sc->sc_dev), sc->sc_overrun_cnt); | | 1354 | device_xname(sc->sc_dev), sc->sc_overrun_cnt); |
1355 | sc->sc_overrun_cnt = 0; | | 1355 | sc->sc_overrun_cnt = 0; |
1356 | } | | 1356 | } |
1357 | /* XXX do what */ | | 1357 | /* XXX do what */ |
1358 | eintrs &= ~OHCI_SO; | | 1358 | eintrs &= ~OHCI_SO; |
1359 | } | | 1359 | } |
1360 | if (eintrs & OHCI_WDH) { | | 1360 | if (eintrs & OHCI_WDH) { |
1361 | /* | | 1361 | /* |
1362 | * We block the interrupt below, and reenable it later from | | 1362 | * We block the interrupt below, and reenable it later from |
1363 | * ohci_softintr(). | | 1363 | * ohci_softintr(). |
1364 | */ | | 1364 | */ |
1365 | usb_schedsoftintr(&sc->sc_bus); | | 1365 | usb_schedsoftintr(&sc->sc_bus); |
1366 | } | | 1366 | } |
1367 | if (eintrs & OHCI_RD) { | | 1367 | if (eintrs & OHCI_RD) { |
1368 | DPRINTFN(5, "resume detect", sc, 0, 0, 0); | | 1368 | DPRINTFN(5, "resume detect", sc, 0, 0, 0); |
1369 | printf("%s: resume detect\n", device_xname(sc->sc_dev)); | | 1369 | printf("%s: resume detect\n", device_xname(sc->sc_dev)); |
1370 | /* XXX process resume detect */ | | 1370 | /* XXX process resume detect */ |
1371 | } | | 1371 | } |
1372 | if (eintrs & OHCI_UE) { | | 1372 | if (eintrs & OHCI_UE) { |
1373 | DPRINTFN(5, "unrecoverable error", sc, 0, 0, 0); | | 1373 | DPRINTFN(5, "unrecoverable error", sc, 0, 0, 0); |
1374 | printf("%s: unrecoverable error, controller halted\n", | | 1374 | printf("%s: unrecoverable error, controller halted\n", |
1375 | device_xname(sc->sc_dev)); | | 1375 | device_xname(sc->sc_dev)); |
1376 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); | | 1376 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); |
1377 | /* XXX what else */ | | 1377 | /* XXX what else */ |
1378 | } | | 1378 | } |
1379 | if (eintrs & OHCI_RHSC) { | | 1379 | if (eintrs & OHCI_RHSC) { |
1380 | /* | | 1380 | /* |
1381 | * We block the interrupt below, and reenable it later from | | 1381 | * We block the interrupt below, and reenable it later from |
1382 | * a timeout. | | 1382 | * a timeout. |
1383 | */ | | 1383 | */ |
1384 | softint_schedule(sc->sc_rhsc_si); | | 1384 | softint_schedule(sc->sc_rhsc_si); |
1385 | } | | 1385 | } |
1386 | | | 1386 | |
1387 | if (eintrs != 0) { | | 1387 | if (eintrs != 0) { |
1388 | /* Block unprocessed interrupts. */ | | 1388 | /* Block unprocessed interrupts. */ |
1389 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs); | | 1389 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs); |
1390 | sc->sc_eintrs &= ~eintrs; | | 1390 | sc->sc_eintrs &= ~eintrs; |
1391 | DPRINTF("sc %p blocking intrs 0x%x", sc, eintrs, 0, 0); | | 1391 | DPRINTF("sc %p blocking intrs 0x%x", sc, eintrs, 0, 0); |
1392 | } | | 1392 | } |
1393 | | | 1393 | |
1394 | return 1; | | 1394 | return 1; |
1395 | } | | 1395 | } |
1396 | | | 1396 | |
1397 | void | | 1397 | void |
1398 | ohci_rhsc_enable(void *v_sc) | | 1398 | ohci_rhsc_enable(void *v_sc) |
1399 | { | | 1399 | { |
1400 | ohci_softc_t *sc = v_sc; | | 1400 | ohci_softc_t *sc = v_sc; |
1401 | | | 1401 | |
1402 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1402 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1403 | DPRINTF("sc %p", sc, 0, 0, 0); | | 1403 | DPRINTF("sc %p", sc, 0, 0, 0); |
1404 | mutex_spin_enter(&sc->sc_intr_lock); | | 1404 | mutex_spin_enter(&sc->sc_intr_lock); |
1405 | sc->sc_eintrs |= OHCI_RHSC; | | 1405 | sc->sc_eintrs |= OHCI_RHSC; |
1406 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); | | 1406 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); |
1407 | mutex_spin_exit(&sc->sc_intr_lock); | | 1407 | mutex_spin_exit(&sc->sc_intr_lock); |
1408 | } | | 1408 | } |
1409 | | | 1409 | |
1410 | #ifdef OHCI_DEBUG | | 1410 | #ifdef OHCI_DEBUG |
1411 | const char *ohci_cc_strs[] = { | | 1411 | const char *ohci_cc_strs[] = { |
1412 | "NO_ERROR", | | 1412 | "NO_ERROR", |
1413 | "CRC", | | 1413 | "CRC", |
1414 | "BIT_STUFFING", | | 1414 | "BIT_STUFFING", |
1415 | "DATA_TOGGLE_MISMATCH", | | 1415 | "DATA_TOGGLE_MISMATCH", |
1416 | "STALL", | | 1416 | "STALL", |
1417 | "DEVICE_NOT_RESPONDING", | | 1417 | "DEVICE_NOT_RESPONDING", |
1418 | "PID_CHECK_FAILURE", | | 1418 | "PID_CHECK_FAILURE", |
1419 | "UNEXPECTED_PID", | | 1419 | "UNEXPECTED_PID", |
1420 | "DATA_OVERRUN", | | 1420 | "DATA_OVERRUN", |
1421 | "DATA_UNDERRUN", | | 1421 | "DATA_UNDERRUN", |
1422 | "BUFFER_OVERRUN", | | 1422 | "BUFFER_OVERRUN", |
1423 | "BUFFER_UNDERRUN", | | 1423 | "BUFFER_UNDERRUN", |
1424 | "reserved", | | 1424 | "reserved", |
1425 | "reserved", | | 1425 | "reserved", |
1426 | "NOT_ACCESSED", | | 1426 | "NOT_ACCESSED", |
1427 | "NOT_ACCESSED", | | 1427 | "NOT_ACCESSED", |
1428 | }; | | 1428 | }; |
1429 | #endif | | 1429 | #endif |
1430 | | | 1430 | |
1431 | void | | 1431 | void |
1432 | ohci_softintr(void *v) | | 1432 | ohci_softintr(void *v) |
1433 | { | | 1433 | { |
1434 | struct usbd_bus *bus = v; | | 1434 | struct usbd_bus *bus = v; |
1435 | ohci_softc_t *sc = OHCI_BUS2SC(bus); | | 1435 | ohci_softc_t *sc = OHCI_BUS2SC(bus); |
1436 | ohci_soft_itd_t *sitd, *sidone, *sitdnext; | | 1436 | ohci_soft_itd_t *sitd, *sidone, *sitdnext; |
1437 | ohci_soft_td_t *std, *sdone, *stdnext; | | 1437 | ohci_soft_td_t *std, *sdone, *stdnext; |
1438 | struct usbd_xfer *xfer; | | 1438 | struct usbd_xfer *xfer; |
1439 | struct ohci_pipe *opipe; | | 1439 | struct ohci_pipe *opipe; |
1440 | int len, cc; | | 1440 | int len, cc; |
1441 | int i, j, actlen, iframes, uedir; | | 1441 | int i, j, actlen, iframes, uedir; |
1442 | ohci_physaddr_t done; | | 1442 | ohci_physaddr_t done; |
1443 | | | 1443 | |
1444 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 1444 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
1445 | | | 1445 | |
1446 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1446 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1447 | | | 1447 | |
1448 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), | | 1448 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), |
1449 | sizeof(sc->sc_hcca->hcca_done_head), | | 1449 | sizeof(sc->sc_hcca->hcca_done_head), |
1450 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1450 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1451 | done = O32TOH(sc->sc_hcca->hcca_done_head) & ~OHCI_DONE_INTRS; | | 1451 | done = O32TOH(sc->sc_hcca->hcca_done_head) & ~OHCI_DONE_INTRS; |
1452 | sc->sc_hcca->hcca_done_head = 0; | | 1452 | sc->sc_hcca->hcca_done_head = 0; |
1453 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), | | 1453 | usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head), |
1454 | sizeof(sc->sc_hcca->hcca_done_head), | | 1454 | sizeof(sc->sc_hcca->hcca_done_head), |
1455 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 1455 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1456 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_WDH); | | 1456 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_WDH); |
1457 | sc->sc_eintrs |= OHCI_WDH; | | 1457 | sc->sc_eintrs |= OHCI_WDH; |
1458 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_WDH); | | 1458 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_WDH); |
1459 | | | 1459 | |
1460 | /* Reverse the done list. */ | | 1460 | /* Reverse the done list. */ |
1461 | for (sdone = NULL, sidone = NULL; done != 0; ) { | | 1461 | for (sdone = NULL, sidone = NULL; done != 0; ) { |
1462 | std = ohci_hash_find_td(sc, done); | | 1462 | std = ohci_hash_find_td(sc, done); |
1463 | if (std != NULL) { | | 1463 | if (std != NULL) { |
1464 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), | | 1464 | usb_syncmem(&std->dma, std->offs, sizeof(std->td), |
1465 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1465 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1466 | std->dnext = sdone; | | 1466 | std->dnext = sdone; |
1467 | done = O32TOH(std->td.td_nexttd); | | 1467 | done = O32TOH(std->td.td_nexttd); |
1468 | sdone = std; | | 1468 | sdone = std; |
1469 | DPRINTFN(10, "add TD %p", std, 0, 0, 0); | | 1469 | DPRINTFN(10, "add TD %p", std, 0, 0, 0); |
1470 | continue; | | 1470 | continue; |
1471 | } | | 1471 | } |
1472 | sitd = ohci_hash_find_itd(sc, done); | | 1472 | sitd = ohci_hash_find_itd(sc, done); |
1473 | if (sitd != NULL) { | | 1473 | if (sitd != NULL) { |
1474 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), | | 1474 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), |
1475 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 1475 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
1476 | sitd->dnext = sidone; | | 1476 | sitd->dnext = sidone; |
1477 | done = O32TOH(sitd->itd.itd_nextitd); | | 1477 | done = O32TOH(sitd->itd.itd_nextitd); |
1478 | sidone = sitd; | | 1478 | sidone = sitd; |
1479 | DPRINTFN(5, "add ITD %p", sitd, 0, 0, 0); | | 1479 | DPRINTFN(5, "add ITD %p", sitd, 0, 0, 0); |
1480 | continue; | | 1480 | continue; |
1481 | } | | 1481 | } |
1482 | DPRINTFN(10, "addr %p not found", done, 0, 0, 0); | | 1482 | DPRINTFN(10, "addr %p not found", done, 0, 0, 0); |
1483 | device_printf(sc->sc_dev, "WARNING: addr 0x%08lx not found\n", | | 1483 | device_printf(sc->sc_dev, "WARNING: addr 0x%08lx not found\n", |
1484 | (u_long)done); | | 1484 | (u_long)done); |
1485 | break; | | 1485 | break; |
1486 | } | | 1486 | } |
1487 | | | 1487 | |
1488 | DPRINTFN(10, "sdone=%p sidone=%p", sdone, sidone, 0, 0); | | 1488 | DPRINTFN(10, "sdone=%p sidone=%p", sdone, sidone, 0, 0); |
1489 | DPRINTFN(10, "--- TD dump start ---", 0, 0, 0, 0); | | 1489 | DPRINTFN(10, "--- TD dump start ---", 0, 0, 0, 0); |
1490 | #ifdef OHCI_DEBUG | | 1490 | #ifdef OHCI_DEBUG |
1491 | if (ohcidebug >= 10) { | | 1491 | if (ohcidebug >= 10) { |
1492 | for (std = sdone; std; std = std->dnext) | | 1492 | for (std = sdone; std; std = std->dnext) |
1493 | ohci_dump_td(sc, std); | | 1493 | ohci_dump_td(sc, std); |
1494 | } | | 1494 | } |
1495 | #endif | | 1495 | #endif |
1496 | DPRINTFN(10, "--- TD dump end ---", 0, 0, 0, 0); | | 1496 | DPRINTFN(10, "--- TD dump end ---", 0, 0, 0, 0); |
1497 | | | 1497 | |
1498 | for (std = sdone; std; std = stdnext) { | | 1498 | for (std = sdone; std; std = stdnext) { |
1499 | xfer = std->xfer; | | 1499 | xfer = std->xfer; |
1500 | stdnext = std->dnext; | | 1500 | stdnext = std->dnext; |
1501 | DPRINTFN(10, "std=%p xfer=%p hcpriv=%p", std, xfer, | | 1501 | DPRINTFN(10, "std=%p xfer=%p hcpriv=%p", std, xfer, |
1502 | xfer ? xfer->ux_hcpriv : 0, 0); | | 1502 | xfer ? xfer->ux_hcpriv : 0, 0); |
1503 | if (xfer == NULL) { | | 1503 | if (xfer == NULL) { |
1504 | /* | | 1504 | /* |
1505 | * xfer == NULL: There seems to be no xfer associated | | 1505 | * xfer == NULL: There seems to be no xfer associated |
1506 | * with this TD. It is tailp that happened to end up on | | 1506 | * with this TD. It is tailp that happened to end up on |
1507 | * the done queue. | | 1507 | * the done queue. |
1508 | * Shouldn't happen, but some chips are broken(?). | | 1508 | * Shouldn't happen, but some chips are broken(?). |
1509 | */ | | 1509 | */ |
1510 | continue; | | 1510 | continue; |
1511 | } | | 1511 | } |
1512 | if (xfer->ux_status == USBD_CANCELLED || | | 1512 | if (xfer->ux_status == USBD_CANCELLED || |
1513 | xfer->ux_status == USBD_TIMEOUT) { | | 1513 | xfer->ux_status == USBD_TIMEOUT) { |
1514 | DPRINTF("cancel/timeout %p", xfer, 0, 0, 0); | | 1514 | DPRINTF("cancel/timeout %p", xfer, 0, 0, 0); |
1515 | /* Handled by abort routine. */ | | 1515 | /* Handled by abort routine. */ |
1516 | continue; | | 1516 | continue; |
1517 | } | | 1517 | } |
1518 | callout_stop(&xfer->ux_callout); | | 1518 | callout_stop(&xfer->ux_callout); |
1519 | | | 1519 | |
1520 | len = std->len; | | 1520 | len = std->len; |
1521 | if (std->td.td_cbp != 0) | | 1521 | if (std->td.td_cbp != 0) |
1522 | len -= O32TOH(std->td.td_be) - | | 1522 | len -= O32TOH(std->td.td_be) - |
1523 | O32TOH(std->td.td_cbp) + 1; | | 1523 | O32TOH(std->td.td_cbp) + 1; |
1524 | DPRINTFN(10, "len=%d, flags=0x%x", len, std->flags, 0, 0); | | 1524 | DPRINTFN(10, "len=%d, flags=0x%x", len, std->flags, 0, 0); |
1525 | if (std->flags & OHCI_ADD_LEN) | | 1525 | if (std->flags & OHCI_ADD_LEN) |
1526 | xfer->ux_actlen += len; | | 1526 | xfer->ux_actlen += len; |
1527 | | | 1527 | |
1528 | cc = OHCI_TD_GET_CC(O32TOH(std->td.td_flags)); | | 1528 | cc = OHCI_TD_GET_CC(O32TOH(std->td.td_flags)); |
1529 | if (cc == OHCI_CC_NO_ERROR) { | | 1529 | if (cc == OHCI_CC_NO_ERROR) { |
1530 | ohci_hash_rem_td(sc, std); | | 1530 | ohci_hash_rem_td(sc, std); |
1531 | if (std->flags & OHCI_CALL_DONE) { | | 1531 | if (std->flags & OHCI_CALL_DONE) { |
1532 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 1532 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
1533 | usb_transfer_complete(xfer); | | 1533 | usb_transfer_complete(xfer); |
1534 | } | | 1534 | } |
1535 | } else { | | 1535 | } else { |
1536 | /* | | 1536 | /* |
1537 | * Endpoint is halted. First unlink all the TDs | | 1537 | * Endpoint is halted. First unlink all the TDs |
1538 | * belonging to the failed transfer, and then restart | | 1538 | * belonging to the failed transfer, and then restart |
1539 | * the endpoint. | | 1539 | * the endpoint. |
1540 | */ | | 1540 | */ |
1541 | ohci_soft_td_t *p, *n; | | 1541 | ohci_soft_td_t *p, *n; |
1542 | opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 1542 | opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
1543 | | | 1543 | |
1544 | DPRINTFN(10, "error cc=%d", cc, 0, 0, 0); | | 1544 | DPRINTFN(10, "error cc=%d", cc, 0, 0, 0); |
1545 | | | 1545 | |
1546 | /* remove xfer's TDs from the hash */ | | 1546 | /* remove xfer's TDs from the hash */ |
1547 | for (p = std; p->xfer == xfer; p = n) { | | 1547 | for (p = std; p->xfer == xfer; p = n) { |
1548 | n = p->nexttd; | | 1548 | n = p->nexttd; |
1549 | ohci_hash_rem_td(sc, p); | | 1549 | ohci_hash_rem_td(sc, p); |
1550 | } | | 1550 | } |
1551 | | | 1551 | |
1552 | ohci_soft_ed_t *sed = opipe->sed; | | 1552 | ohci_soft_ed_t *sed = opipe->sed; |
1553 | | | 1553 | |
1554 | /* clear halt and TD chain */ | | 1554 | /* clear halt and TD chain */ |
1555 | sed->ed.ed_headp = HTOO32(p->physaddr); | | 1555 | sed->ed.ed_headp = HTOO32(p->physaddr); |
1556 | usb_syncmem(&sed->dma, | | 1556 | usb_syncmem(&sed->dma, |
1557 | sed->offs + offsetof(ohci_ed_t, ed_headp), | | 1557 | sed->offs + offsetof(ohci_ed_t, ed_headp), |
1558 | sizeof(sed->ed.ed_headp), | | 1558 | sizeof(sed->ed.ed_headp), |
1559 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 1559 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1560 | | | 1560 | |
1561 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); | | 1561 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); |
1562 | | | 1562 | |
1563 | if (cc == OHCI_CC_DATA_UNDERRUN) | | 1563 | if (cc == OHCI_CC_DATA_UNDERRUN) |
1564 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 1564 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
1565 | else if (cc == OHCI_CC_STALL) | | 1565 | else if (cc == OHCI_CC_STALL) |
1566 | xfer->ux_status = USBD_STALLED; | | 1566 | xfer->ux_status = USBD_STALLED; |
1567 | else | | 1567 | else |
1568 | xfer->ux_status = USBD_IOERROR; | | 1568 | xfer->ux_status = USBD_IOERROR; |
1569 | usb_transfer_complete(xfer); | | 1569 | usb_transfer_complete(xfer); |
1570 | } | | 1570 | } |
1571 | } | | 1571 | } |
1572 | DPRINTFN(10, "--- ITD dump start ---", 0, 0, 0, 0); | | 1572 | DPRINTFN(10, "--- ITD dump start ---", 0, 0, 0, 0); |
1573 | #ifdef OHCI_DEBUG | | 1573 | #ifdef OHCI_DEBUG |
1574 | if (ohcidebug >= 10) { | | 1574 | if (ohcidebug >= 10) { |
1575 | for (sitd = sidone; sitd; sitd = sitd->dnext) | | 1575 | for (sitd = sidone; sitd; sitd = sitd->dnext) |
1576 | ohci_dump_itd(sc, sitd); | | 1576 | ohci_dump_itd(sc, sitd); |
1577 | } | | 1577 | } |
1578 | #endif | | 1578 | #endif |
1579 | DPRINTFN(10, "--- ITD dump end ---", 0, 0, 0, 0); | | 1579 | DPRINTFN(10, "--- ITD dump end ---", 0, 0, 0, 0); |
1580 | | | 1580 | |
1581 | for (sitd = sidone; sitd != NULL; sitd = sitdnext) { | | 1581 | for (sitd = sidone; sitd != NULL; sitd = sitdnext) { |
1582 | xfer = sitd->xfer; | | 1582 | xfer = sitd->xfer; |
1583 | sitdnext = sitd->dnext; | | 1583 | sitdnext = sitd->dnext; |
1584 | DPRINTFN(1, "sitd=%p xfer=%p hcpriv=%p", sitd, xfer, | | 1584 | DPRINTFN(1, "sitd=%p xfer=%p hcpriv=%p", sitd, xfer, |
1585 | xfer ? xfer->ux_hcpriv : 0, 0); | | 1585 | xfer ? xfer->ux_hcpriv : 0, 0); |
1586 | if (xfer == NULL) | | 1586 | if (xfer == NULL) |
1587 | continue; | | 1587 | continue; |
1588 | if (xfer->ux_status == USBD_CANCELLED || | | 1588 | if (xfer->ux_status == USBD_CANCELLED || |
1589 | xfer->ux_status == USBD_TIMEOUT) { | | 1589 | xfer->ux_status == USBD_TIMEOUT) { |
1590 | DPRINTF("cancel/timeout %p", xfer, 0, 0, 0); | | 1590 | DPRINTF("cancel/timeout %p", xfer, 0, 0, 0); |
1591 | /* Handled by abort routine. */ | | 1591 | /* Handled by abort routine. */ |
1592 | continue; | | 1592 | continue; |
1593 | } | | 1593 | } |
1594 | KASSERT(!sitd->isdone); | | 1594 | KASSERT(!sitd->isdone); |
1595 | #ifdef DIAGNOSTIC | | 1595 | #ifdef DIAGNOSTIC |
1596 | sitd->isdone = true; | | 1596 | sitd->isdone = true; |
1597 | #endif | | 1597 | #endif |
1598 | if (sitd->flags & OHCI_CALL_DONE) { | | 1598 | if (sitd->flags & OHCI_CALL_DONE) { |
1599 | ohci_soft_itd_t *next; | | 1599 | ohci_soft_itd_t *next; |
1600 | | | 1600 | |
1601 | opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 1601 | opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
1602 | opipe->isoc.inuse -= xfer->ux_nframes; | | 1602 | opipe->isoc.inuse -= xfer->ux_nframes; |
1603 | uedir = UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc-> | | 1603 | uedir = UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc-> |
1604 | bEndpointAddress); | | 1604 | bEndpointAddress); |
1605 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 1605 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
1606 | actlen = 0; | | 1606 | actlen = 0; |
1607 | for (i = 0, sitd = xfer->ux_hcpriv;; | | 1607 | for (i = 0, sitd = xfer->ux_hcpriv;; |
1608 | sitd = next) { | | 1608 | sitd = next) { |
1609 | next = sitd->nextitd; | | 1609 | next = sitd->nextitd; |
1610 | if (OHCI_ITD_GET_CC(O32TOH(sitd-> | | 1610 | if (OHCI_ITD_GET_CC(O32TOH(sitd-> |
1611 | itd.itd_flags)) != OHCI_CC_NO_ERROR) | | 1611 | itd.itd_flags)) != OHCI_CC_NO_ERROR) |
1612 | xfer->ux_status = USBD_IOERROR; | | 1612 | xfer->ux_status = USBD_IOERROR; |
1613 | /* For input, update frlengths with actual */ | | 1613 | /* For input, update frlengths with actual */ |
1614 | /* XXX anything necessary for output? */ | | 1614 | /* XXX anything necessary for output? */ |
1615 | if (uedir == UE_DIR_IN && | | 1615 | if (uedir == UE_DIR_IN && |
1616 | xfer->ux_status == USBD_NORMAL_COMPLETION) { | | 1616 | xfer->ux_status == USBD_NORMAL_COMPLETION) { |
1617 | iframes = OHCI_ITD_GET_FC(O32TOH( | | 1617 | iframes = OHCI_ITD_GET_FC(O32TOH( |
1618 | sitd->itd.itd_flags)); | | 1618 | sitd->itd.itd_flags)); |
1619 | for (j = 0; j < iframes; i++, j++) { | | 1619 | for (j = 0; j < iframes; i++, j++) { |
1620 | len = O16TOH(sitd-> | | 1620 | len = O16TOH(sitd-> |
1621 | itd.itd_offset[j]); | | 1621 | itd.itd_offset[j]); |
1622 | if ((OHCI_ITD_PSW_GET_CC(len) & | | 1622 | if ((OHCI_ITD_PSW_GET_CC(len) & |
1623 | OHCI_CC_NOT_ACCESSED_MASK) | | 1623 | OHCI_CC_NOT_ACCESSED_MASK) |
1624 | == OHCI_CC_NOT_ACCESSED) | | 1624 | == OHCI_CC_NOT_ACCESSED) |
1625 | len = 0; | | 1625 | len = 0; |
1626 | else | | 1626 | else |
1627 | len = OHCI_ITD_PSW_LENGTH(len); | | 1627 | len = OHCI_ITD_PSW_LENGTH(len); |
1628 | xfer->ux_frlengths[i] = len; | | 1628 | xfer->ux_frlengths[i] = len; |
1629 | actlen += len; | | 1629 | actlen += len; |
1630 | } | | 1630 | } |
1631 | } | | 1631 | } |
1632 | if (sitd->flags & OHCI_CALL_DONE) | | 1632 | if (sitd->flags & OHCI_CALL_DONE) |
1633 | break; | | 1633 | break; |
1634 | ohci_hash_rem_itd(sc, sitd); | | 1634 | ohci_hash_rem_itd(sc, sitd); |
1635 | | | 1635 | |
1636 | } | | 1636 | } |
1637 | ohci_hash_rem_itd(sc, sitd); | | 1637 | ohci_hash_rem_itd(sc, sitd); |
1638 | if (uedir == UE_DIR_IN && | | 1638 | if (uedir == UE_DIR_IN && |
1639 | xfer->ux_status == USBD_NORMAL_COMPLETION) | | 1639 | xfer->ux_status == USBD_NORMAL_COMPLETION) |
1640 | xfer->ux_actlen = actlen; | | 1640 | xfer->ux_actlen = actlen; |
1641 | xfer->ux_hcpriv = NULL; | | 1641 | xfer->ux_hcpriv = NULL; |
1642 | | | 1642 | |
1643 | usb_transfer_complete(xfer); | | 1643 | usb_transfer_complete(xfer); |
1644 | } | | 1644 | } |
1645 | } | | 1645 | } |
1646 | | | 1646 | |
1647 | if (sc->sc_softwake) { | | 1647 | if (sc->sc_softwake) { |
1648 | sc->sc_softwake = 0; | | 1648 | sc->sc_softwake = 0; |
1649 | cv_broadcast(&sc->sc_softwake_cv); | | 1649 | cv_broadcast(&sc->sc_softwake_cv); |
1650 | } | | 1650 | } |
1651 | | | 1651 | |
1652 | DPRINTFN(10, "done", 0, 0, 0, 0); | | 1652 | DPRINTFN(10, "done", 0, 0, 0, 0); |
1653 | } | | 1653 | } |
1654 | | | 1654 | |
1655 | void | | 1655 | void |
1656 | ohci_device_ctrl_done(struct usbd_xfer *xfer) | | 1656 | ohci_device_ctrl_done(struct usbd_xfer *xfer) |
1657 | { | | 1657 | { |
1658 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 1658 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
1659 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | | 1659 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); |
1660 | int len = UGETW(xfer->ux_request.wLength); | | 1660 | int len = UGETW(xfer->ux_request.wLength); |
1661 | int isread = (xfer->ux_request.bmRequestType & UT_READ); | | 1661 | int isread = (xfer->ux_request.bmRequestType & UT_READ); |
1662 | | | 1662 | |
1663 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1663 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1664 | DPRINTFN(10, "xfer=%p", xfer, 0, 0, 0); | | 1664 | DPRINTFN(10, "xfer=%p", xfer, 0, 0, 0); |
1665 | | | 1665 | |
1666 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 1666 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
1667 | KASSERT(xfer->ux_rqflags & URQ_REQUEST); | | 1667 | KASSERT(xfer->ux_rqflags & URQ_REQUEST); |
1668 | | | 1668 | |
1669 | if (len) | | 1669 | if (len) |
1670 | usb_syncmem(&xfer->ux_dmabuf, 0, len, | | 1670 | usb_syncmem(&xfer->ux_dmabuf, 0, len, |
1671 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | | 1671 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
1672 | usb_syncmem(&opipe->ctrl.reqdma, 0, | | 1672 | usb_syncmem(&opipe->ctrl.reqdma, 0, |
1673 | sizeof(usb_device_request_t), BUS_DMASYNC_POSTWRITE); | | 1673 | sizeof(usb_device_request_t), BUS_DMASYNC_POSTWRITE); |
1674 | } | | 1674 | } |
1675 | | | 1675 | |
1676 | void | | 1676 | void |
1677 | ohci_device_intr_done(struct usbd_xfer *xfer) | | 1677 | ohci_device_intr_done(struct usbd_xfer *xfer) |
1678 | { | | 1678 | { |
1679 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | | 1679 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); |
1680 | int isread = | | 1680 | int isread = |
1681 | (UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN); | | 1681 | (UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN); |
1682 | | | 1682 | |
1683 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 1683 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
1684 | DPRINTFN(10, "xfer=%p, actlen=%d", xfer, xfer->ux_actlen, 0, 0); | | 1684 | DPRINTFN(10, "xfer=%p, actlen=%d", xfer, xfer->ux_actlen, 0, 0); |
1685 | | | 1685 | |
1686 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 1686 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
1687 | | | 1687 | |
1688 | usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length, | | 1688 | usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length, |
1689 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | | 1689 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
1690 | } | | 1690 | } |
1691 | | | 1691 | |
1692 | void | | 1692 | void |
1693 | ohci_device_bulk_done(struct usbd_xfer *xfer) | | 1693 | ohci_device_bulk_done(struct usbd_xfer *xfer) |
1694 | { | | 1694 | { |
1695 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | | 1695 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); |
1696 | | | 1696 | |
1697 | int isread = | | 1697 | int isread = |
1698 | (UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN); | | 1698 | (UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN); |
1699 | | | 1699 | |
1700 | KASSERT(mutex_owned(&sc->sc_lock)); | | 1700 | KASSERT(mutex_owned(&sc->sc_lock)); |
1701 | | | 1701 | |