| @@ -1,1043 +1,1043 @@ | | | @@ -1,1043 +1,1043 @@ |
1 | /* $NetBSD: ohci.c,v 1.296 2020/02/21 12:41:29 skrll Exp $ */ | | 1 | /* $NetBSD: ohci.c,v 1.297 2020/03/05 08:12:30 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.296 2020/02/21 12:41:29 skrll Exp $"); | | 44 | __KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.297 2020/03/05 08:12:30 skrll Exp $"); |
45 | | | 45 | |
46 | #ifdef _KERNEL_OPT | | 46 | #ifdef _KERNEL_OPT |
47 | #include "opt_usb.h" | | 47 | #include "opt_usb.h" |
48 | #endif | | 48 | #endif |
49 | | | 49 | |
50 | #include <sys/param.h> | | 50 | #include <sys/param.h> |
51 | | | 51 | |
52 | #include <sys/cpu.h> | | 52 | #include <sys/cpu.h> |
53 | #include <sys/device.h> | | 53 | #include <sys/device.h> |
54 | #include <sys/kernel.h> | | 54 | #include <sys/kernel.h> |
55 | #include <sys/kmem.h> | | 55 | #include <sys/kmem.h> |
56 | #include <sys/proc.h> | | 56 | #include <sys/proc.h> |
57 | #include <sys/queue.h> | | 57 | #include <sys/queue.h> |
58 | #include <sys/select.h> | | 58 | #include <sys/select.h> |
59 | #include <sys/sysctl.h> | | 59 | #include <sys/sysctl.h> |
60 | #include <sys/systm.h> | | 60 | #include <sys/systm.h> |
61 | | | 61 | |
62 | #include <machine/endian.h> | | 62 | #include <machine/endian.h> |
63 | | | 63 | |
64 | #include <dev/usb/usb.h> | | 64 | #include <dev/usb/usb.h> |
65 | #include <dev/usb/usbdi.h> | | 65 | #include <dev/usb/usbdi.h> |
66 | #include <dev/usb/usbdivar.h> | | 66 | #include <dev/usb/usbdivar.h> |
67 | #include <dev/usb/usb_mem.h> | | 67 | #include <dev/usb/usb_mem.h> |
68 | #include <dev/usb/usb_quirks.h> | | 68 | #include <dev/usb/usb_quirks.h> |
69 | | | 69 | |
70 | #include <dev/usb/ohcireg.h> | | 70 | #include <dev/usb/ohcireg.h> |
71 | #include <dev/usb/ohcivar.h> | | 71 | #include <dev/usb/ohcivar.h> |
72 | #include <dev/usb/usbroothub.h> | | 72 | #include <dev/usb/usbroothub.h> |
73 | #include <dev/usb/usbhist.h> | | 73 | #include <dev/usb/usbhist.h> |
74 | | | 74 | |
75 | #ifdef USB_DEBUG | | 75 | #ifdef USB_DEBUG |
76 | #ifndef OHCI_DEBUG | | 76 | #ifndef OHCI_DEBUG |
77 | #define ohcidebug 0 | | 77 | #define ohcidebug 0 |
78 | #else | | 78 | #else |
79 | static int ohcidebug = 10; | | 79 | static int ohcidebug = 10; |
80 | | | 80 | |
81 | SYSCTL_SETUP(sysctl_hw_ohci_setup, "sysctl hw.ohci setup") | | 81 | SYSCTL_SETUP(sysctl_hw_ohci_setup, "sysctl hw.ohci setup") |
82 | { | | 82 | { |
83 | int err; | | 83 | int err; |
84 | const struct sysctlnode *rnode; | | 84 | const struct sysctlnode *rnode; |
85 | const struct sysctlnode *cnode; | | 85 | const struct sysctlnode *cnode; |
86 | | | 86 | |
87 | err = sysctl_createv(clog, 0, NULL, &rnode, | | 87 | err = sysctl_createv(clog, 0, NULL, &rnode, |
88 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "ohci", | | 88 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "ohci", |
89 | SYSCTL_DESCR("ohci global controls"), | | 89 | SYSCTL_DESCR("ohci global controls"), |
90 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | | 90 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); |
91 | | | 91 | |
92 | if (err) | | 92 | if (err) |
93 | goto fail; | | 93 | goto fail; |
94 | | | 94 | |
95 | /* control debugging printfs */ | | 95 | /* control debugging printfs */ |
96 | err = sysctl_createv(clog, 0, &rnode, &cnode, | | 96 | err = sysctl_createv(clog, 0, &rnode, &cnode, |
97 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | | 97 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
98 | "debug", SYSCTL_DESCR("Enable debugging output"), | | 98 | "debug", SYSCTL_DESCR("Enable debugging output"), |
99 | NULL, 0, &ohcidebug, sizeof(ohcidebug), CTL_CREATE, CTL_EOL); | | 99 | NULL, 0, &ohcidebug, sizeof(ohcidebug), CTL_CREATE, CTL_EOL); |
100 | if (err) | | 100 | if (err) |
101 | goto fail; | | 101 | goto fail; |
102 | | | 102 | |
103 | return; | | 103 | return; |
104 | fail: | | 104 | fail: |
105 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | | 105 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); |
106 | } | | 106 | } |
107 | | | 107 | |
108 | #endif /* OHCI_DEBUG */ | | 108 | #endif /* OHCI_DEBUG */ |
109 | #endif /* USB_DEBUG */ | | 109 | #endif /* USB_DEBUG */ |
110 | | | 110 | |
111 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOG(ohcidebug,FMT,A,B,C,D) | | 111 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOG(ohcidebug,FMT,A,B,C,D) |
112 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(ohcidebug,N,FMT,A,B,C,D) | | 112 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(ohcidebug,N,FMT,A,B,C,D) |
113 | #define OHCIHIST_FUNC() USBHIST_FUNC() | | 113 | #define OHCIHIST_FUNC() USBHIST_FUNC() |
114 | #define OHCIHIST_CALLED(name) USBHIST_CALLED(ohcidebug) | | 114 | #define OHCIHIST_CALLED(name) USBHIST_CALLED(ohcidebug) |
115 | | | 115 | |
116 | #if BYTE_ORDER == BIG_ENDIAN | | 116 | #if BYTE_ORDER == BIG_ENDIAN |
117 | #define SWAP_ENDIAN OHCI_LITTLE_ENDIAN | | 117 | #define SWAP_ENDIAN OHCI_LITTLE_ENDIAN |
118 | #else | | 118 | #else |
119 | #define SWAP_ENDIAN OHCI_BIG_ENDIAN | | 119 | #define SWAP_ENDIAN OHCI_BIG_ENDIAN |
120 | #endif | | 120 | #endif |
121 | | | 121 | |
122 | #define O16TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap16(val) : val) | | 122 | #define O16TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap16(val) : val) |
123 | #define O32TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap32(val) : val) | | 123 | #define O32TOH(val) (sc->sc_endian == SWAP_ENDIAN ? bswap32(val) : val) |
124 | #define HTOO16(val) O16TOH(val) | | 124 | #define HTOO16(val) O16TOH(val) |
125 | #define HTOO32(val) O32TOH(val) | | 125 | #define HTOO32(val) O32TOH(val) |
126 | | | 126 | |
127 | struct ohci_pipe; | | 127 | struct ohci_pipe; |
128 | | | 128 | |
129 | Static ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *); | | 129 | Static ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *); |
130 | Static void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *); | | 130 | Static void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *); |
131 | | | 131 | |
132 | Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *); | | 132 | Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *); |
133 | Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *); | | 133 | Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *); |
134 | Static void ohci_free_std_locked(ohci_softc_t *, ohci_soft_td_t *); | | 134 | Static void ohci_free_std_locked(ohci_softc_t *, ohci_soft_td_t *); |
135 | | | 135 | |
136 | Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *); | | 136 | Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *); |
137 | Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *); | | 137 | Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *); |
138 | Static void ohci_free_sitd_locked(ohci_softc_t *, | | 138 | Static void ohci_free_sitd_locked(ohci_softc_t *, |
139 | ohci_soft_itd_t *); | | 139 | ohci_soft_itd_t *); |
140 | | | 140 | |
141 | Static int ohci_alloc_std_chain(ohci_softc_t *, struct usbd_xfer *, | | 141 | Static int ohci_alloc_std_chain(ohci_softc_t *, struct usbd_xfer *, |
142 | int, int); | | 142 | int, int); |
143 | Static void ohci_free_stds(ohci_softc_t *, struct ohci_xfer *); | | 143 | Static void ohci_free_stds(ohci_softc_t *, struct ohci_xfer *); |
144 | | | 144 | |
145 | Static void ohci_reset_std_chain(ohci_softc_t *, struct usbd_xfer *, | | 145 | Static void ohci_reset_std_chain(ohci_softc_t *, struct usbd_xfer *, |
146 | int, int, ohci_soft_td_t *, ohci_soft_td_t **); | | 146 | int, int, ohci_soft_td_t *, ohci_soft_td_t **); |
147 | | | 147 | |
148 | Static usbd_status ohci_open(struct usbd_pipe *); | | 148 | Static usbd_status ohci_open(struct usbd_pipe *); |
149 | Static void ohci_poll(struct usbd_bus *); | | 149 | Static void ohci_poll(struct usbd_bus *); |
150 | Static void ohci_softintr(void *); | | 150 | Static void ohci_softintr(void *); |
151 | Static void ohci_rhsc(ohci_softc_t *, struct usbd_xfer *); | | 151 | Static void ohci_rhsc(ohci_softc_t *, struct usbd_xfer *); |
152 | Static void ohci_rhsc_softint(void *); | | 152 | Static void ohci_rhsc_softint(void *); |
153 | | | 153 | |
154 | Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *, | | 154 | Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *, |
155 | ohci_soft_ed_t *); | | 155 | ohci_soft_ed_t *); |
156 | | | 156 | |
157 | Static void ohci_rem_ed(ohci_softc_t *, ohci_soft_ed_t *, | | 157 | Static void ohci_rem_ed(ohci_softc_t *, ohci_soft_ed_t *, |
158 | ohci_soft_ed_t *); | | 158 | ohci_soft_ed_t *); |
159 | Static void ohci_hash_add_td(ohci_softc_t *, ohci_soft_td_t *); | | 159 | Static void ohci_hash_add_td(ohci_softc_t *, ohci_soft_td_t *); |
160 | Static void ohci_hash_rem_td(ohci_softc_t *, ohci_soft_td_t *); | | 160 | Static void ohci_hash_rem_td(ohci_softc_t *, ohci_soft_td_t *); |
161 | Static ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, ohci_physaddr_t); | | 161 | Static ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, ohci_physaddr_t); |
162 | Static void ohci_hash_add_itd(ohci_softc_t *, ohci_soft_itd_t *); | | 162 | Static void ohci_hash_add_itd(ohci_softc_t *, ohci_soft_itd_t *); |
163 | Static void ohci_hash_rem_itd(ohci_softc_t *, ohci_soft_itd_t *); | | 163 | Static void ohci_hash_rem_itd(ohci_softc_t *, ohci_soft_itd_t *); |
164 | Static ohci_soft_itd_t *ohci_hash_find_itd(ohci_softc_t *, ohci_physaddr_t); | | 164 | Static ohci_soft_itd_t *ohci_hash_find_itd(ohci_softc_t *, ohci_physaddr_t); |
165 | | | 165 | |
166 | Static usbd_status ohci_setup_isoc(struct usbd_pipe *); | | 166 | Static usbd_status ohci_setup_isoc(struct usbd_pipe *); |
167 | Static void ohci_device_isoc_enter(struct usbd_xfer *); | | 167 | Static void ohci_device_isoc_enter(struct usbd_xfer *); |
168 | | | 168 | |
169 | Static struct usbd_xfer * | | 169 | Static struct usbd_xfer * |
170 | ohci_allocx(struct usbd_bus *, unsigned int); | | 170 | ohci_allocx(struct usbd_bus *, unsigned int); |
171 | Static void ohci_freex(struct usbd_bus *, struct usbd_xfer *); | | 171 | Static void ohci_freex(struct usbd_bus *, struct usbd_xfer *); |
172 | Static bool ohci_dying(struct usbd_bus *); | | 172 | Static bool ohci_dying(struct usbd_bus *); |
173 | Static void ohci_get_lock(struct usbd_bus *, kmutex_t **); | | 173 | Static void ohci_get_lock(struct usbd_bus *, kmutex_t **); |
174 | Static int ohci_roothub_ctrl(struct usbd_bus *, | | 174 | Static int ohci_roothub_ctrl(struct usbd_bus *, |
175 | usb_device_request_t *, void *, int); | | 175 | usb_device_request_t *, void *, int); |
176 | | | 176 | |
177 | Static usbd_status ohci_root_intr_transfer(struct usbd_xfer *); | | 177 | Static usbd_status ohci_root_intr_transfer(struct usbd_xfer *); |
178 | Static usbd_status ohci_root_intr_start(struct usbd_xfer *); | | 178 | Static usbd_status ohci_root_intr_start(struct usbd_xfer *); |
179 | Static void ohci_root_intr_abort(struct usbd_xfer *); | | 179 | Static void ohci_root_intr_abort(struct usbd_xfer *); |
180 | Static void ohci_root_intr_close(struct usbd_pipe *); | | 180 | Static void ohci_root_intr_close(struct usbd_pipe *); |
181 | Static void ohci_root_intr_done(struct usbd_xfer *); | | 181 | Static void ohci_root_intr_done(struct usbd_xfer *); |
182 | | | 182 | |
183 | Static int ohci_device_ctrl_init(struct usbd_xfer *); | | 183 | Static int ohci_device_ctrl_init(struct usbd_xfer *); |
184 | Static void ohci_device_ctrl_fini(struct usbd_xfer *); | | 184 | Static void ohci_device_ctrl_fini(struct usbd_xfer *); |
185 | Static usbd_status ohci_device_ctrl_transfer(struct usbd_xfer *); | | 185 | Static usbd_status ohci_device_ctrl_transfer(struct usbd_xfer *); |
186 | Static usbd_status ohci_device_ctrl_start(struct usbd_xfer *); | | 186 | Static usbd_status ohci_device_ctrl_start(struct usbd_xfer *); |
187 | Static void ohci_device_ctrl_abort(struct usbd_xfer *); | | 187 | Static void ohci_device_ctrl_abort(struct usbd_xfer *); |
188 | Static void ohci_device_ctrl_close(struct usbd_pipe *); | | 188 | Static void ohci_device_ctrl_close(struct usbd_pipe *); |
189 | Static void ohci_device_ctrl_done(struct usbd_xfer *); | | 189 | Static void ohci_device_ctrl_done(struct usbd_xfer *); |
190 | | | 190 | |
191 | Static int ohci_device_bulk_init(struct usbd_xfer *); | | 191 | Static int ohci_device_bulk_init(struct usbd_xfer *); |
192 | Static void ohci_device_bulk_fini(struct usbd_xfer *); | | 192 | Static void ohci_device_bulk_fini(struct usbd_xfer *); |
193 | Static usbd_status ohci_device_bulk_transfer(struct usbd_xfer *); | | 193 | Static usbd_status ohci_device_bulk_transfer(struct usbd_xfer *); |
194 | Static usbd_status ohci_device_bulk_start(struct usbd_xfer *); | | 194 | Static usbd_status ohci_device_bulk_start(struct usbd_xfer *); |
195 | Static void ohci_device_bulk_abort(struct usbd_xfer *); | | 195 | Static void ohci_device_bulk_abort(struct usbd_xfer *); |
196 | Static void ohci_device_bulk_close(struct usbd_pipe *); | | 196 | Static void ohci_device_bulk_close(struct usbd_pipe *); |
197 | Static void ohci_device_bulk_done(struct usbd_xfer *); | | 197 | Static void ohci_device_bulk_done(struct usbd_xfer *); |
198 | | | 198 | |
199 | Static int ohci_device_intr_init(struct usbd_xfer *); | | 199 | Static int ohci_device_intr_init(struct usbd_xfer *); |
200 | Static void ohci_device_intr_fini(struct usbd_xfer *); | | 200 | Static void ohci_device_intr_fini(struct usbd_xfer *); |
201 | Static usbd_status ohci_device_intr_transfer(struct usbd_xfer *); | | 201 | Static usbd_status ohci_device_intr_transfer(struct usbd_xfer *); |
202 | Static usbd_status ohci_device_intr_start(struct usbd_xfer *); | | 202 | Static usbd_status ohci_device_intr_start(struct usbd_xfer *); |
203 | Static void ohci_device_intr_abort(struct usbd_xfer *); | | 203 | Static void ohci_device_intr_abort(struct usbd_xfer *); |
204 | Static void ohci_device_intr_close(struct usbd_pipe *); | | 204 | Static void ohci_device_intr_close(struct usbd_pipe *); |
205 | Static void ohci_device_intr_done(struct usbd_xfer *); | | 205 | Static void ohci_device_intr_done(struct usbd_xfer *); |
206 | | | 206 | |
207 | Static int ohci_device_isoc_init(struct usbd_xfer *); | | 207 | Static int ohci_device_isoc_init(struct usbd_xfer *); |
208 | Static void ohci_device_isoc_fini(struct usbd_xfer *); | | 208 | Static void ohci_device_isoc_fini(struct usbd_xfer *); |
209 | Static usbd_status ohci_device_isoc_transfer(struct usbd_xfer *); | | 209 | Static usbd_status ohci_device_isoc_transfer(struct usbd_xfer *); |
210 | Static void ohci_device_isoc_abort(struct usbd_xfer *); | | 210 | Static void ohci_device_isoc_abort(struct usbd_xfer *); |
211 | Static void ohci_device_isoc_close(struct usbd_pipe *); | | 211 | Static void ohci_device_isoc_close(struct usbd_pipe *); |
212 | Static void ohci_device_isoc_done(struct usbd_xfer *); | | 212 | Static void ohci_device_isoc_done(struct usbd_xfer *); |
213 | | | 213 | |
214 | Static usbd_status ohci_device_setintr(ohci_softc_t *, | | 214 | Static usbd_status ohci_device_setintr(ohci_softc_t *, |
215 | struct ohci_pipe *, int); | | 215 | struct ohci_pipe *, int); |
216 | | | 216 | |
217 | Static void ohci_rhsc_enable(void *); | | 217 | Static void ohci_rhsc_enable(void *); |
218 | | | 218 | |
219 | Static void ohci_close_pipe(struct usbd_pipe *, ohci_soft_ed_t *); | | 219 | Static void ohci_close_pipe(struct usbd_pipe *, ohci_soft_ed_t *); |
220 | Static void ohci_abortx(struct usbd_xfer *); | | 220 | Static void ohci_abortx(struct usbd_xfer *); |
221 | | | 221 | |
222 | Static void ohci_device_clear_toggle(struct usbd_pipe *); | | 222 | Static void ohci_device_clear_toggle(struct usbd_pipe *); |
223 | Static void ohci_noop(struct usbd_pipe *); | | 223 | Static void ohci_noop(struct usbd_pipe *); |
224 | | | 224 | |
225 | #ifdef OHCI_DEBUG | | 225 | #ifdef OHCI_DEBUG |
226 | Static void ohci_dumpregs(ohci_softc_t *); | | 226 | Static void ohci_dumpregs(ohci_softc_t *); |
227 | Static void ohci_dump_tds(ohci_softc_t *, ohci_soft_td_t *); | | 227 | Static void ohci_dump_tds(ohci_softc_t *, ohci_soft_td_t *); |
228 | Static void ohci_dump_td(ohci_softc_t *, ohci_soft_td_t *); | | 228 | Static void ohci_dump_td(ohci_softc_t *, ohci_soft_td_t *); |
229 | Static void ohci_dump_ed(ohci_softc_t *, ohci_soft_ed_t *); | | 229 | Static void ohci_dump_ed(ohci_softc_t *, ohci_soft_ed_t *); |
230 | Static void ohci_dump_itd(ohci_softc_t *, ohci_soft_itd_t *); | | 230 | Static void ohci_dump_itd(ohci_softc_t *, ohci_soft_itd_t *); |
231 | Static void ohci_dump_itds(ohci_softc_t *, ohci_soft_itd_t *); | | 231 | Static void ohci_dump_itds(ohci_softc_t *, ohci_soft_itd_t *); |
232 | #endif | | 232 | #endif |
233 | | | 233 | |
234 | #define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ | | 234 | #define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ |
235 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) | | 235 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) |
236 | #define OWRITE1(sc, r, x) \ | | 236 | #define OWRITE1(sc, r, x) \ |
237 | do { OBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | | 237 | do { OBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0) |
238 | #define OWRITE2(sc, r, x) \ | | 238 | #define OWRITE2(sc, r, x) \ |
239 | do { OBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | | 239 | do { OBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0) |
240 | #define OWRITE4(sc, r, x) \ | | 240 | #define OWRITE4(sc, r, x) \ |
241 | do { OBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0) | | 241 | do { OBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0) |
242 | | | 242 | |
243 | static __inline uint32_t | | 243 | static __inline uint32_t |
244 | OREAD4(ohci_softc_t *sc, bus_size_t r) | | 244 | OREAD4(ohci_softc_t *sc, bus_size_t r) |
245 | { | | 245 | { |
246 | | | 246 | |
247 | OBARR(sc); | | 247 | OBARR(sc); |
248 | return bus_space_read_4(sc->iot, sc->ioh, r); | | 248 | return bus_space_read_4(sc->iot, sc->ioh, r); |
249 | } | | 249 | } |
250 | | | 250 | |
251 | /* Reverse the bits in a value 0 .. 31 */ | | 251 | /* Reverse the bits in a value 0 .. 31 */ |
252 | Static uint8_t revbits[OHCI_NO_INTRS] = | | 252 | Static uint8_t revbits[OHCI_NO_INTRS] = |
253 | { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, | | 253 | { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, |
254 | 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, | | 254 | 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, |
255 | 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, | | 255 | 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, |
256 | 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; | | 256 | 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; |
257 | | | 257 | |
258 | struct ohci_pipe { | | 258 | struct ohci_pipe { |
259 | struct usbd_pipe pipe; | | 259 | struct usbd_pipe pipe; |
260 | ohci_soft_ed_t *sed; | | 260 | ohci_soft_ed_t *sed; |
261 | union { | | 261 | union { |
262 | ohci_soft_td_t *td; | | 262 | ohci_soft_td_t *td; |
263 | ohci_soft_itd_t *itd; | | 263 | ohci_soft_itd_t *itd; |
264 | } tail; | | 264 | } tail; |
265 | /* Info needed for different pipe kinds. */ | | 265 | /* Info needed for different pipe kinds. */ |
266 | union { | | 266 | union { |
267 | /* Control pipe */ | | 267 | /* Control pipe */ |
268 | struct { | | 268 | struct { |
269 | usb_dma_t reqdma; | | 269 | usb_dma_t reqdma; |
270 | } ctrl; | | 270 | } ctrl; |
271 | /* Interrupt pipe */ | | 271 | /* Interrupt pipe */ |
272 | struct { | | 272 | struct { |
273 | int nslots; | | 273 | int nslots; |
274 | int pos; | | 274 | int pos; |
275 | } intr; | | 275 | } intr; |
276 | /* Isochronous pipe */ | | 276 | /* Isochronous pipe */ |
277 | struct isoc { | | 277 | struct isoc { |
278 | int next, inuse; | | 278 | int next, inuse; |
279 | } isoc; | | 279 | } isoc; |
280 | }; | | 280 | }; |
281 | }; | | 281 | }; |
282 | | | 282 | |
283 | Static const struct usbd_bus_methods ohci_bus_methods = { | | 283 | Static const struct usbd_bus_methods ohci_bus_methods = { |
284 | .ubm_open = ohci_open, | | 284 | .ubm_open = ohci_open, |
285 | .ubm_softint = ohci_softintr, | | 285 | .ubm_softint = ohci_softintr, |
286 | .ubm_dopoll = ohci_poll, | | 286 | .ubm_dopoll = ohci_poll, |
287 | .ubm_allocx = ohci_allocx, | | 287 | .ubm_allocx = ohci_allocx, |
288 | .ubm_freex = ohci_freex, | | 288 | .ubm_freex = ohci_freex, |
289 | .ubm_abortx = ohci_abortx, | | 289 | .ubm_abortx = ohci_abortx, |
290 | .ubm_dying = ohci_dying, | | 290 | .ubm_dying = ohci_dying, |
291 | .ubm_getlock = ohci_get_lock, | | 291 | .ubm_getlock = ohci_get_lock, |
292 | .ubm_rhctrl = ohci_roothub_ctrl, | | 292 | .ubm_rhctrl = ohci_roothub_ctrl, |
293 | }; | | 293 | }; |
294 | | | 294 | |
295 | Static const struct usbd_pipe_methods ohci_root_intr_methods = { | | 295 | Static const struct usbd_pipe_methods ohci_root_intr_methods = { |
296 | .upm_transfer = ohci_root_intr_transfer, | | 296 | .upm_transfer = ohci_root_intr_transfer, |
297 | .upm_start = ohci_root_intr_start, | | 297 | .upm_start = ohci_root_intr_start, |
298 | .upm_abort = ohci_root_intr_abort, | | 298 | .upm_abort = ohci_root_intr_abort, |
299 | .upm_close = ohci_root_intr_close, | | 299 | .upm_close = ohci_root_intr_close, |
300 | .upm_cleartoggle = ohci_noop, | | 300 | .upm_cleartoggle = ohci_noop, |
301 | .upm_done = ohci_root_intr_done, | | 301 | .upm_done = ohci_root_intr_done, |
302 | }; | | 302 | }; |
303 | | | 303 | |
304 | Static const struct usbd_pipe_methods ohci_device_ctrl_methods = { | | 304 | Static const struct usbd_pipe_methods ohci_device_ctrl_methods = { |
305 | .upm_init = ohci_device_ctrl_init, | | 305 | .upm_init = ohci_device_ctrl_init, |
306 | .upm_fini = ohci_device_ctrl_fini, | | 306 | .upm_fini = ohci_device_ctrl_fini, |
307 | .upm_transfer = ohci_device_ctrl_transfer, | | 307 | .upm_transfer = ohci_device_ctrl_transfer, |
308 | .upm_start = ohci_device_ctrl_start, | | 308 | .upm_start = ohci_device_ctrl_start, |
309 | .upm_abort = ohci_device_ctrl_abort, | | 309 | .upm_abort = ohci_device_ctrl_abort, |
310 | .upm_close = ohci_device_ctrl_close, | | 310 | .upm_close = ohci_device_ctrl_close, |
311 | .upm_cleartoggle = ohci_noop, | | 311 | .upm_cleartoggle = ohci_noop, |
312 | .upm_done = ohci_device_ctrl_done, | | 312 | .upm_done = ohci_device_ctrl_done, |
313 | }; | | 313 | }; |
314 | | | 314 | |
315 | Static const struct usbd_pipe_methods ohci_device_intr_methods = { | | 315 | Static const struct usbd_pipe_methods ohci_device_intr_methods = { |
316 | .upm_init = ohci_device_intr_init, | | 316 | .upm_init = ohci_device_intr_init, |
317 | .upm_fini = ohci_device_intr_fini, | | 317 | .upm_fini = ohci_device_intr_fini, |
318 | .upm_transfer = ohci_device_intr_transfer, | | 318 | .upm_transfer = ohci_device_intr_transfer, |
319 | .upm_start = ohci_device_intr_start, | | 319 | .upm_start = ohci_device_intr_start, |
320 | .upm_abort = ohci_device_intr_abort, | | 320 | .upm_abort = ohci_device_intr_abort, |
321 | .upm_close = ohci_device_intr_close, | | 321 | .upm_close = ohci_device_intr_close, |
322 | .upm_cleartoggle = ohci_device_clear_toggle, | | 322 | .upm_cleartoggle = ohci_device_clear_toggle, |
323 | .upm_done = ohci_device_intr_done, | | 323 | .upm_done = ohci_device_intr_done, |
324 | }; | | 324 | }; |
325 | | | 325 | |
326 | Static const struct usbd_pipe_methods ohci_device_bulk_methods = { | | 326 | Static const struct usbd_pipe_methods ohci_device_bulk_methods = { |
327 | .upm_init = ohci_device_bulk_init, | | 327 | .upm_init = ohci_device_bulk_init, |
328 | .upm_fini = ohci_device_bulk_fini, | | 328 | .upm_fini = ohci_device_bulk_fini, |
329 | .upm_transfer = ohci_device_bulk_transfer, | | 329 | .upm_transfer = ohci_device_bulk_transfer, |
330 | .upm_start = ohci_device_bulk_start, | | 330 | .upm_start = ohci_device_bulk_start, |
331 | .upm_abort = ohci_device_bulk_abort, | | 331 | .upm_abort = ohci_device_bulk_abort, |
332 | .upm_close = ohci_device_bulk_close, | | 332 | .upm_close = ohci_device_bulk_close, |
333 | .upm_cleartoggle = ohci_device_clear_toggle, | | 333 | .upm_cleartoggle = ohci_device_clear_toggle, |
334 | .upm_done = ohci_device_bulk_done, | | 334 | .upm_done = ohci_device_bulk_done, |
335 | }; | | 335 | }; |
336 | | | 336 | |
337 | Static const struct usbd_pipe_methods ohci_device_isoc_methods = { | | 337 | Static const struct usbd_pipe_methods ohci_device_isoc_methods = { |
338 | .upm_init = ohci_device_isoc_init, | | 338 | .upm_init = ohci_device_isoc_init, |
339 | .upm_fini = ohci_device_isoc_fini, | | 339 | .upm_fini = ohci_device_isoc_fini, |
340 | .upm_transfer = ohci_device_isoc_transfer, | | 340 | .upm_transfer = ohci_device_isoc_transfer, |
341 | .upm_abort = ohci_device_isoc_abort, | | 341 | .upm_abort = ohci_device_isoc_abort, |
342 | .upm_close = ohci_device_isoc_close, | | 342 | .upm_close = ohci_device_isoc_close, |
343 | .upm_cleartoggle = ohci_noop, | | 343 | .upm_cleartoggle = ohci_noop, |
344 | .upm_done = ohci_device_isoc_done, | | 344 | .upm_done = ohci_device_isoc_done, |
345 | }; | | 345 | }; |
346 | | | 346 | |
347 | int | | 347 | int |
348 | ohci_activate(device_t self, enum devact act) | | 348 | ohci_activate(device_t self, enum devact act) |
349 | { | | 349 | { |
350 | struct ohci_softc *sc = device_private(self); | | 350 | struct ohci_softc *sc = device_private(self); |
351 | | | 351 | |
352 | switch (act) { | | 352 | switch (act) { |
353 | case DVACT_DEACTIVATE: | | 353 | case DVACT_DEACTIVATE: |
354 | sc->sc_dying = 1; | | 354 | sc->sc_dying = 1; |
355 | return 0; | | 355 | return 0; |
356 | default: | | 356 | default: |
357 | return EOPNOTSUPP; | | 357 | return EOPNOTSUPP; |
358 | } | | 358 | } |
359 | } | | 359 | } |
360 | | | 360 | |
361 | void | | 361 | void |
362 | ohci_childdet(device_t self, device_t child) | | 362 | ohci_childdet(device_t self, device_t child) |
363 | { | | 363 | { |
364 | struct ohci_softc *sc = device_private(self); | | 364 | struct ohci_softc *sc = device_private(self); |
365 | | | 365 | |
366 | KASSERT(sc->sc_child == child); | | 366 | KASSERT(sc->sc_child == child); |
367 | sc->sc_child = NULL; | | 367 | sc->sc_child = NULL; |
368 | } | | 368 | } |
369 | | | 369 | |
370 | int | | 370 | int |
371 | ohci_detach(struct ohci_softc *sc, int flags) | | 371 | ohci_detach(struct ohci_softc *sc, int flags) |
372 | { | | 372 | { |
373 | int rv = 0; | | 373 | int rv = 0; |
374 | | | 374 | |
375 | if (sc->sc_child != NULL) | | 375 | if (sc->sc_child != NULL) |
376 | rv = config_detach(sc->sc_child, flags); | | 376 | rv = config_detach(sc->sc_child, flags); |
377 | | | 377 | |
378 | if (rv != 0) | | 378 | if (rv != 0) |
379 | return rv; | | 379 | return rv; |
380 | | | 380 | |
381 | softint_disestablish(sc->sc_rhsc_si); | | 381 | softint_disestablish(sc->sc_rhsc_si); |
382 | | | 382 | |
383 | callout_halt(&sc->sc_tmo_rhsc, NULL); | | 383 | callout_halt(&sc->sc_tmo_rhsc, NULL); |
384 | callout_destroy(&sc->sc_tmo_rhsc); | | 384 | callout_destroy(&sc->sc_tmo_rhsc); |
385 | | | 385 | |
386 | mutex_destroy(&sc->sc_lock); | | 386 | mutex_destroy(&sc->sc_lock); |
387 | mutex_destroy(&sc->sc_intr_lock); | | 387 | mutex_destroy(&sc->sc_intr_lock); |
388 | | | 388 | |
389 | if (sc->sc_hcca != NULL) | | 389 | if (sc->sc_hcca != NULL) |
390 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); | | 390 | usb_freemem(&sc->sc_bus, &sc->sc_hccadma); |
391 | pool_cache_destroy(sc->sc_xferpool); | | 391 | pool_cache_destroy(sc->sc_xferpool); |
392 | | | 392 | |
393 | return rv; | | 393 | return rv; |
394 | } | | 394 | } |
395 | | | 395 | |
396 | ohci_soft_ed_t * | | 396 | ohci_soft_ed_t * |
397 | ohci_alloc_sed(ohci_softc_t *sc) | | 397 | ohci_alloc_sed(ohci_softc_t *sc) |
398 | { | | 398 | { |
399 | ohci_soft_ed_t *sed; | | 399 | ohci_soft_ed_t *sed; |
400 | usbd_status err; | | 400 | usbd_status err; |
401 | int i, offs; | | 401 | int i, offs; |
402 | usb_dma_t dma; | | 402 | usb_dma_t dma; |
403 | | | 403 | |
404 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 404 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
405 | | | 405 | |
406 | mutex_enter(&sc->sc_lock); | | 406 | mutex_enter(&sc->sc_lock); |
407 | if (sc->sc_freeeds == NULL) { | | 407 | if (sc->sc_freeeds == NULL) { |
408 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); | | 408 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); |
409 | mutex_exit(&sc->sc_lock); | | 409 | mutex_exit(&sc->sc_lock); |
410 | | | 410 | |
411 | err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK, | | 411 | err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK, |
412 | OHCI_ED_ALIGN, &dma); | | 412 | OHCI_ED_ALIGN, &dma); |
413 | if (err) | | 413 | if (err) |
414 | return 0; | | 414 | return 0; |
415 | | | 415 | |
416 | mutex_enter(&sc->sc_lock); | | 416 | mutex_enter(&sc->sc_lock); |
417 | for (i = 0; i < OHCI_SED_CHUNK; i++) { | | 417 | for (i = 0; i < OHCI_SED_CHUNK; i++) { |
418 | offs = i * OHCI_SED_SIZE; | | 418 | offs = i * OHCI_SED_SIZE; |
419 | sed = KERNADDR(&dma, offs); | | 419 | sed = KERNADDR(&dma, offs); |
420 | sed->physaddr = DMAADDR(&dma, offs); | | 420 | sed->physaddr = DMAADDR(&dma, offs); |
421 | sed->dma = dma; | | 421 | sed->dma = dma; |
422 | sed->offs = offs; | | 422 | sed->offs = offs; |
423 | sed->next = sc->sc_freeeds; | | 423 | sed->next = sc->sc_freeeds; |
424 | sc->sc_freeeds = sed; | | 424 | sc->sc_freeeds = sed; |
425 | } | | 425 | } |
426 | } | | 426 | } |
427 | sed = sc->sc_freeeds; | | 427 | sed = sc->sc_freeeds; |
428 | sc->sc_freeeds = sed->next; | | 428 | sc->sc_freeeds = sed->next; |
429 | mutex_exit(&sc->sc_lock); | | 429 | mutex_exit(&sc->sc_lock); |
430 | | | 430 | |
431 | memset(&sed->ed, 0, sizeof(ohci_ed_t)); | | 431 | memset(&sed->ed, 0, sizeof(ohci_ed_t)); |
432 | sed->next = 0; | | 432 | sed->next = 0; |
433 | return sed; | | 433 | return sed; |
434 | } | | 434 | } |
435 | | | 435 | |
436 | static inline void | | 436 | static inline void |
437 | ohci_free_sed_locked(ohci_softc_t *sc, ohci_soft_ed_t *sed) | | 437 | ohci_free_sed_locked(ohci_softc_t *sc, ohci_soft_ed_t *sed) |
438 | { | | 438 | { |
439 | | | 439 | |
440 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 440 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
441 | | | 441 | |
442 | sed->next = sc->sc_freeeds; | | 442 | sed->next = sc->sc_freeeds; |
443 | sc->sc_freeeds = sed; | | 443 | sc->sc_freeeds = sed; |
444 | } | | 444 | } |
445 | | | 445 | |
446 | void | | 446 | void |
447 | ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed) | | 447 | ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed) |
448 | { | | 448 | { |
449 | | | 449 | |
450 | mutex_enter(&sc->sc_lock); | | 450 | mutex_enter(&sc->sc_lock); |
451 | ohci_free_sed_locked(sc, sed); | | 451 | ohci_free_sed_locked(sc, sed); |
452 | mutex_exit(&sc->sc_lock); | | 452 | mutex_exit(&sc->sc_lock); |
453 | } | | 453 | } |
454 | | | 454 | |
455 | ohci_soft_td_t * | | 455 | ohci_soft_td_t * |
456 | ohci_alloc_std(ohci_softc_t *sc) | | 456 | ohci_alloc_std(ohci_softc_t *sc) |
457 | { | | 457 | { |
458 | ohci_soft_td_t *std; | | 458 | ohci_soft_td_t *std; |
459 | usbd_status err; | | 459 | usbd_status err; |
460 | int i, offs; | | 460 | int i, offs; |
461 | usb_dma_t dma; | | 461 | usb_dma_t dma; |
462 | | | 462 | |
463 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 463 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
464 | | | 464 | |
465 | mutex_enter(&sc->sc_lock); | | 465 | mutex_enter(&sc->sc_lock); |
466 | if (sc->sc_freetds == NULL) { | | 466 | if (sc->sc_freetds == NULL) { |
467 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); | | 467 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); |
468 | mutex_exit(&sc->sc_lock); | | 468 | mutex_exit(&sc->sc_lock); |
469 | | | 469 | |
470 | err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK, | | 470 | err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK, |
471 | OHCI_TD_ALIGN, &dma); | | 471 | OHCI_TD_ALIGN, &dma); |
472 | if (err) | | 472 | if (err) |
473 | return NULL; | | 473 | return NULL; |
474 | | | 474 | |
475 | mutex_enter(&sc->sc_lock); | | 475 | mutex_enter(&sc->sc_lock); |
476 | for (i = 0; i < OHCI_STD_CHUNK; i++) { | | 476 | for (i = 0; i < OHCI_STD_CHUNK; i++) { |
477 | offs = i * OHCI_STD_SIZE; | | 477 | offs = i * OHCI_STD_SIZE; |
478 | std = KERNADDR(&dma, offs); | | 478 | std = KERNADDR(&dma, offs); |
479 | std->physaddr = DMAADDR(&dma, offs); | | 479 | std->physaddr = DMAADDR(&dma, offs); |
480 | std->dma = dma; | | 480 | std->dma = dma; |
481 | std->offs = offs; | | 481 | std->offs = offs; |
482 | std->nexttd = sc->sc_freetds; | | 482 | std->nexttd = sc->sc_freetds; |
483 | sc->sc_freetds = std; | | 483 | sc->sc_freetds = std; |
484 | } | | 484 | } |
485 | } | | 485 | } |
486 | | | 486 | |
487 | std = sc->sc_freetds; | | 487 | std = sc->sc_freetds; |
488 | sc->sc_freetds = std->nexttd; | | 488 | sc->sc_freetds = std->nexttd; |
489 | mutex_exit(&sc->sc_lock); | | 489 | mutex_exit(&sc->sc_lock); |
490 | | | 490 | |
491 | memset(&std->td, 0, sizeof(ohci_td_t)); | | 491 | memset(&std->td, 0, sizeof(ohci_td_t)); |
492 | std->nexttd = NULL; | | 492 | std->nexttd = NULL; |
493 | std->xfer = NULL; | | 493 | std->xfer = NULL; |
494 | | | 494 | |
495 | return std; | | 495 | return std; |
496 | } | | 496 | } |
497 | | | 497 | |
498 | void | | 498 | void |
499 | ohci_free_std_locked(ohci_softc_t *sc, ohci_soft_td_t *std) | | 499 | ohci_free_std_locked(ohci_softc_t *sc, ohci_soft_td_t *std) |
500 | { | | 500 | { |
501 | | | 501 | |
502 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 502 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
503 | | | 503 | |
504 | std->nexttd = sc->sc_freetds; | | 504 | std->nexttd = sc->sc_freetds; |
505 | sc->sc_freetds = std; | | 505 | sc->sc_freetds = std; |
506 | } | | 506 | } |
507 | | | 507 | |
508 | void | | 508 | void |
509 | ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std) | | 509 | ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std) |
510 | { | | 510 | { |
511 | | | 511 | |
512 | mutex_enter(&sc->sc_lock); | | 512 | mutex_enter(&sc->sc_lock); |
513 | ohci_free_std_locked(sc, std); | | 513 | ohci_free_std_locked(sc, std); |
514 | mutex_exit(&sc->sc_lock); | | 514 | mutex_exit(&sc->sc_lock); |
515 | } | | 515 | } |
516 | | | 516 | |
517 | Static int | | 517 | Static int |
518 | ohci_alloc_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, int length, int rd) | | 518 | ohci_alloc_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, int length, int rd) |
519 | { | | 519 | { |
520 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 520 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
521 | uint16_t flags = xfer->ux_flags; | | 521 | uint16_t flags = xfer->ux_flags; |
522 | | | 522 | |
523 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 523 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
524 | | | 524 | |
525 | DPRINTFN(8, "addr=%jd endpt=%jd len=%jd speed=%jd", | | 525 | DPRINTFN(8, "addr=%jd endpt=%jd len=%jd speed=%jd", |
526 | xfer->ux_pipe->up_dev->ud_addr, | | 526 | xfer->ux_pipe->up_dev->ud_addr, |
527 | UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress), | | 527 | UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress), |
528 | length, xfer->ux_pipe->up_dev->ud_speed); | | 528 | length, xfer->ux_pipe->up_dev->ud_speed); |
529 | | | 529 | |
530 | ASSERT_SLEEPABLE(); | | 530 | ASSERT_SLEEPABLE(); |
531 | KASSERT(length != 0 || (!rd && (flags & USBD_FORCE_SHORT_XFER))); | | 531 | KASSERT(length != 0 || (!rd && (flags & USBD_FORCE_SHORT_XFER))); |
532 | | | 532 | |
533 | size_t nstd = (!rd && (flags & USBD_FORCE_SHORT_XFER)) ? 1 : 0; | | 533 | size_t nstd = (!rd && (flags & USBD_FORCE_SHORT_XFER)) ? 1 : 0; |
534 | nstd += ((length + OHCI_PAGE_SIZE - 1) / OHCI_PAGE_SIZE); | | 534 | nstd += ((length + OHCI_PAGE_SIZE - 1) / OHCI_PAGE_SIZE); |
535 | ox->ox_stds = kmem_zalloc(sizeof(ohci_soft_td_t *) * nstd, | | 535 | ox->ox_stds = kmem_zalloc(sizeof(ohci_soft_td_t *) * nstd, |
536 | KM_SLEEP); | | 536 | KM_SLEEP); |
537 | ox->ox_nstd = nstd; | | 537 | ox->ox_nstd = nstd; |
538 | | | 538 | |
539 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, nstd, 0, 0); | | 539 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, nstd, 0, 0); |
540 | | | 540 | |
541 | for (size_t j = 0; j < ox->ox_nstd;) { | | 541 | for (size_t j = 0; j < ox->ox_nstd;) { |
542 | ohci_soft_td_t *cur = ohci_alloc_std(sc); | | 542 | ohci_soft_td_t *cur = ohci_alloc_std(sc); |
543 | if (cur == NULL) | | 543 | if (cur == NULL) |
544 | goto nomem; | | 544 | goto nomem; |
545 | | | 545 | |
546 | ox->ox_stds[j++] = cur; | | 546 | ox->ox_stds[j++] = cur; |
547 | cur->xfer = xfer; | | 547 | cur->xfer = xfer; |
548 | cur->flags = 0; | | 548 | cur->flags = 0; |
549 | } | | 549 | } |
550 | | | 550 | |
551 | return 0; | | 551 | return 0; |
552 | | | 552 | |
553 | nomem: | | 553 | nomem: |
554 | ohci_free_stds(sc, ox); | | 554 | ohci_free_stds(sc, ox); |
555 | kmem_free(ox->ox_stds, sizeof(ohci_soft_td_t *) * nstd); | | 555 | kmem_free(ox->ox_stds, sizeof(ohci_soft_td_t *) * nstd); |
556 | | | 556 | |
557 | return ENOMEM; | | 557 | return ENOMEM; |
558 | } | | 558 | } |
559 | | | 559 | |
560 | Static void | | 560 | Static void |
561 | ohci_free_stds(ohci_softc_t *sc, struct ohci_xfer *ox) | | 561 | ohci_free_stds(ohci_softc_t *sc, struct ohci_xfer *ox) |
562 | { | | 562 | { |
563 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 563 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
564 | DPRINTF("ox=%#jx", (uintptr_t)ox, 0, 0, 0); | | 564 | DPRINTF("ox=%#jx", (uintptr_t)ox, 0, 0, 0); |
565 | | | 565 | |
566 | mutex_enter(&sc->sc_lock); | | 566 | mutex_enter(&sc->sc_lock); |
567 | for (size_t i = 0; i < ox->ox_nstd; i++) { | | 567 | for (size_t i = 0; i < ox->ox_nstd; i++) { |
568 | ohci_soft_td_t *std = ox->ox_stds[i]; | | 568 | ohci_soft_td_t *std = ox->ox_stds[i]; |
569 | if (std == NULL) | | 569 | if (std == NULL) |
570 | break; | | 570 | break; |
571 | ohci_free_std_locked(sc, std); | | 571 | ohci_free_std_locked(sc, std); |
572 | } | | 572 | } |
573 | mutex_exit(&sc->sc_lock); | | 573 | mutex_exit(&sc->sc_lock); |
574 | } | | 574 | } |
575 | | | 575 | |
576 | void | | 576 | void |
577 | ohci_reset_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, | | 577 | ohci_reset_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, |
578 | int alen, int rd, ohci_soft_td_t *sp, ohci_soft_td_t **ep) | | 578 | int alen, int rd, ohci_soft_td_t *sp, ohci_soft_td_t **ep) |
579 | { | | 579 | { |
580 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 580 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
581 | ohci_soft_td_t *next, *cur; | | 581 | ohci_soft_td_t *next, *cur; |
582 | int len, curlen; | | 582 | int len, curlen; |
583 | usb_dma_t *dma = &xfer->ux_dmabuf; | | 583 | usb_dma_t *dma = &xfer->ux_dmabuf; |
584 | uint16_t flags = xfer->ux_flags; | | 584 | uint16_t flags = xfer->ux_flags; |
585 | | | 585 | |
586 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 586 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
587 | DPRINTF("start len=%jd", alen, 0, 0, 0); | | 587 | DPRINTF("start len=%jd", alen, 0, 0, 0); |
588 | | | 588 | |
589 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); | | 589 | KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock)); |
590 | | | 590 | |
591 | DPRINTFN(8, "addr=%jd endpt=%jd len=%jd speed=%jd", | | 591 | DPRINTFN(8, "addr=%jd endpt=%jd len=%jd speed=%jd", |
592 | xfer->ux_pipe->up_dev->ud_addr, | | 592 | xfer->ux_pipe->up_dev->ud_addr, |
593 | UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress), | | 593 | UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress), |
594 | alen, xfer->ux_pipe->up_dev->ud_speed); | | 594 | alen, xfer->ux_pipe->up_dev->ud_speed); |
595 | | | 595 | |
596 | KASSERT(sp); | | 596 | KASSERT(sp); |
597 | | | 597 | |
598 | int mps = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize); | | 598 | int mps = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize); |
599 | | | 599 | |
600 | /* | | 600 | /* |
601 | * Assign next for the len == 0 case where we don't go through the | | 601 | * Assign next for the len == 0 case where we don't go through the |
602 | * main loop. | | 602 | * main loop. |
603 | */ | | 603 | */ |
604 | len = alen; | | 604 | len = alen; |
605 | cur = next = sp; | | 605 | cur = next = sp; |
606 | | | 606 | |
607 | usb_syncmem(dma, 0, len, | | 607 | usb_syncmem(dma, 0, len, |
608 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | | 608 | rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); |
609 | const uint32_t tdflags = HTOO32( | | 609 | const uint32_t tdflags = HTOO32( |
610 | (rd ? OHCI_TD_IN : OHCI_TD_OUT) | | | 610 | (rd ? OHCI_TD_IN : OHCI_TD_OUT) | |
611 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); | | 611 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR); |
612 | | | 612 | |
613 | size_t curoffs = 0; | | 613 | size_t curoffs = 0; |
614 | for (size_t j = 1; len != 0;) { | | 614 | for (size_t j = 1; len != 0;) { |
615 | if (j == ox->ox_nstd) | | 615 | if (j == ox->ox_nstd) |
616 | next = NULL; | | 616 | next = NULL; |
617 | else | | 617 | else |
618 | next = ox->ox_stds[j++]; | | 618 | next = ox->ox_stds[j++]; |
619 | KASSERT(next != cur); | | 619 | KASSERT(next != cur); |
620 | | | 620 | |
621 | curlen = 0; | | 621 | curlen = 0; |
622 | const ohci_physaddr_t sdataphys = DMAADDR(dma, curoffs); | | 622 | const ohci_physaddr_t sdataphys = DMAADDR(dma, curoffs); |
623 | ohci_physaddr_t edataphys = DMAADDR(dma, curoffs + len - 1); | | 623 | ohci_physaddr_t edataphys = DMAADDR(dma, curoffs + len - 1); |
624 | | | 624 | |
625 | const ohci_physaddr_t sphyspg = OHCI_PAGE(sdataphys); | | 625 | const ohci_physaddr_t sphyspg = OHCI_PAGE(sdataphys); |
626 | ohci_physaddr_t ephyspg = OHCI_PAGE(edataphys); | | 626 | ohci_physaddr_t ephyspg = OHCI_PAGE(edataphys); |
627 | /* | | 627 | /* |
628 | * The OHCI hardware can handle at most one page | | 628 | * The OHCI hardware can handle at most one page |
629 | * crossing per TD | | 629 | * crossing per TD |
630 | */ | | 630 | */ |
631 | curlen = len; | | 631 | curlen = len; |
632 | if (sphyspg != ephyspg && | | 632 | if (sphyspg != ephyspg && |
633 | sphyspg + OHCI_PAGE_SIZE != ephyspg) { | | 633 | sphyspg + OHCI_PAGE_SIZE != ephyspg) { |
634 | /* must use multiple TDs, fill as much as possible. */ | | 634 | /* must use multiple TDs, fill as much as possible. */ |
635 | curlen = 2 * OHCI_PAGE_SIZE - | | 635 | curlen = 2 * OHCI_PAGE_SIZE - |
636 | OHCI_PAGE_OFFSET(sdataphys); | | 636 | OHCI_PAGE_OFFSET(sdataphys); |
637 | /* the length must be a multiple of the max size */ | | 637 | /* the length must be a multiple of the max size */ |
638 | curlen -= curlen % mps; | | 638 | curlen -= curlen % mps; |
639 | edataphys = DMAADDR(dma, curoffs + curlen - 1); | | 639 | edataphys = DMAADDR(dma, curoffs + curlen - 1); |
640 | } | | 640 | } |
641 | KASSERT(curlen != 0); | | 641 | KASSERT(curlen != 0); |
642 | DPRINTFN(4, "sdataphys=0x%08jx edataphys=0x%08jx " | | 642 | DPRINTFN(4, "sdataphys=0x%08jx edataphys=0x%08jx " |
643 | "len=%jd curlen=%jd", sdataphys, edataphys, len, curlen); | | 643 | "len=%jd curlen=%jd", sdataphys, edataphys, len, curlen); |
644 | | | 644 | |
645 | cur->td.td_flags = tdflags; | | 645 | cur->td.td_flags = tdflags; |
646 | cur->td.td_cbp = HTOO32(sdataphys); | | 646 | cur->td.td_cbp = HTOO32(sdataphys); |
647 | cur->td.td_be = HTOO32(edataphys); | | 647 | cur->td.td_be = HTOO32(edataphys); |
648 | cur->td.td_nexttd = (next != NULL) ? HTOO32(next->physaddr) : 0; | | 648 | cur->td.td_nexttd = (next != NULL) ? HTOO32(next->physaddr) : 0; |
649 | cur->nexttd = next; | | 649 | cur->nexttd = next; |
650 | cur->len = curlen; | | 650 | cur->len = curlen; |
651 | cur->flags = OHCI_ADD_LEN; | | 651 | cur->flags = OHCI_ADD_LEN; |
652 | cur->xfer = xfer; | | 652 | cur->xfer = xfer; |
653 | ohci_hash_add_td(sc, cur); | | 653 | ohci_hash_add_td(sc, cur); |
654 | | | 654 | |
655 | curoffs += curlen; | | 655 | curoffs += curlen; |
656 | len -= curlen; | | 656 | len -= curlen; |
657 | | | 657 | |
658 | if (len != 0) { | | 658 | if (len != 0) { |
659 | KASSERT(next != NULL); | | 659 | KASSERT(next != NULL); |
660 | DPRINTFN(10, "extend chain", 0, 0, 0, 0); | | 660 | DPRINTFN(10, "extend chain", 0, 0, 0, 0); |
661 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), | | 661 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), |
662 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 662 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
663 | | | 663 | |
664 | cur = next; | | 664 | cur = next; |
665 | } | | 665 | } |
666 | } | | 666 | } |
667 | cur->td.td_flags |= | | 667 | cur->td.td_flags |= |
668 | HTOO32(xfer->ux_flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0); | | 668 | HTOO32(xfer->ux_flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0); |
669 | | | 669 | |
670 | if (!rd && | | 670 | if (!rd && |
671 | (flags & USBD_FORCE_SHORT_XFER) && | | 671 | (flags & USBD_FORCE_SHORT_XFER) && |
672 | alen % mps == 0) { | | 672 | alen % mps == 0) { |
673 | /* We're adding a ZLP so sync the previous TD */ | | 673 | /* We're adding a ZLP so sync the previous TD */ |
674 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), | | 674 | usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), |
675 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 675 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
676 | | | 676 | |
677 | /* Force a 0 length transfer at the end. */ | | 677 | /* Force a 0 length transfer at the end. */ |
678 | | | 678 | |
679 | KASSERT(next != NULL); | | 679 | KASSERT(next != NULL); |
680 | cur = next; | | 680 | cur = next; |
681 | | | 681 | |
682 | cur->td.td_flags = tdflags; | | 682 | cur->td.td_flags = tdflags; |
683 | cur->td.td_cbp = 0; /* indicate 0 length packet */ | | 683 | cur->td.td_cbp = 0; /* indicate 0 length packet */ |
684 | cur->td.td_nexttd = 0; | | 684 | cur->td.td_nexttd = 0; |
685 | cur->td.td_be = ~0; | | 685 | cur->td.td_be = ~0; |
686 | cur->nexttd = NULL; | | 686 | cur->nexttd = NULL; |
687 | cur->len = 0; | | 687 | cur->len = 0; |
688 | cur->flags = 0; | | 688 | cur->flags = 0; |
689 | cur->xfer = xfer; | | 689 | cur->xfer = xfer; |
690 | ohci_hash_add_td(sc, cur); | | 690 | ohci_hash_add_td(sc, cur); |
691 | | | 691 | |
692 | DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0); | | 692 | DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0); |
693 | } | | 693 | } |
694 | | | 694 | |
695 | /* Last TD gets usb_syncmem'ed by caller */ | | 695 | /* Last TD gets usb_syncmem'ed by caller */ |
696 | *ep = cur; | | 696 | *ep = cur; |
697 | } | | 697 | } |
698 | | | 698 | |
699 | ohci_soft_itd_t * | | 699 | ohci_soft_itd_t * |
700 | ohci_alloc_sitd(ohci_softc_t *sc) | | 700 | ohci_alloc_sitd(ohci_softc_t *sc) |
701 | { | | 701 | { |
702 | ohci_soft_itd_t *sitd; | | 702 | ohci_soft_itd_t *sitd; |
703 | usbd_status err; | | 703 | usbd_status err; |
704 | int i, offs; | | 704 | int i, offs; |
705 | usb_dma_t dma; | | 705 | usb_dma_t dma; |
706 | | | 706 | |
707 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 707 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
708 | | | 708 | |
709 | mutex_enter(&sc->sc_lock); | | 709 | mutex_enter(&sc->sc_lock); |
710 | if (sc->sc_freeitds == NULL) { | | 710 | if (sc->sc_freeitds == NULL) { |
711 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); | | 711 | DPRINTFN(2, "allocating chunk", 0, 0, 0, 0); |
712 | mutex_exit(&sc->sc_lock); | | 712 | mutex_exit(&sc->sc_lock); |
713 | | | 713 | |
714 | err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK, | | 714 | err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK, |
715 | OHCI_ITD_ALIGN, &dma); | | 715 | OHCI_ITD_ALIGN, &dma); |
716 | if (err) | | 716 | if (err) |
717 | return NULL; | | 717 | return NULL; |
718 | mutex_enter(&sc->sc_lock); | | 718 | mutex_enter(&sc->sc_lock); |
719 | for (i = 0; i < OHCI_SITD_CHUNK; i++) { | | 719 | for (i = 0; i < OHCI_SITD_CHUNK; i++) { |
720 | offs = i * OHCI_SITD_SIZE; | | 720 | offs = i * OHCI_SITD_SIZE; |
721 | sitd = KERNADDR(&dma, offs); | | 721 | sitd = KERNADDR(&dma, offs); |
722 | sitd->physaddr = DMAADDR(&dma, offs); | | 722 | sitd->physaddr = DMAADDR(&dma, offs); |
723 | sitd->dma = dma; | | 723 | sitd->dma = dma; |
724 | sitd->offs = offs; | | 724 | sitd->offs = offs; |
725 | sitd->nextitd = sc->sc_freeitds; | | 725 | sitd->nextitd = sc->sc_freeitds; |
726 | sc->sc_freeitds = sitd; | | 726 | sc->sc_freeitds = sitd; |
727 | } | | 727 | } |
728 | } | | 728 | } |
729 | | | 729 | |
730 | sitd = sc->sc_freeitds; | | 730 | sitd = sc->sc_freeitds; |
731 | sc->sc_freeitds = sitd->nextitd; | | 731 | sc->sc_freeitds = sitd->nextitd; |
732 | mutex_exit(&sc->sc_lock); | | 732 | mutex_exit(&sc->sc_lock); |
733 | | | 733 | |
734 | memset(&sitd->itd, 0, sizeof(ohci_itd_t)); | | 734 | memset(&sitd->itd, 0, sizeof(ohci_itd_t)); |
735 | sitd->nextitd = NULL; | | 735 | sitd->nextitd = NULL; |
736 | sitd->xfer = NULL; | | 736 | sitd->xfer = NULL; |
737 | | | 737 | |
738 | #ifdef DIAGNOSTIC | | 738 | #ifdef DIAGNOSTIC |
739 | sitd->isdone = true; | | 739 | sitd->isdone = true; |
740 | #endif | | 740 | #endif |
741 | | | 741 | |
742 | return sitd; | | 742 | return sitd; |
743 | } | | 743 | } |
744 | | | 744 | |
745 | Static void | | 745 | Static void |
746 | ohci_free_sitd_locked(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | | 746 | ohci_free_sitd_locked(ohci_softc_t *sc, ohci_soft_itd_t *sitd) |
747 | { | | 747 | { |
748 | | | 748 | |
749 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 749 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
750 | DPRINTFN(10, "sitd=%#jx", (uintptr_t)sitd, 0, 0, 0); | | 750 | DPRINTFN(10, "sitd=%#jx", (uintptr_t)sitd, 0, 0, 0); |
751 | | | 751 | |
752 | KASSERT(sitd->isdone); | | 752 | KASSERT(sitd->isdone); |
753 | #ifdef DIAGNOSTIC | | 753 | #ifdef DIAGNOSTIC |
754 | /* Warn double free */ | | 754 | /* Warn double free */ |
755 | sitd->isdone = false; | | 755 | sitd->isdone = false; |
756 | #endif | | 756 | #endif |
757 | | | 757 | |
758 | sitd->nextitd = sc->sc_freeitds; | | 758 | sitd->nextitd = sc->sc_freeitds; |
759 | sc->sc_freeitds = sitd; | | 759 | sc->sc_freeitds = sitd; |
760 | } | | 760 | } |
761 | | | 761 | |
762 | void | | 762 | void |
763 | ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) | | 763 | ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd) |
764 | { | | 764 | { |
765 | | | 765 | |
766 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 766 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
767 | | | 767 | |
768 | mutex_enter(&sc->sc_lock); | | 768 | mutex_enter(&sc->sc_lock); |
769 | ohci_free_sitd_locked(sc, sitd); | | 769 | ohci_free_sitd_locked(sc, sitd); |
770 | mutex_exit(&sc->sc_lock); | | 770 | mutex_exit(&sc->sc_lock); |
771 | } | | 771 | } |
772 | | | 772 | |
773 | int | | 773 | int |
774 | ohci_init(ohci_softc_t *sc) | | 774 | ohci_init(ohci_softc_t *sc) |
775 | { | | 775 | { |
776 | ohci_soft_ed_t *sed, *psed; | | 776 | ohci_soft_ed_t *sed, *psed; |
777 | usbd_status err; | | 777 | usbd_status err; |
778 | int i; | | 778 | int i; |
779 | uint32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca /*, descb */; | | 779 | uint32_t s, ctl, rwc, ival, hcr, fm, per, rev, desca /*, descb */; |
780 | | | 780 | |
781 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 781 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
782 | | | 782 | |
783 | aprint_normal_dev(sc->sc_dev, ""); | | 783 | aprint_normal_dev(sc->sc_dev, ""); |
784 | | | 784 | |
785 | sc->sc_hcca = NULL; | | 785 | sc->sc_hcca = NULL; |
786 | callout_init(&sc->sc_tmo_rhsc, CALLOUT_MPSAFE); | | 786 | callout_init(&sc->sc_tmo_rhsc, CALLOUT_MPSAFE); |
787 | | | 787 | |
788 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | | 788 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); |
789 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); | | 789 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB); |
790 | | | 790 | |
791 | sc->sc_rhsc_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE, | | 791 | sc->sc_rhsc_si = softint_establish(SOFTINT_USB | SOFTINT_MPSAFE, |
792 | ohci_rhsc_softint, sc); | | 792 | ohci_rhsc_softint, sc); |
793 | | | 793 | |
794 | for (i = 0; i < OHCI_HASH_SIZE; i++) | | 794 | for (i = 0; i < OHCI_HASH_SIZE; i++) |
795 | LIST_INIT(&sc->sc_hash_tds[i]); | | 795 | LIST_INIT(&sc->sc_hash_tds[i]); |
796 | for (i = 0; i < OHCI_HASH_SIZE; i++) | | 796 | for (i = 0; i < OHCI_HASH_SIZE; i++) |
797 | LIST_INIT(&sc->sc_hash_itds[i]); | | 797 | LIST_INIT(&sc->sc_hash_itds[i]); |
798 | | | 798 | |
799 | sc->sc_xferpool = pool_cache_init(sizeof(struct ohci_xfer), 0, 0, 0, | | 799 | sc->sc_xferpool = pool_cache_init(sizeof(struct ohci_xfer), 0, 0, 0, |
800 | "ohcixfer", NULL, IPL_USB, NULL, NULL, NULL); | | 800 | "ohcixfer", NULL, IPL_USB, NULL, NULL, NULL); |
801 | | | 801 | |
802 | rev = OREAD4(sc, OHCI_REVISION); | | 802 | rev = OREAD4(sc, OHCI_REVISION); |
803 | aprint_normal("OHCI version %d.%d%s\n", | | 803 | aprint_normal("OHCI version %d.%d%s\n", |
804 | OHCI_REV_HI(rev), OHCI_REV_LO(rev), | | 804 | OHCI_REV_HI(rev), OHCI_REV_LO(rev), |
805 | OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); | | 805 | OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); |
806 | | | 806 | |
807 | if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { | | 807 | if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { |
808 | aprint_error_dev(sc->sc_dev, "unsupported OHCI revision\n"); | | 808 | aprint_error_dev(sc->sc_dev, "unsupported OHCI revision\n"); |
809 | sc->sc_bus.ub_revision = USBREV_UNKNOWN; | | 809 | sc->sc_bus.ub_revision = USBREV_UNKNOWN; |
810 | return -1; | | 810 | return -1; |
811 | } | | 811 | } |
812 | sc->sc_bus.ub_revision = USBREV_1_0; | | 812 | sc->sc_bus.ub_revision = USBREV_1_0; |
813 | sc->sc_bus.ub_usedma = true; | | 813 | sc->sc_bus.ub_usedma = true; |
814 | | | 814 | |
815 | /* XXX determine alignment by R/W */ | | 815 | /* XXX determine alignment by R/W */ |
816 | /* Allocate the HCCA area. */ | | 816 | /* Allocate the HCCA area. */ |
817 | err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, | | 817 | err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE, |
818 | OHCI_HCCA_ALIGN, &sc->sc_hccadma); | | 818 | OHCI_HCCA_ALIGN, &sc->sc_hccadma); |
819 | if (err) { | | 819 | if (err) { |
820 | sc->sc_hcca = NULL; | | 820 | sc->sc_hcca = NULL; |
821 | return err; | | 821 | return err; |
822 | } | | 822 | } |
823 | sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0); | | 823 | sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0); |
824 | memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE); | | 824 | memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE); |
825 | | | 825 | |
826 | sc->sc_eintrs = OHCI_NORMAL_INTRS; | | 826 | sc->sc_eintrs = OHCI_NORMAL_INTRS; |
827 | | | 827 | |
828 | /* Allocate dummy ED that starts the control list. */ | | 828 | /* Allocate dummy ED that starts the control list. */ |
829 | sc->sc_ctrl_head = ohci_alloc_sed(sc); | | 829 | sc->sc_ctrl_head = ohci_alloc_sed(sc); |
830 | if (sc->sc_ctrl_head == NULL) { | | 830 | if (sc->sc_ctrl_head == NULL) { |
831 | err = ENOMEM; | | 831 | err = ENOMEM; |
832 | goto bad1; | | 832 | goto bad1; |
833 | } | | 833 | } |
834 | sc->sc_ctrl_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 834 | sc->sc_ctrl_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
835 | | | 835 | |
836 | /* Allocate dummy ED that starts the bulk list. */ | | 836 | /* Allocate dummy ED that starts the bulk list. */ |
837 | sc->sc_bulk_head = ohci_alloc_sed(sc); | | 837 | sc->sc_bulk_head = ohci_alloc_sed(sc); |
838 | if (sc->sc_bulk_head == NULL) { | | 838 | if (sc->sc_bulk_head == NULL) { |
839 | err = ENOMEM; | | 839 | err = ENOMEM; |
840 | goto bad2; | | 840 | goto bad2; |
841 | } | | 841 | } |
842 | sc->sc_bulk_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 842 | sc->sc_bulk_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
843 | usb_syncmem(&sc->sc_bulk_head->dma, sc->sc_bulk_head->offs, | | 843 | usb_syncmem(&sc->sc_bulk_head->dma, sc->sc_bulk_head->offs, |
844 | sizeof(sc->sc_bulk_head->ed), | | 844 | sizeof(sc->sc_bulk_head->ed), |
845 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 845 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
846 | | | 846 | |
847 | /* Allocate dummy ED that starts the isochronous list. */ | | 847 | /* Allocate dummy ED that starts the isochronous list. */ |
848 | sc->sc_isoc_head = ohci_alloc_sed(sc); | | 848 | sc->sc_isoc_head = ohci_alloc_sed(sc); |
849 | if (sc->sc_isoc_head == NULL) { | | 849 | if (sc->sc_isoc_head == NULL) { |
850 | err = ENOMEM; | | 850 | err = ENOMEM; |
851 | goto bad3; | | 851 | goto bad3; |
852 | } | | 852 | } |
853 | sc->sc_isoc_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 853 | sc->sc_isoc_head->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
854 | usb_syncmem(&sc->sc_isoc_head->dma, sc->sc_isoc_head->offs, | | 854 | usb_syncmem(&sc->sc_isoc_head->dma, sc->sc_isoc_head->offs, |
855 | sizeof(sc->sc_isoc_head->ed), | | 855 | sizeof(sc->sc_isoc_head->ed), |
856 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 856 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
857 | | | 857 | |
858 | /* Allocate all the dummy EDs that make up the interrupt tree. */ | | 858 | /* Allocate all the dummy EDs that make up the interrupt tree. */ |
859 | for (i = 0; i < OHCI_NO_EDS; i++) { | | 859 | for (i = 0; i < OHCI_NO_EDS; i++) { |
860 | sed = ohci_alloc_sed(sc); | | 860 | sed = ohci_alloc_sed(sc); |
861 | if (sed == NULL) { | | 861 | if (sed == NULL) { |
862 | while (--i >= 0) | | 862 | while (--i >= 0) |
863 | ohci_free_sed(sc, sc->sc_eds[i]); | | 863 | ohci_free_sed(sc, sc->sc_eds[i]); |
864 | err = ENOMEM; | | 864 | err = ENOMEM; |
865 | goto bad4; | | 865 | goto bad4; |
866 | } | | 866 | } |
867 | /* All ED fields are set to 0. */ | | 867 | /* All ED fields are set to 0. */ |
868 | sc->sc_eds[i] = sed; | | 868 | sc->sc_eds[i] = sed; |
869 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 869 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
870 | if (i != 0) | | 870 | if (i != 0) |
871 | psed = sc->sc_eds[(i-1) / 2]; | | 871 | psed = sc->sc_eds[(i-1) / 2]; |
872 | else | | 872 | else |
873 | psed= sc->sc_isoc_head; | | 873 | psed= sc->sc_isoc_head; |
874 | sed->next = psed; | | 874 | sed->next = psed; |
875 | sed->ed.ed_nexted = HTOO32(psed->physaddr); | | 875 | sed->ed.ed_nexted = HTOO32(psed->physaddr); |
876 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 876 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
877 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 877 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
878 | } | | 878 | } |
879 | /* | | 879 | /* |
880 | * Fill HCCA interrupt table. The bit reversal is to get | | 880 | * Fill HCCA interrupt table. The bit reversal is to get |
881 | * the tree set up properly to spread the interrupts. | | 881 | * the tree set up properly to spread the interrupts. |
882 | */ | | 882 | */ |
883 | for (i = 0; i < OHCI_NO_INTRS; i++) | | 883 | for (i = 0; i < OHCI_NO_INTRS; i++) |
884 | sc->sc_hcca->hcca_interrupt_table[revbits[i]] = | | 884 | sc->sc_hcca->hcca_interrupt_table[revbits[i]] = |
885 | HTOO32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); | | 885 | HTOO32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); |
886 | usb_syncmem(&sc->sc_hccadma, 0, OHCI_HCCA_SIZE, | | 886 | usb_syncmem(&sc->sc_hccadma, 0, OHCI_HCCA_SIZE, |
887 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 887 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
888 | | | 888 | |
889 | #ifdef OHCI_DEBUG | | 889 | #ifdef OHCI_DEBUG |
890 | DPRINTFN(15, "--- dump start ---", 0, 0, 0 ,0); | | 890 | DPRINTFN(15, "--- dump start ---", 0, 0, 0 ,0); |
891 | if (ohcidebug >= 15) { | | 891 | if (ohcidebug >= 15) { |
892 | for (i = 0; i < OHCI_NO_EDS; i++) { | | 892 | for (i = 0; i < OHCI_NO_EDS; i++) { |
893 | DPRINTFN(15, "ed#%jd ", i, 0, 0, 0); | | 893 | DPRINTFN(15, "ed#%jd ", i, 0, 0, 0); |
894 | ohci_dump_ed(sc, sc->sc_eds[i]); | | 894 | ohci_dump_ed(sc, sc->sc_eds[i]); |
895 | } | | 895 | } |
896 | DPRINTFN(15, "iso", 0, 0, 0 ,0); | | 896 | DPRINTFN(15, "iso", 0, 0, 0 ,0); |
897 | ohci_dump_ed(sc, sc->sc_isoc_head); | | 897 | ohci_dump_ed(sc, sc->sc_isoc_head); |
898 | } | | 898 | } |
899 | DPRINTFN(15, "--- dump end ---", 0, 0, 0 ,0); | | 899 | DPRINTFN(15, "--- dump end ---", 0, 0, 0 ,0); |
900 | #endif | | 900 | #endif |
901 | | | 901 | |
902 | /* Preserve values programmed by SMM/BIOS but lost over reset. */ | | 902 | /* Preserve values programmed by SMM/BIOS but lost over reset. */ |
903 | ctl = OREAD4(sc, OHCI_CONTROL); | | 903 | ctl = OREAD4(sc, OHCI_CONTROL); |
904 | rwc = ctl & OHCI_RWC; | | 904 | rwc = ctl & OHCI_RWC; |
905 | fm = OREAD4(sc, OHCI_FM_INTERVAL); | | 905 | fm = OREAD4(sc, OHCI_FM_INTERVAL); |
906 | desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); | | 906 | desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); |
907 | /* descb = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); */ | | 907 | /* descb = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); */ |
908 | | | 908 | |
909 | /* Determine in what context we are running. */ | | 909 | /* Determine in what context we are running. */ |
910 | if (ctl & OHCI_IR) { | | 910 | if (ctl & OHCI_IR) { |
911 | /* SMM active, request change */ | | 911 | /* SMM active, request change */ |
912 | DPRINTF("SMM active, request owner change", 0, 0, 0, 0); | | 912 | DPRINTF("SMM active, request owner change", 0, 0, 0, 0); |
913 | if ((sc->sc_intre & (OHCI_OC | OHCI_MIE)) == | | 913 | if ((sc->sc_intre & (OHCI_OC | OHCI_MIE)) == |
914 | (OHCI_OC | OHCI_MIE)) | | 914 | (OHCI_OC | OHCI_MIE)) |
915 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_MIE); | | 915 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_MIE); |
916 | s = OREAD4(sc, OHCI_COMMAND_STATUS); | | 916 | s = OREAD4(sc, OHCI_COMMAND_STATUS); |
917 | OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR); | | 917 | OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR); |
918 | for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { | | 918 | for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { |
919 | usb_delay_ms(&sc->sc_bus, 1); | | 919 | usb_delay_ms(&sc->sc_bus, 1); |
920 | ctl = OREAD4(sc, OHCI_CONTROL); | | 920 | ctl = OREAD4(sc, OHCI_CONTROL); |
921 | } | | 921 | } |
922 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_MIE); | | 922 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_MIE); |
923 | if ((ctl & OHCI_IR) == 0) { | | 923 | if ((ctl & OHCI_IR) == 0) { |
924 | aprint_error_dev(sc->sc_dev, | | 924 | aprint_error_dev(sc->sc_dev, |
925 | "SMM does not respond, resetting\n"); | | 925 | "SMM does not respond, resetting\n"); |
926 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); | | 926 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); |
927 | goto reset; | | 927 | goto reset; |
928 | } | | 928 | } |
929 | #if 0 | | 929 | #if 0 |
930 | /* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */ | | 930 | /* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */ |
931 | } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { | | 931 | } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { |
932 | /* BIOS started controller. */ | | 932 | /* BIOS started controller. */ |
933 | DPRINTF("BIOS active", 0, 0, 0, 0); | | 933 | DPRINTF("BIOS active", 0, 0, 0, 0); |
934 | if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) { | | 934 | if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) { |
935 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL | rwc); | | 935 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL | rwc); |
936 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); | | 936 | usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY); |
937 | } | | 937 | } |
938 | #endif | | 938 | #endif |
939 | } else { | | 939 | } else { |
940 | DPRINTF("cold started", 0 ,0 ,0 ,0); | | 940 | DPRINTF("cold started", 0 ,0 ,0 ,0); |
941 | reset: | | 941 | reset: |
942 | /* Controller was cold started. */ | | 942 | /* Controller was cold started. */ |
943 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); | | 943 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); |
944 | } | | 944 | } |
945 | | | 945 | |
946 | /* | | 946 | /* |
947 | * This reset should not be necessary according to the OHCI spec, but | | 947 | * This reset should not be necessary according to the OHCI spec, but |
948 | * without it some controllers do not start. | | 948 | * without it some controllers do not start. |
949 | */ | | 949 | */ |
950 | DPRINTF("sc %#jx: resetting", (uintptr_t)sc, 0, 0, 0); | | 950 | DPRINTF("sc %#jx: resetting", (uintptr_t)sc, 0, 0, 0); |
951 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); | | 951 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc); |
952 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); | | 952 | usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); |
953 | | | 953 | |
954 | /* We now own the host controller and the bus has been reset. */ | | 954 | /* We now own the host controller and the bus has been reset. */ |
955 | | | 955 | |
956 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ | | 956 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ |
957 | /* Nominal time for a reset is 10 us. */ | | 957 | /* Nominal time for a reset is 10 us. */ |
958 | for (i = 0; i < 10; i++) { | | 958 | for (i = 0; i < 10; i++) { |
959 | delay(10); | | 959 | delay(10); |
960 | hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; | | 960 | hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; |
961 | if (!hcr) | | 961 | if (!hcr) |
962 | break; | | 962 | break; |
963 | } | | 963 | } |
964 | if (hcr) { | | 964 | if (hcr) { |
965 | aprint_error_dev(sc->sc_dev, "reset timeout\n"); | | 965 | aprint_error_dev(sc->sc_dev, "reset timeout\n"); |
966 | err = EIO; | | 966 | err = EIO; |
967 | goto bad5; | | 967 | goto bad5; |
968 | } | | 968 | } |
969 | #ifdef OHCI_DEBUG | | 969 | #ifdef OHCI_DEBUG |
970 | if (ohcidebug >= 15) | | 970 | if (ohcidebug >= 15) |
971 | ohci_dumpregs(sc); | | 971 | ohci_dumpregs(sc); |
972 | #endif | | 972 | #endif |
973 | | | 973 | |
974 | /* The controller is now in SUSPEND state, we have 2ms to finish. */ | | 974 | /* The controller is now in SUSPEND state, we have 2ms to finish. */ |
975 | | | 975 | |
976 | /* Set up HC registers. */ | | 976 | /* Set up HC registers. */ |
977 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); | | 977 | OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0)); |
978 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); | | 978 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); |
979 | OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); | | 979 | OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); |
980 | /* disable all interrupts and then switch on all desired interrupts */ | | 980 | /* disable all interrupts and then switch on all desired interrupts */ |
981 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); | | 981 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); |
982 | /* switch on desired functional features */ | | 982 | /* switch on desired functional features */ |
983 | ctl = OREAD4(sc, OHCI_CONTROL); | | 983 | ctl = OREAD4(sc, OHCI_CONTROL); |
984 | ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); | | 984 | ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); |
985 | ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | | | 985 | ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | |
986 | OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL | rwc; | | 986 | OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL | rwc; |
987 | /* And finally start it! */ | | 987 | /* And finally start it! */ |
988 | OWRITE4(sc, OHCI_CONTROL, ctl); | | 988 | OWRITE4(sc, OHCI_CONTROL, ctl); |
989 | | | 989 | |
990 | /* | | 990 | /* |
991 | * The controller is now OPERATIONAL. Set a some final | | 991 | * The controller is now OPERATIONAL. Set a some final |
992 | * registers that should be set earlier, but that the | | 992 | * registers that should be set earlier, but that the |
993 | * controller ignores when in the SUSPEND state. | | 993 | * controller ignores when in the SUSPEND state. |
994 | */ | | 994 | */ |
995 | ival = OHCI_GET_IVAL(fm); | | 995 | ival = OHCI_GET_IVAL(fm); |
996 | fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; | | 996 | fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; |
997 | fm |= OHCI_FSMPS(ival) | ival; | | 997 | fm |= OHCI_FSMPS(ival) | ival; |
998 | OWRITE4(sc, OHCI_FM_INTERVAL, fm); | | 998 | OWRITE4(sc, OHCI_FM_INTERVAL, fm); |
999 | per = OHCI_PERIODIC(ival); /* 90% periodic */ | | 999 | per = OHCI_PERIODIC(ival); /* 90% periodic */ |
1000 | OWRITE4(sc, OHCI_PERIODIC_START, per); | | 1000 | OWRITE4(sc, OHCI_PERIODIC_START, per); |
1001 | | | 1001 | |
1002 | if (sc->sc_flags & OHCIF_SUPERIO) { | | 1002 | if (sc->sc_flags & OHCIF_SUPERIO) { |
1003 | /* no overcurrent protection */ | | 1003 | /* no overcurrent protection */ |
1004 | desca |= OHCI_NOCP; | | 1004 | desca |= OHCI_NOCP; |
1005 | /* | | 1005 | /* |
1006 | * Clear NoPowerSwitching and PowerOnToPowerGoodTime meaning | | 1006 | * Clear NoPowerSwitching and PowerOnToPowerGoodTime meaning |
1007 | * that | | 1007 | * that |
1008 | * - ports are always power switched | | 1008 | * - ports are always power switched |
1009 | * - don't wait for powered root hub port | | 1009 | * - don't wait for powered root hub port |
1010 | */ | | 1010 | */ |
1011 | desca &= ~(__SHIFTIN(0xff, OHCI_POTPGT_MASK) | OHCI_NPS); | | 1011 | desca &= ~(__SHIFTIN(0xff, OHCI_POTPGT_MASK) | OHCI_NPS); |
1012 | } | | 1012 | } |
1013 | | | 1013 | |
1014 | /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ | | 1014 | /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ |
1015 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); | | 1015 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); |
1016 | OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ | | 1016 | OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ |
1017 | usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY); | | 1017 | usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY); |
1018 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); | | 1018 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); |
1019 | | | 1019 | |
1020 | /* | | 1020 | /* |
1021 | * The AMD756 requires a delay before re-reading the register, | | 1021 | * The AMD756 requires a delay before re-reading the register, |
1022 | * otherwise it will occasionally report 0 ports. | | 1022 | * otherwise it will occasionally report 0 ports. |
1023 | */ | | 1023 | */ |
1024 | sc->sc_noport = 0; | | 1024 | sc->sc_noport = 0; |
1025 | for (i = 0; i < 10 && sc->sc_noport == 0; i++) { | | 1025 | for (i = 0; i < 10 && sc->sc_noport == 0; i++) { |
1026 | usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY); | | 1026 | usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY); |
1027 | sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); | | 1027 | sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); |
1028 | } | | 1028 | } |
1029 | | | 1029 | |
1030 | #ifdef OHCI_DEBUG | | 1030 | #ifdef OHCI_DEBUG |
1031 | if (ohcidebug >= 5) | | 1031 | if (ohcidebug >= 5) |
1032 | ohci_dumpregs(sc); | | 1032 | ohci_dumpregs(sc); |
1033 | #endif | | 1033 | #endif |
1034 | | | 1034 | |
1035 | /* Set up the bus struct. */ | | 1035 | /* Set up the bus struct. */ |
1036 | sc->sc_bus.ub_methods = &ohci_bus_methods; | | 1036 | sc->sc_bus.ub_methods = &ohci_bus_methods; |
1037 | sc->sc_bus.ub_pipesize = sizeof(struct ohci_pipe); | | 1037 | sc->sc_bus.ub_pipesize = sizeof(struct ohci_pipe); |
1038 | | | 1038 | |
1039 | sc->sc_control = sc->sc_intre = 0; | | 1039 | sc->sc_control = sc->sc_intre = 0; |
1040 | | | 1040 | |
1041 | /* Finally, turn on interrupts. */ | | 1041 | /* Finally, turn on interrupts. */ |
1042 | DPRINTF("enabling %#jx", sc->sc_eintrs | OHCI_MIE, 0, 0, 0); | | 1042 | DPRINTF("enabling %#jx", sc->sc_eintrs | OHCI_MIE, 0, 0, 0); |
1043 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); | | 1043 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); |
| @@ -2516,1154 +2516,1153 @@ ohci_root_intr_start(struct usbd_xfer *x | | | @@ -2516,1154 +2516,1153 @@ ohci_root_intr_start(struct usbd_xfer *x |
2516 | | | 2516 | |
2517 | if (!polling) | | 2517 | if (!polling) |
2518 | mutex_enter(&sc->sc_lock); | | 2518 | mutex_enter(&sc->sc_lock); |
2519 | KASSERT(sc->sc_intrxfer == NULL); | | 2519 | KASSERT(sc->sc_intrxfer == NULL); |
2520 | sc->sc_intrxfer = xfer; | | 2520 | sc->sc_intrxfer = xfer; |
2521 | xfer->ux_status = USBD_IN_PROGRESS; | | 2521 | xfer->ux_status = USBD_IN_PROGRESS; |
2522 | if (!polling) | | 2522 | if (!polling) |
2523 | mutex_exit(&sc->sc_lock); | | 2523 | mutex_exit(&sc->sc_lock); |
2524 | | | 2524 | |
2525 | return USBD_IN_PROGRESS; | | 2525 | return USBD_IN_PROGRESS; |
2526 | } | | 2526 | } |
2527 | | | 2527 | |
2528 | /* Abort a root interrupt request. */ | | 2528 | /* Abort a root interrupt request. */ |
2529 | Static void | | 2529 | Static void |
2530 | ohci_root_intr_abort(struct usbd_xfer *xfer) | | 2530 | ohci_root_intr_abort(struct usbd_xfer *xfer) |
2531 | { | | 2531 | { |
2532 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2532 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2533 | | | 2533 | |
2534 | KASSERT(mutex_owned(&sc->sc_lock)); | | 2534 | KASSERT(mutex_owned(&sc->sc_lock)); |
2535 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); | | 2535 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); |
2536 | | | 2536 | |
2537 | /* If xfer has already completed, nothing to do here. */ | | 2537 | /* If xfer has already completed, nothing to do here. */ |
2538 | if (sc->sc_intrxfer == NULL) | | 2538 | if (sc->sc_intrxfer == NULL) |
2539 | return; | | 2539 | return; |
2540 | | | 2540 | |
2541 | /* | | 2541 | /* |
2542 | * Otherwise, sc->sc_intrxfer had better be this transfer. | | 2542 | * Otherwise, sc->sc_intrxfer had better be this transfer. |
2543 | * Cancel it. | | 2543 | * Cancel it. |
2544 | */ | | 2544 | */ |
2545 | KASSERT(sc->sc_intrxfer == xfer); | | 2545 | KASSERT(sc->sc_intrxfer == xfer); |
2546 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); | | 2546 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); |
2547 | xfer->ux_status = USBD_CANCELLED; | | 2547 | xfer->ux_status = USBD_CANCELLED; |
2548 | usb_transfer_complete(xfer); | | 2548 | usb_transfer_complete(xfer); |
2549 | } | | 2549 | } |
2550 | | | 2550 | |
2551 | /* Close the root pipe. */ | | 2551 | /* Close the root pipe. */ |
2552 | Static void | | 2552 | Static void |
2553 | ohci_root_intr_close(struct usbd_pipe *pipe) | | 2553 | ohci_root_intr_close(struct usbd_pipe *pipe) |
2554 | { | | 2554 | { |
2555 | ohci_softc_t *sc __diagused = OHCI_PIPE2SC(pipe); | | 2555 | ohci_softc_t *sc __diagused = OHCI_PIPE2SC(pipe); |
2556 | | | 2556 | |
2557 | KASSERT(mutex_owned(&sc->sc_lock)); | | 2557 | KASSERT(mutex_owned(&sc->sc_lock)); |
2558 | | | 2558 | |
2559 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2559 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2560 | | | 2560 | |
2561 | /* | | 2561 | /* |
2562 | * Caller must guarantee the xfer has completed first, by | | 2562 | * Caller must guarantee the xfer has completed first, by |
2563 | * closing the pipe only after normal completion or an abort. | | 2563 | * closing the pipe only after normal completion or an abort. |
2564 | */ | | 2564 | */ |
2565 | KASSERT(sc->sc_intrxfer == NULL); | | 2565 | KASSERT(sc->sc_intrxfer == NULL); |
2566 | } | | 2566 | } |
2567 | | | 2567 | |
2568 | /************************/ | | 2568 | /************************/ |
2569 | | | 2569 | |
2570 | int | | 2570 | int |
2571 | ohci_device_ctrl_init(struct usbd_xfer *xfer) | | 2571 | ohci_device_ctrl_init(struct usbd_xfer *xfer) |
2572 | { | | 2572 | { |
2573 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2573 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2574 | usb_device_request_t *req = &xfer->ux_request; | | 2574 | usb_device_request_t *req = &xfer->ux_request; |
2575 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2575 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2576 | ohci_soft_td_t *stat, *setup; | | 2576 | ohci_soft_td_t *stat, *setup; |
2577 | int isread = req->bmRequestType & UT_READ; | | 2577 | int isread = req->bmRequestType & UT_READ; |
2578 | int len = xfer->ux_bufsize; | | 2578 | int len = xfer->ux_bufsize; |
2579 | int err = ENOMEM; | | 2579 | int err = ENOMEM; |
2580 | | | 2580 | |
2581 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2581 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2582 | | | 2582 | |
2583 | setup = ohci_alloc_std(sc); | | 2583 | setup = ohci_alloc_std(sc); |
2584 | if (setup == NULL) { | | 2584 | if (setup == NULL) { |
2585 | goto bad1; | | 2585 | goto bad1; |
2586 | } | | 2586 | } |
2587 | stat = ohci_alloc_std(sc); | | 2587 | stat = ohci_alloc_std(sc); |
2588 | if (stat == NULL) { | | 2588 | if (stat == NULL) { |
2589 | goto bad2; | | 2589 | goto bad2; |
2590 | } | | 2590 | } |
2591 | | | 2591 | |
2592 | ox->ox_setup = setup; | | 2592 | ox->ox_setup = setup; |
2593 | ox->ox_stat = stat; | | 2593 | ox->ox_stat = stat; |
2594 | ox->ox_nstd = 0; | | 2594 | ox->ox_nstd = 0; |
2595 | | | 2595 | |
2596 | /* Set up data transaction */ | | 2596 | /* Set up data transaction */ |
2597 | if (len != 0) { | | 2597 | if (len != 0) { |
2598 | err = ohci_alloc_std_chain(sc, xfer, len, isread); | | 2598 | err = ohci_alloc_std_chain(sc, xfer, len, isread); |
2599 | if (err) { | | 2599 | if (err) { |
2600 | goto bad3; | | 2600 | goto bad3; |
2601 | } | | 2601 | } |
2602 | } | | 2602 | } |
2603 | return 0; | | 2603 | return 0; |
2604 | | | 2604 | |
2605 | bad3: | | 2605 | bad3: |
2606 | ohci_free_std(sc, stat); | | 2606 | ohci_free_std(sc, stat); |
2607 | bad2: | | 2607 | bad2: |
2608 | ohci_free_std(sc, setup); | | 2608 | ohci_free_std(sc, setup); |
2609 | bad1: | | 2609 | bad1: |
2610 | return err; | | 2610 | return err; |
2611 | } | | 2611 | } |
2612 | | | 2612 | |
2613 | void | | 2613 | void |
2614 | ohci_device_ctrl_fini(struct usbd_xfer *xfer) | | 2614 | ohci_device_ctrl_fini(struct usbd_xfer *xfer) |
2615 | { | | 2615 | { |
2616 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2616 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2617 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2617 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2618 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 2618 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
2619 | | | 2619 | |
2620 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2620 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2621 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); | | 2621 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); |
2622 | | | 2622 | |
2623 | mutex_enter(&sc->sc_lock); | | 2623 | mutex_enter(&sc->sc_lock); |
2624 | if (ox->ox_setup != opipe->tail.td) { | | 2624 | if (ox->ox_setup != opipe->tail.td) { |
2625 | ohci_free_std_locked(sc, ox->ox_setup); | | 2625 | ohci_free_std_locked(sc, ox->ox_setup); |
2626 | } | | 2626 | } |
2627 | for (size_t i = 0; i < ox->ox_nstd; i++) { | | 2627 | for (size_t i = 0; i < ox->ox_nstd; i++) { |
2628 | ohci_soft_td_t *std = ox->ox_stds[i]; | | 2628 | ohci_soft_td_t *std = ox->ox_stds[i]; |
2629 | if (std == NULL) | | 2629 | if (std == NULL) |
2630 | break; | | 2630 | break; |
2631 | ohci_free_std_locked(sc, std); | | 2631 | ohci_free_std_locked(sc, std); |
2632 | } | | 2632 | } |
2633 | ohci_free_std_locked(sc, ox->ox_stat); | | 2633 | ohci_free_std_locked(sc, ox->ox_stat); |
2634 | mutex_exit(&sc->sc_lock); | | 2634 | mutex_exit(&sc->sc_lock); |
2635 | | | 2635 | |
2636 | if (ox->ox_nstd) { | | 2636 | if (ox->ox_nstd) { |
2637 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; | | 2637 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; |
2638 | kmem_free(ox->ox_stds, sz); | | 2638 | kmem_free(ox->ox_stds, sz); |
2639 | } | | 2639 | } |
2640 | } | | 2640 | } |
2641 | | | 2641 | |
2642 | Static usbd_status | | 2642 | Static usbd_status |
2643 | ohci_device_ctrl_transfer(struct usbd_xfer *xfer) | | 2643 | ohci_device_ctrl_transfer(struct usbd_xfer *xfer) |
2644 | { | | 2644 | { |
2645 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2645 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2646 | usbd_status err; | | 2646 | usbd_status err; |
2647 | | | 2647 | |
2648 | /* Insert last in queue. */ | | 2648 | /* Insert last in queue. */ |
2649 | mutex_enter(&sc->sc_lock); | | 2649 | mutex_enter(&sc->sc_lock); |
2650 | err = usb_insert_transfer(xfer); | | 2650 | err = usb_insert_transfer(xfer); |
2651 | mutex_exit(&sc->sc_lock); | | 2651 | mutex_exit(&sc->sc_lock); |
2652 | if (err) | | 2652 | if (err) |
2653 | return err; | | 2653 | return err; |
2654 | | | 2654 | |
2655 | /* Pipe isn't running, start first */ | | 2655 | /* Pipe isn't running, start first */ |
2656 | return ohci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 2656 | return ohci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
2657 | } | | 2657 | } |
2658 | | | 2658 | |
2659 | Static usbd_status | | 2659 | Static usbd_status |
2660 | ohci_device_ctrl_start(struct usbd_xfer *xfer) | | 2660 | ohci_device_ctrl_start(struct usbd_xfer *xfer) |
2661 | { | | 2661 | { |
2662 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2662 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2663 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2663 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2664 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 2664 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
2665 | usb_device_request_t *req = &xfer->ux_request; | | 2665 | usb_device_request_t *req = &xfer->ux_request; |
2666 | struct usbd_device *dev __diagused = opipe->pipe.up_dev; | | 2666 | struct usbd_device *dev __diagused = opipe->pipe.up_dev; |
2667 | ohci_soft_td_t *setup, *stat, *next, *tail; | | 2667 | ohci_soft_td_t *setup, *stat, *next, *tail; |
2668 | ohci_soft_ed_t *sed; | | 2668 | ohci_soft_ed_t *sed; |
2669 | int isread; | | 2669 | int isread; |
2670 | int len; | | 2670 | int len; |
2671 | const bool polling = sc->sc_bus.ub_usepolling; | | 2671 | const bool polling = sc->sc_bus.ub_usepolling; |
2672 | | | 2672 | |
2673 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2673 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2674 | | | 2674 | |
2675 | if (sc->sc_dying) | | 2675 | if (sc->sc_dying) |
2676 | return USBD_IOERROR; | | 2676 | return USBD_IOERROR; |
2677 | | | 2677 | |
2678 | KASSERT(xfer->ux_rqflags & URQ_REQUEST); | | 2678 | KASSERT(xfer->ux_rqflags & URQ_REQUEST); |
2679 | | | 2679 | |
2680 | isread = req->bmRequestType & UT_READ; | | 2680 | isread = req->bmRequestType & UT_READ; |
2681 | len = UGETW(req->wLength); | | 2681 | len = UGETW(req->wLength); |
2682 | | | 2682 | |
2683 | DPRINTF("xfer=%#jx len=%jd, addr=%jd, endpt=%jd", (uintptr_t)xfer, len, | | 2683 | DPRINTF("xfer=%#jx len=%jd, addr=%jd, endpt=%jd", (uintptr_t)xfer, len, |
2684 | dev->ud_addr, opipe->pipe.up_endpoint->ue_edesc->bEndpointAddress); | | 2684 | dev->ud_addr, opipe->pipe.up_endpoint->ue_edesc->bEndpointAddress); |
2685 | DPRINTF("type=0x%02jx, request=0x%02jx, wValue=0x%04jx, wIndex=0x%04jx", | | 2685 | DPRINTF("type=0x%02jx, request=0x%02jx, wValue=0x%04jx, wIndex=0x%04jx", |
2686 | req->bmRequestType, req->bRequest, UGETW(req->wValue), | | 2686 | req->bmRequestType, req->bRequest, UGETW(req->wValue), |
2687 | UGETW(req->wIndex)); | | 2687 | UGETW(req->wIndex)); |
2688 | | | 2688 | |
2689 | /* Need to take lock here for pipe->tail.td */ | | 2689 | /* Need to take lock here for pipe->tail.td */ |
2690 | if (!polling) | | 2690 | if (!polling) |
2691 | mutex_enter(&sc->sc_lock); | | 2691 | mutex_enter(&sc->sc_lock); |
2692 | | | 2692 | |
2693 | /* | | 2693 | /* |
2694 | * Use the pipe "tail" TD as our first and loan our first TD to the | | 2694 | * Use the pipe "tail" TD as our first and loan our first TD to the |
2695 | * next transfer | | 2695 | * next transfer |
2696 | */ | | 2696 | */ |
2697 | setup = opipe->tail.td; | | 2697 | setup = opipe->tail.td; |
2698 | opipe->tail.td = ox->ox_setup; | | 2698 | opipe->tail.td = ox->ox_setup; |
2699 | ox->ox_setup = setup; | | 2699 | ox->ox_setup = setup; |
2700 | | | 2700 | |
2701 | stat = ox->ox_stat; | | 2701 | stat = ox->ox_stat; |
2702 | | | 2702 | |
2703 | /* point at sentinel */ | | 2703 | /* point at sentinel */ |
2704 | tail = opipe->tail.td; | | 2704 | tail = opipe->tail.td; |
2705 | sed = opipe->sed; | | 2705 | sed = opipe->sed; |
2706 | | | 2706 | |
2707 | KASSERTMSG(OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)) == dev->ud_addr, | | 2707 | KASSERTMSG(OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)) == dev->ud_addr, |
2708 | "address ED %d pipe %d\n", | | 2708 | "address ED %d pipe %d\n", |
2709 | OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)), dev->ud_addr); | | 2709 | OHCI_ED_GET_FA(O32TOH(sed->ed.ed_flags)), dev->ud_addr); |
2710 | KASSERTMSG(OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)) == | | 2710 | KASSERTMSG(OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)) == |
2711 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize), | | 2711 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize), |
2712 | "MPL ED %d pipe %d\n", | | 2712 | "MPL ED %d pipe %d\n", |
2713 | OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)), | | 2713 | OHCI_ED_GET_MAXP(O32TOH(sed->ed.ed_flags)), |
2714 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize)); | | 2714 | UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize)); |
2715 | | | 2715 | |
2716 | /* next will point to data if len != 0 */ | | 2716 | /* next will point to data if len != 0 */ |
2717 | next = stat; | | 2717 | next = stat; |
2718 | | | 2718 | |
2719 | /* Set up data transaction */ | | 2719 | /* Set up data transaction */ |
2720 | if (len != 0) { | | 2720 | if (len != 0) { |
2721 | ohci_soft_td_t *std; | | 2721 | ohci_soft_td_t *std; |
2722 | ohci_soft_td_t *end; | | 2722 | ohci_soft_td_t *end; |
2723 | | | 2723 | |
2724 | next = ox->ox_stds[0]; | | 2724 | next = ox->ox_stds[0]; |
2725 | ohci_reset_std_chain(sc, xfer, len, isread, next, &end); | | 2725 | ohci_reset_std_chain(sc, xfer, len, isread, next, &end); |
2726 | | | 2726 | |
2727 | end->td.td_nexttd = HTOO32(stat->physaddr); | | 2727 | end->td.td_nexttd = HTOO32(stat->physaddr); |
2728 | end->nexttd = stat; | | 2728 | end->nexttd = stat; |
2729 | | | 2729 | |
2730 | usb_syncmem(&end->dma, end->offs, sizeof(end->td), | | 2730 | usb_syncmem(&end->dma, end->offs, sizeof(end->td), |
2731 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2731 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2732 | | | 2732 | |
2733 | usb_syncmem(&xfer->ux_dmabuf, 0, len, | | 2733 | usb_syncmem(&xfer->ux_dmabuf, 0, len, |
2734 | isread ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | | 2734 | isread ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); |
2735 | std = ox->ox_stds[0]; | | 2735 | std = ox->ox_stds[0]; |
2736 | /* Start toggle at 1 and then use the carried toggle. */ | | 2736 | /* Start toggle at 1 and then use the carried toggle. */ |
2737 | std->td.td_flags &= HTOO32(~OHCI_TD_TOGGLE_MASK); | | 2737 | std->td.td_flags &= HTOO32(~OHCI_TD_TOGGLE_MASK); |
2738 | std->td.td_flags |= HTOO32(OHCI_TD_TOGGLE_1); | | 2738 | std->td.td_flags |= HTOO32(OHCI_TD_TOGGLE_1); |
2739 | usb_syncmem(&std->dma, | | 2739 | usb_syncmem(&std->dma, |
2740 | std->offs + offsetof(ohci_td_t, td_flags), | | 2740 | std->offs + offsetof(ohci_td_t, td_flags), |
2741 | sizeof(std->td.td_flags), | | 2741 | sizeof(std->td.td_flags), |
2742 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2742 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2743 | } | | 2743 | } |
2744 | | | 2744 | |
2745 | DPRINTFN(8, "setup %#jx data %#jx stat %#jx tail %#jx", | | 2745 | DPRINTFN(8, "setup %#jx data %#jx stat %#jx tail %#jx", |
2746 | (uintptr_t)setup, | | 2746 | (uintptr_t)setup, |
2747 | (uintptr_t)(len != 0 ? ox->ox_stds[0] : NULL), (uintptr_t)stat, | | 2747 | (uintptr_t)(len != 0 ? ox->ox_stds[0] : NULL), (uintptr_t)stat, |
2748 | (uintptr_t)tail); | | 2748 | (uintptr_t)tail); |
2749 | KASSERT(opipe->tail.td == tail); | | 2749 | KASSERT(opipe->tail.td == tail); |
2750 | | | 2750 | |
2751 | memcpy(KERNADDR(&opipe->ctrl.reqdma, 0), req, sizeof(*req)); | | 2751 | memcpy(KERNADDR(&opipe->ctrl.reqdma, 0), req, sizeof(*req)); |
2752 | usb_syncmem(&opipe->ctrl.reqdma, 0, sizeof(*req), BUS_DMASYNC_PREWRITE); | | 2752 | usb_syncmem(&opipe->ctrl.reqdma, 0, sizeof(*req), BUS_DMASYNC_PREWRITE); |
2753 | | | 2753 | |
2754 | setup->td.td_flags = HTOO32(OHCI_TD_SETUP | OHCI_TD_NOCC | | | 2754 | setup->td.td_flags = HTOO32(OHCI_TD_SETUP | OHCI_TD_NOCC | |
2755 | OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); | | 2755 | OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); |
2756 | setup->td.td_cbp = HTOO32(DMAADDR(&opipe->ctrl.reqdma, 0)); | | 2756 | setup->td.td_cbp = HTOO32(DMAADDR(&opipe->ctrl.reqdma, 0)); |
2757 | setup->td.td_nexttd = HTOO32(next->physaddr); | | 2757 | setup->td.td_nexttd = HTOO32(next->physaddr); |
2758 | setup->td.td_be = HTOO32(O32TOH(setup->td.td_cbp) + sizeof(*req) - 1); | | 2758 | setup->td.td_be = HTOO32(O32TOH(setup->td.td_cbp) + sizeof(*req) - 1); |
2759 | setup->nexttd = next; | | 2759 | setup->nexttd = next; |
2760 | setup->len = 0; | | 2760 | setup->len = 0; |
2761 | setup->xfer = xfer; | | 2761 | setup->xfer = xfer; |
2762 | setup->flags = 0; | | 2762 | setup->flags = 0; |
2763 | ohci_hash_add_td(sc, setup); | | 2763 | ohci_hash_add_td(sc, setup); |
2764 | | | 2764 | |
2765 | xfer->ux_hcpriv = setup; | | 2765 | xfer->ux_hcpriv = setup; |
2766 | usb_syncmem(&setup->dma, setup->offs, sizeof(setup->td), | | 2766 | usb_syncmem(&setup->dma, setup->offs, sizeof(setup->td), |
2767 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2767 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2768 | | | 2768 | |
2769 | stat->td.td_flags = HTOO32( | | 2769 | stat->td.td_flags = HTOO32( |
2770 | (isread ? OHCI_TD_OUT : OHCI_TD_IN) | | | 2770 | (isread ? OHCI_TD_OUT : OHCI_TD_IN) | |
2771 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); | | 2771 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); |
2772 | stat->td.td_cbp = 0; | | 2772 | stat->td.td_cbp = 0; |
2773 | stat->td.td_nexttd = HTOO32(tail->physaddr); | | 2773 | stat->td.td_nexttd = HTOO32(tail->physaddr); |
2774 | stat->td.td_be = 0; | | 2774 | stat->td.td_be = 0; |
2775 | stat->nexttd = tail; | | 2775 | stat->nexttd = tail; |
2776 | stat->flags = OHCI_CALL_DONE; | | 2776 | stat->flags = OHCI_CALL_DONE; |
2777 | stat->len = 0; | | 2777 | stat->len = 0; |
2778 | stat->xfer = xfer; | | 2778 | stat->xfer = xfer; |
2779 | ohci_hash_add_td(sc, stat); | | 2779 | ohci_hash_add_td(sc, stat); |
2780 | | | 2780 | |
2781 | usb_syncmem(&stat->dma, stat->offs, sizeof(stat->td), | | 2781 | usb_syncmem(&stat->dma, stat->offs, sizeof(stat->td), |
2782 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2782 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2783 | | | 2783 | |
2784 | memset(&tail->td, 0, sizeof(tail->td)); | | 2784 | memset(&tail->td, 0, sizeof(tail->td)); |
2785 | tail->nexttd = NULL; | | 2785 | tail->nexttd = NULL; |
2786 | tail->xfer = NULL; | | 2786 | tail->xfer = NULL; |
2787 | | | 2787 | |
2788 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), | | 2788 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), |
2789 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2789 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2790 | | | 2790 | |
2791 | #ifdef OHCI_DEBUG | | 2791 | #ifdef OHCI_DEBUG |
2792 | USBHIST_LOGN(ohcidebug, 5, "--- dump start ---", 0, 0, 0, 0); | | 2792 | USBHIST_LOGN(ohcidebug, 5, "--- dump start ---", 0, 0, 0, 0); |
2793 | if (ohcidebug >= 5) { | | 2793 | if (ohcidebug >= 5) { |
2794 | ohci_dump_ed(sc, sed); | | 2794 | ohci_dump_ed(sc, sed); |
2795 | ohci_dump_tds(sc, setup); | | 2795 | ohci_dump_tds(sc, setup); |
2796 | } | | 2796 | } |
2797 | USBHIST_LOGN(ohcidebug, 5, "--- dump end ---", 0, 0, 0, 0); | | 2797 | USBHIST_LOGN(ohcidebug, 5, "--- dump end ---", 0, 0, 0, 0); |
2798 | #endif | | 2798 | #endif |
2799 | | | 2799 | |
2800 | /* Insert ED in schedule */ | | 2800 | /* Insert ED in schedule */ |
2801 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | | 2801 | sed->ed.ed_tailp = HTOO32(tail->physaddr); |
2802 | usb_syncmem(&sed->dma, | | 2802 | usb_syncmem(&sed->dma, |
2803 | sed->offs + offsetof(ohci_ed_t, ed_tailp), | | 2803 | sed->offs + offsetof(ohci_ed_t, ed_tailp), |
2804 | sizeof(sed->ed.ed_tailp), | | 2804 | sizeof(sed->ed.ed_tailp), |
2805 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2805 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2806 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); | | 2806 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); |
2807 | usbd_xfer_schedule_timeout(xfer); | | 2807 | usbd_xfer_schedule_timeout(xfer); |
2808 | | | 2808 | |
2809 | DPRINTF("done", 0, 0, 0, 0); | | 2809 | DPRINTF("done", 0, 0, 0, 0); |
2810 | | | 2810 | |
2811 | xfer->ux_status = USBD_IN_PROGRESS; | | 2811 | xfer->ux_status = USBD_IN_PROGRESS; |
2812 | if (!polling) | | 2812 | if (!polling) |
2813 | mutex_exit(&sc->sc_lock); | | 2813 | mutex_exit(&sc->sc_lock); |
2814 | | | 2814 | |
2815 | return USBD_IN_PROGRESS; | | 2815 | return USBD_IN_PROGRESS; |
2816 | } | | 2816 | } |
2817 | | | 2817 | |
2818 | /* Abort a device control request. */ | | 2818 | /* Abort a device control request. */ |
2819 | Static void | | 2819 | Static void |
2820 | ohci_device_ctrl_abort(struct usbd_xfer *xfer) | | 2820 | ohci_device_ctrl_abort(struct usbd_xfer *xfer) |
2821 | { | | 2821 | { |
2822 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | | 2822 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); |
2823 | | | 2823 | |
2824 | KASSERT(mutex_owned(&sc->sc_lock)); | | 2824 | KASSERT(mutex_owned(&sc->sc_lock)); |
2825 | | | 2825 | |
2826 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2826 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2827 | DPRINTF("xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 2827 | DPRINTF("xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
2828 | usbd_xfer_abort(xfer); | | 2828 | usbd_xfer_abort(xfer); |
2829 | } | | 2829 | } |
2830 | | | 2830 | |
2831 | /* Close a device control pipe. */ | | 2831 | /* Close a device control pipe. */ |
2832 | Static void | | 2832 | Static void |
2833 | ohci_device_ctrl_close(struct usbd_pipe *pipe) | | 2833 | ohci_device_ctrl_close(struct usbd_pipe *pipe) |
2834 | { | | 2834 | { |
2835 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 2835 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
2836 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 2836 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
2837 | | | 2837 | |
2838 | KASSERT(mutex_owned(&sc->sc_lock)); | | 2838 | KASSERT(mutex_owned(&sc->sc_lock)); |
2839 | | | 2839 | |
2840 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2840 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2841 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); | | 2841 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); |
2842 | ohci_close_pipe(pipe, sc->sc_ctrl_head); | | 2842 | ohci_close_pipe(pipe, sc->sc_ctrl_head); |
2843 | ohci_free_std_locked(sc, opipe->tail.td); | | 2843 | ohci_free_std_locked(sc, opipe->tail.td); |
2844 | | | 2844 | |
2845 | usb_freemem(&sc->sc_bus, &opipe->ctrl.reqdma); | | 2845 | usb_freemem(&sc->sc_bus, &opipe->ctrl.reqdma); |
2846 | } | | 2846 | } |
2847 | | | 2847 | |
2848 | /************************/ | | 2848 | /************************/ |
2849 | | | 2849 | |
2850 | Static void | | 2850 | Static void |
2851 | ohci_device_clear_toggle(struct usbd_pipe *pipe) | | 2851 | ohci_device_clear_toggle(struct usbd_pipe *pipe) |
2852 | { | | 2852 | { |
2853 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 2853 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
2854 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 2854 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
2855 | | | 2855 | |
2856 | opipe->sed->ed.ed_headp &= HTOO32(~OHCI_TOGGLECARRY); | | 2856 | opipe->sed->ed.ed_headp &= HTOO32(~OHCI_TOGGLECARRY); |
2857 | } | | 2857 | } |
2858 | | | 2858 | |
2859 | Static void | | 2859 | Static void |
2860 | ohci_noop(struct usbd_pipe *pipe) | | 2860 | ohci_noop(struct usbd_pipe *pipe) |
2861 | { | | 2861 | { |
2862 | } | | 2862 | } |
2863 | | | 2863 | |
2864 | Static int | | 2864 | Static int |
2865 | ohci_device_bulk_init(struct usbd_xfer *xfer) | | 2865 | ohci_device_bulk_init(struct usbd_xfer *xfer) |
2866 | { | | 2866 | { |
2867 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2867 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2868 | int len = xfer->ux_bufsize; | | 2868 | int len = xfer->ux_bufsize; |
2869 | int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 2869 | int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; |
2870 | int isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 2870 | int isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
2871 | int err; | | 2871 | int err; |
2872 | | | 2872 | |
2873 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2873 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2874 | | | 2874 | |
2875 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); | | 2875 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); |
2876 | | | 2876 | |
2877 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, | | 2877 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, |
2878 | len, isread, xfer->ux_flags); | | 2878 | len, isread, xfer->ux_flags); |
2879 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); | | 2879 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); |
2880 | | | 2880 | |
2881 | /* Allocate a chain of new TDs (including a new tail). */ | | 2881 | /* Allocate a chain of new TDs (including a new tail). */ |
2882 | err = ohci_alloc_std_chain(sc, xfer, len, isread); | | 2882 | err = ohci_alloc_std_chain(sc, xfer, len, isread); |
2883 | if (err) | | 2883 | if (err) |
2884 | return err; | | 2884 | return err; |
2885 | | | 2885 | |
2886 | return 0; | | 2886 | return 0; |
2887 | } | | 2887 | } |
2888 | | | 2888 | |
2889 | Static void | | 2889 | Static void |
2890 | ohci_device_bulk_fini(struct usbd_xfer *xfer) | | 2890 | ohci_device_bulk_fini(struct usbd_xfer *xfer) |
2891 | { | | 2891 | { |
2892 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2892 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2893 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2893 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2894 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 2894 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
2895 | | | 2895 | |
2896 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2896 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2897 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); | | 2897 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); |
2898 | | | 2898 | |
2899 | mutex_enter(&sc->sc_lock); | | 2899 | mutex_enter(&sc->sc_lock); |
2900 | for (size_t i = 0; i < ox->ox_nstd; i++) { | | 2900 | for (size_t i = 0; i < ox->ox_nstd; i++) { |
2901 | ohci_soft_td_t *std = ox->ox_stds[i]; | | 2901 | ohci_soft_td_t *std = ox->ox_stds[i]; |
2902 | if (std == NULL) | | 2902 | if (std == NULL) |
2903 | break; | | 2903 | break; |
2904 | if (std != opipe->tail.td) | | 2904 | if (std != opipe->tail.td) |
2905 | ohci_free_std_locked(sc, std); | | 2905 | ohci_free_std_locked(sc, std); |
2906 | } | | 2906 | } |
2907 | mutex_exit(&sc->sc_lock); | | 2907 | mutex_exit(&sc->sc_lock); |
2908 | | | 2908 | |
2909 | if (ox->ox_nstd) { | | 2909 | if (ox->ox_nstd) { |
2910 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; | | 2910 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; |
2911 | kmem_free(ox->ox_stds, sz); | | 2911 | kmem_free(ox->ox_stds, sz); |
2912 | } | | 2912 | } |
2913 | } | | 2913 | } |
2914 | | | 2914 | |
2915 | Static usbd_status | | 2915 | Static usbd_status |
2916 | ohci_device_bulk_transfer(struct usbd_xfer *xfer) | | 2916 | ohci_device_bulk_transfer(struct usbd_xfer *xfer) |
2917 | { | | 2917 | { |
2918 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2918 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2919 | usbd_status err; | | 2919 | usbd_status err; |
2920 | | | 2920 | |
2921 | /* Insert last in queue. */ | | 2921 | /* Insert last in queue. */ |
2922 | mutex_enter(&sc->sc_lock); | | 2922 | mutex_enter(&sc->sc_lock); |
2923 | err = usb_insert_transfer(xfer); | | 2923 | err = usb_insert_transfer(xfer); |
2924 | mutex_exit(&sc->sc_lock); | | 2924 | mutex_exit(&sc->sc_lock); |
2925 | if (err) | | 2925 | if (err) |
2926 | return err; | | 2926 | return err; |
2927 | | | 2927 | |
2928 | /* Pipe isn't running, start first */ | | 2928 | /* Pipe isn't running, start first */ |
2929 | return ohci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 2929 | return ohci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
2930 | } | | 2930 | } |
2931 | | | 2931 | |
2932 | Static usbd_status | | 2932 | Static usbd_status |
2933 | ohci_device_bulk_start(struct usbd_xfer *xfer) | | 2933 | ohci_device_bulk_start(struct usbd_xfer *xfer) |
2934 | { | | 2934 | { |
2935 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 2935 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
2936 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 2936 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
2937 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 2937 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
2938 | ohci_soft_td_t *last; | | 2938 | ohci_soft_td_t *last; |
2939 | ohci_soft_td_t *data, *tail, *tdp; | | 2939 | ohci_soft_td_t *data, *tail, *tdp; |
2940 | ohci_soft_ed_t *sed; | | 2940 | ohci_soft_ed_t *sed; |
2941 | int len, isread, endpt; | | 2941 | int len, isread, endpt; |
2942 | const bool polling = sc->sc_bus.ub_usepolling; | | 2942 | const bool polling = sc->sc_bus.ub_usepolling; |
2943 | | | 2943 | |
2944 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 2944 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
2945 | | | 2945 | |
2946 | if (sc->sc_dying) | | 2946 | if (sc->sc_dying) |
2947 | return USBD_IOERROR; | | 2947 | return USBD_IOERROR; |
2948 | | | 2948 | |
2949 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); | | 2949 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); |
2950 | | | 2950 | |
2951 | len = xfer->ux_length; | | 2951 | len = xfer->ux_length; |
2952 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 2952 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; |
2953 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 2953 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
2954 | sed = opipe->sed; | | 2954 | sed = opipe->sed; |
2955 | | | 2955 | |
2956 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, | | 2956 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, |
2957 | len, isread, xfer->ux_flags); | | 2957 | len, isread, xfer->ux_flags); |
2958 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); | | 2958 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); |
2959 | | | 2959 | |
2960 | if (!polling) | | 2960 | if (!polling) |
2961 | mutex_enter(&sc->sc_lock); | | 2961 | mutex_enter(&sc->sc_lock); |
2962 | | | 2962 | |
2963 | /* | | 2963 | /* |
2964 | * Use the pipe "tail" TD as our first and loan our first TD to the | | 2964 | * Use the pipe "tail" TD as our first and loan our first TD to the |
2965 | * next transfer | | 2965 | * next transfer |
2966 | */ | | 2966 | */ |
2967 | data = opipe->tail.td; | | 2967 | data = opipe->tail.td; |
2968 | opipe->tail.td = ox->ox_stds[0]; | | 2968 | opipe->tail.td = ox->ox_stds[0]; |
2969 | ox->ox_stds[0] = data; | | 2969 | ox->ox_stds[0] = data; |
2970 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); | | 2970 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); |
2971 | | | 2971 | |
2972 | /* point at sentinel */ | | 2972 | /* point at sentinel */ |
2973 | tail = opipe->tail.td; | | 2973 | tail = opipe->tail.td; |
2974 | memset(&tail->td, 0, sizeof(tail->td)); | | 2974 | memset(&tail->td, 0, sizeof(tail->td)); |
2975 | tail->nexttd = NULL; | | 2975 | tail->nexttd = NULL; |
2976 | tail->xfer = NULL; | | 2976 | tail->xfer = NULL; |
2977 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), | | 2977 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), |
2978 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2978 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2979 | xfer->ux_hcpriv = data; | | 2979 | xfer->ux_hcpriv = data; |
2980 | | | 2980 | |
2981 | DPRINTFN(8, "xfer %#jx data %#jx tail %#jx", (uintptr_t)xfer, | | 2981 | DPRINTFN(8, "xfer %#jx data %#jx tail %#jx", (uintptr_t)xfer, |
2982 | (uintptr_t)ox->ox_stds[0], (uintptr_t)tail, 0); | | 2982 | (uintptr_t)ox->ox_stds[0], (uintptr_t)tail, 0); |
2983 | KASSERT(opipe->tail.td == tail); | | 2983 | KASSERT(opipe->tail.td == tail); |
2984 | | | 2984 | |
2985 | /* We want interrupt at the end of the transfer. */ | | 2985 | /* We want interrupt at the end of the transfer. */ |
2986 | last->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); | | 2986 | last->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); |
2987 | last->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); | | 2987 | last->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); |
2988 | last->td.td_nexttd = HTOO32(tail->physaddr); | | 2988 | last->td.td_nexttd = HTOO32(tail->physaddr); |
2989 | last->nexttd = tail; | | 2989 | last->nexttd = tail; |
2990 | last->flags |= OHCI_CALL_DONE; | | 2990 | last->flags |= OHCI_CALL_DONE; |
2991 | usb_syncmem(&last->dma, last->offs, sizeof(last->td), | | 2991 | usb_syncmem(&last->dma, last->offs, sizeof(last->td), |
2992 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 2992 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2993 | | | 2993 | |
2994 | DPRINTFN(4, "ed_flags=0x%08jx td_flags=0x%08jx " | | 2994 | DPRINTFN(4, "ed_flags=0x%08jx td_flags=0x%08jx " |
2995 | "td_cbp=0x%08jx td_be=0x%08jx", | | 2995 | "td_cbp=0x%08jx td_be=0x%08jx", |
2996 | (int)O32TOH(sed->ed.ed_flags), | | 2996 | (int)O32TOH(sed->ed.ed_flags), |
2997 | (int)O32TOH(data->td.td_flags), | | 2997 | (int)O32TOH(data->td.td_flags), |
2998 | (int)O32TOH(data->td.td_cbp), | | 2998 | (int)O32TOH(data->td.td_cbp), |
2999 | (int)O32TOH(data->td.td_be)); | | 2999 | (int)O32TOH(data->td.td_be)); |
3000 | | | 3000 | |
3001 | #ifdef OHCI_DEBUG | | 3001 | #ifdef OHCI_DEBUG |
3002 | DPRINTFN(5, "--- dump start ---", 0, 0, 0, 0); | | 3002 | DPRINTFN(5, "--- dump start ---", 0, 0, 0, 0); |
3003 | if (ohcidebug >= 5) { | | 3003 | if (ohcidebug >= 5) { |
3004 | ohci_dump_ed(sc, sed); | | 3004 | ohci_dump_ed(sc, sed); |
3005 | ohci_dump_tds(sc, data); | | 3005 | ohci_dump_tds(sc, data); |
3006 | } | | 3006 | } |
3007 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); | | 3007 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); |
3008 | #endif | | 3008 | #endif |
3009 | | | 3009 | |
3010 | /* Insert ED in schedule */ | | 3010 | /* Insert ED in schedule */ |
3011 | for (tdp = data; tdp != tail; tdp = tdp->nexttd) { | | 3011 | for (tdp = data; tdp != tail; tdp = tdp->nexttd) { |
3012 | KASSERT(tdp->xfer == xfer); | | 3012 | KASSERT(tdp->xfer == xfer); |
3013 | } | | 3013 | } |
3014 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3014 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3015 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3015 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3016 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | | 3016 | sed->ed.ed_tailp = HTOO32(tail->physaddr); |
3017 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | | 3017 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); |
3018 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3018 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3019 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3019 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3020 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); | | 3020 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); |
3021 | usbd_xfer_schedule_timeout(xfer); | | 3021 | usbd_xfer_schedule_timeout(xfer); |
3022 | xfer->ux_status = USBD_IN_PROGRESS; | | 3022 | xfer->ux_status = USBD_IN_PROGRESS; |
3023 | if (!polling) | | 3023 | if (!polling) |
3024 | mutex_exit(&sc->sc_lock); | | 3024 | mutex_exit(&sc->sc_lock); |
3025 | | | 3025 | |
3026 | return USBD_IN_PROGRESS; | | 3026 | return USBD_IN_PROGRESS; |
3027 | } | | 3027 | } |
3028 | | | 3028 | |
3029 | Static void | | 3029 | Static void |
3030 | ohci_device_bulk_abort(struct usbd_xfer *xfer) | | 3030 | ohci_device_bulk_abort(struct usbd_xfer *xfer) |
3031 | { | | 3031 | { |
3032 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | | 3032 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); |
3033 | | | 3033 | |
3034 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3034 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3035 | | | 3035 | |
3036 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3036 | KASSERT(mutex_owned(&sc->sc_lock)); |
3037 | | | 3037 | |
3038 | DPRINTF("xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 3038 | DPRINTF("xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
3039 | usbd_xfer_abort(xfer); | | 3039 | usbd_xfer_abort(xfer); |
3040 | } | | 3040 | } |
3041 | | | 3041 | |
3042 | /* | | 3042 | /* |
3043 | * Close a device bulk pipe. | | 3043 | * Close a device bulk pipe. |
3044 | */ | | 3044 | */ |
3045 | Static void | | 3045 | Static void |
3046 | ohci_device_bulk_close(struct usbd_pipe *pipe) | | 3046 | ohci_device_bulk_close(struct usbd_pipe *pipe) |
3047 | { | | 3047 | { |
3048 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 3048 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
3049 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 3049 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
3050 | | | 3050 | |
3051 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3051 | KASSERT(mutex_owned(&sc->sc_lock)); |
3052 | | | 3052 | |
3053 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3053 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3054 | | | 3054 | |
3055 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); | | 3055 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); |
3056 | ohci_close_pipe(pipe, sc->sc_bulk_head); | | 3056 | ohci_close_pipe(pipe, sc->sc_bulk_head); |
3057 | ohci_free_std_locked(sc, opipe->tail.td); | | 3057 | ohci_free_std_locked(sc, opipe->tail.td); |
3058 | } | | 3058 | } |
3059 | | | 3059 | |
3060 | /************************/ | | 3060 | /************************/ |
3061 | | | 3061 | |
3062 | Static int | | 3062 | Static int |
3063 | ohci_device_intr_init(struct usbd_xfer *xfer) | | 3063 | ohci_device_intr_init(struct usbd_xfer *xfer) |
3064 | { | | 3064 | { |
3065 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3065 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3066 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3066 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3067 | int len = xfer->ux_bufsize; | | 3067 | int len = xfer->ux_bufsize; |
3068 | int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 3068 | int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; |
3069 | int isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 3069 | int isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
3070 | int err; | | 3070 | int err; |
3071 | | | 3071 | |
3072 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3072 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3073 | | | 3073 | |
3074 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); | | 3074 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); |
3075 | KASSERT(len != 0); | | 3075 | KASSERT(len != 0); |
3076 | | | 3076 | |
3077 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, | | 3077 | DPRINTFN(4, "xfer=%#jx len=%jd isread=%jd flags=%jd", (uintptr_t)xfer, |
3078 | len, isread, xfer->ux_flags); | | 3078 | len, isread, xfer->ux_flags); |
3079 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); | | 3079 | DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0); |
3080 | | | 3080 | |
3081 | ox->ox_nstd = 0; | | 3081 | ox->ox_nstd = 0; |
3082 | | | 3082 | |
3083 | err = ohci_alloc_std_chain(sc, xfer, len, isread); | | 3083 | err = ohci_alloc_std_chain(sc, xfer, len, isread); |
3084 | if (err) { | | 3084 | if (err) { |
3085 | return err; | | 3085 | return err; |
3086 | } | | 3086 | } |
3087 | | | 3087 | |
3088 | return 0; | | 3088 | return 0; |
3089 | } | | 3089 | } |
3090 | | | 3090 | |
3091 | Static void | | 3091 | Static void |
3092 | ohci_device_intr_fini(struct usbd_xfer *xfer) | | 3092 | ohci_device_intr_fini(struct usbd_xfer *xfer) |
3093 | { | | 3093 | { |
3094 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3094 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3095 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3095 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3096 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 3096 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
3097 | | | 3097 | |
3098 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3098 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3099 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); | | 3099 | DPRINTFN(8, "xfer %#jx nstd %jd", (uintptr_t)xfer, ox->ox_nstd, 0, 0); |
3100 | | | 3100 | |
3101 | mutex_enter(&sc->sc_lock); | | 3101 | mutex_enter(&sc->sc_lock); |
3102 | for (size_t i = 0; i < ox->ox_nstd; i++) { | | 3102 | for (size_t i = 0; i < ox->ox_nstd; i++) { |
3103 | ohci_soft_td_t *std = ox->ox_stds[i]; | | 3103 | ohci_soft_td_t *std = ox->ox_stds[i]; |
3104 | if (std != NULL) | | 3104 | if (std != NULL) |
3105 | break; | | 3105 | break; |
3106 | if (std != opipe->tail.td) | | 3106 | if (std != opipe->tail.td) |
3107 | ohci_free_std_locked(sc, std); | | 3107 | ohci_free_std_locked(sc, std); |
3108 | } | | 3108 | } |
3109 | mutex_exit(&sc->sc_lock); | | 3109 | mutex_exit(&sc->sc_lock); |
3110 | | | 3110 | |
3111 | if (ox->ox_nstd) { | | 3111 | if (ox->ox_nstd) { |
3112 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; | | 3112 | const size_t sz = sizeof(ohci_soft_td_t *) * ox->ox_nstd; |
3113 | kmem_free(ox->ox_stds, sz); | | 3113 | kmem_free(ox->ox_stds, sz); |
3114 | } | | 3114 | } |
3115 | } | | 3115 | } |
3116 | | | 3116 | |
3117 | Static usbd_status | | 3117 | Static usbd_status |
3118 | ohci_device_intr_transfer(struct usbd_xfer *xfer) | | 3118 | ohci_device_intr_transfer(struct usbd_xfer *xfer) |
3119 | { | | 3119 | { |
3120 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3120 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3121 | usbd_status err; | | 3121 | usbd_status err; |
3122 | | | 3122 | |
3123 | /* Insert last in queue. */ | | 3123 | /* Insert last in queue. */ |
3124 | mutex_enter(&sc->sc_lock); | | 3124 | mutex_enter(&sc->sc_lock); |
3125 | err = usb_insert_transfer(xfer); | | 3125 | err = usb_insert_transfer(xfer); |
3126 | mutex_exit(&sc->sc_lock); | | 3126 | mutex_exit(&sc->sc_lock); |
3127 | if (err) | | 3127 | if (err) |
3128 | return err; | | 3128 | return err; |
3129 | | | 3129 | |
3130 | /* Pipe isn't running, start first */ | | 3130 | /* Pipe isn't running, start first */ |
3131 | return ohci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 3131 | return ohci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
3132 | } | | 3132 | } |
3133 | | | 3133 | |
3134 | Static usbd_status | | 3134 | Static usbd_status |
3135 | ohci_device_intr_start(struct usbd_xfer *xfer) | | 3135 | ohci_device_intr_start(struct usbd_xfer *xfer) |
3136 | { | | 3136 | { |
3137 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3137 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3138 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 3138 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
3139 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3139 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3140 | ohci_soft_ed_t *sed = opipe->sed; | | 3140 | ohci_soft_ed_t *sed = opipe->sed; |
3141 | ohci_soft_td_t *data, *last, *tail; | | 3141 | ohci_soft_td_t *data, *last, *tail; |
3142 | int len, isread, endpt; | | 3142 | int len, isread, endpt; |
3143 | const bool polling = sc->sc_bus.ub_usepolling; | | 3143 | const bool polling = sc->sc_bus.ub_usepolling; |
3144 | | | 3144 | |
3145 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3145 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3146 | | | 3146 | |
3147 | if (sc->sc_dying) | | 3147 | if (sc->sc_dying) |
3148 | return USBD_IOERROR; | | 3148 | return USBD_IOERROR; |
3149 | | | 3149 | |
3150 | DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd priv=%#jx", (uintptr_t)xfer, | | 3150 | DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd priv=%#jx", (uintptr_t)xfer, |
3151 | xfer->ux_length, xfer->ux_flags, (uintptr_t)xfer->ux_priv); | | 3151 | xfer->ux_length, xfer->ux_flags, (uintptr_t)xfer->ux_priv); |
3152 | | | 3152 | |
3153 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); | | 3153 | KASSERT(!(xfer->ux_rqflags & URQ_REQUEST)); |
3154 | | | 3154 | |
3155 | len = xfer->ux_length; | | 3155 | len = xfer->ux_length; |
3156 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 3156 | endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress; |
3157 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 3157 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
3158 | | | 3158 | |
3159 | if (!polling) | | 3159 | if (!polling) |
3160 | mutex_enter(&sc->sc_lock); | | 3160 | mutex_enter(&sc->sc_lock); |
3161 | | | 3161 | |
3162 | /* | | 3162 | /* |
3163 | * Use the pipe "tail" TD as our first and loan our first TD to the | | 3163 | * Use the pipe "tail" TD as our first and loan our first TD to the |
3164 | * next transfer. | | 3164 | * next transfer. |
3165 | */ | | 3165 | */ |
3166 | data = opipe->tail.td; | | 3166 | data = opipe->tail.td; |
3167 | opipe->tail.td = ox->ox_stds[0]; | | 3167 | opipe->tail.td = ox->ox_stds[0]; |
3168 | ox->ox_stds[0] = data; | | 3168 | ox->ox_stds[0] = data; |
3169 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); | | 3169 | ohci_reset_std_chain(sc, xfer, len, isread, data, &last); |
3170 | | | 3170 | |
3171 | /* point at sentinel */ | | 3171 | /* point at sentinel */ |
3172 | tail = opipe->tail.td; | | 3172 | tail = opipe->tail.td; |
3173 | memset(&tail->td, 0, sizeof(tail->td)); | | 3173 | memset(&tail->td, 0, sizeof(tail->td)); |
3174 | tail->nexttd = NULL; | | 3174 | tail->nexttd = NULL; |
3175 | tail->xfer = NULL; | | 3175 | tail->xfer = NULL; |
3176 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), | | 3176 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td), |
3177 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3177 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3178 | xfer->ux_hcpriv = data; | | 3178 | xfer->ux_hcpriv = data; |
3179 | | | 3179 | |
3180 | DPRINTFN(8, "data %#jx tail %#jx", (uintptr_t)ox->ox_stds[0], | | 3180 | DPRINTFN(8, "data %#jx tail %#jx", (uintptr_t)ox->ox_stds[0], |
3181 | (uintptr_t)tail, 0, 0); | | 3181 | (uintptr_t)tail, 0, 0); |
3182 | KASSERT(opipe->tail.td == tail); | | 3182 | KASSERT(opipe->tail.td == tail); |
3183 | | | 3183 | |
3184 | /* We want interrupt at the end of the transfer. */ | | 3184 | /* We want interrupt at the end of the transfer. */ |
3185 | last->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); | | 3185 | last->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); |
3186 | last->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); | | 3186 | last->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); |
3187 | | | 3187 | |
3188 | last->td.td_nexttd = HTOO32(tail->physaddr); | | 3188 | last->td.td_nexttd = HTOO32(tail->physaddr); |
3189 | last->nexttd = tail; | | 3189 | last->nexttd = tail; |
3190 | last->flags |= OHCI_CALL_DONE; | | 3190 | last->flags |= OHCI_CALL_DONE; |
3191 | usb_syncmem(&last->dma, last->offs, sizeof(last->td), | | 3191 | usb_syncmem(&last->dma, last->offs, sizeof(last->td), |
3192 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3192 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3193 | | | 3193 | |
3194 | #ifdef OHCI_DEBUG | | 3194 | #ifdef OHCI_DEBUG |
3195 | DPRINTFN(5, "--- dump start ---", 0, 0, 0, 0); | | 3195 | DPRINTFN(5, "--- dump start ---", 0, 0, 0, 0); |
3196 | if (ohcidebug >= 5) { | | 3196 | if (ohcidebug >= 5) { |
3197 | ohci_dump_ed(sc, sed); | | 3197 | ohci_dump_ed(sc, sed); |
3198 | ohci_dump_tds(sc, data); | | 3198 | ohci_dump_tds(sc, data); |
3199 | } | | 3199 | } |
3200 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); | | 3200 | DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0); |
3201 | #endif | | 3201 | #endif |
3202 | | | 3202 | |
3203 | /* Insert ED in schedule */ | | 3203 | /* Insert ED in schedule */ |
3204 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3204 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3205 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3205 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3206 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | | 3206 | sed->ed.ed_tailp = HTOO32(tail->physaddr); |
3207 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | | 3207 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); |
3208 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3208 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3209 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3209 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3210 | | | 3210 | |
3211 | xfer->ux_status = USBD_IN_PROGRESS; | | 3211 | xfer->ux_status = USBD_IN_PROGRESS; |
3212 | if (!polling) | | 3212 | if (!polling) |
3213 | mutex_exit(&sc->sc_lock); | | 3213 | mutex_exit(&sc->sc_lock); |
3214 | | | 3214 | |
3215 | return USBD_IN_PROGRESS; | | 3215 | return USBD_IN_PROGRESS; |
3216 | } | | 3216 | } |
3217 | | | 3217 | |
3218 | /* Abort a device interrupt request. */ | | 3218 | /* Abort a device interrupt request. */ |
3219 | Static void | | 3219 | Static void |
3220 | ohci_device_intr_abort(struct usbd_xfer *xfer) | | 3220 | ohci_device_intr_abort(struct usbd_xfer *xfer) |
3221 | { | | 3221 | { |
3222 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); | | 3222 | ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer); |
3223 | | | 3223 | |
3224 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3224 | KASSERT(mutex_owned(&sc->sc_lock)); |
3225 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); | | 3225 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); |
3226 | | | 3226 | |
3227 | usbd_xfer_abort(xfer); | | 3227 | usbd_xfer_abort(xfer); |
3228 | } | | 3228 | } |
3229 | | | 3229 | |
3230 | /* Close a device interrupt pipe. */ | | 3230 | /* Close a device interrupt pipe. */ |
3231 | Static void | | 3231 | Static void |
3232 | ohci_device_intr_close(struct usbd_pipe *pipe) | | 3232 | ohci_device_intr_close(struct usbd_pipe *pipe) |
3233 | { | | 3233 | { |
3234 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 3234 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
3235 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 3235 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
3236 | int nslots = opipe->intr.nslots; | | 3236 | int nslots = opipe->intr.nslots; |
3237 | int pos = opipe->intr.pos; | | 3237 | int pos = opipe->intr.pos; |
3238 | int j; | | 3238 | int j; |
3239 | ohci_soft_ed_t *p, *sed = opipe->sed; | | 3239 | ohci_soft_ed_t *p, *sed = opipe->sed; |
3240 | | | 3240 | |
3241 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3241 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3242 | | | 3242 | |
3243 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3243 | KASSERT(mutex_owned(&sc->sc_lock)); |
3244 | | | 3244 | |
3245 | DPRINTFN(1, "pipe=%#jx nslots=%jd pos=%jd", (uintptr_t)pipe, nslots, | | 3245 | DPRINTFN(1, "pipe=%#jx nslots=%jd pos=%jd", (uintptr_t)pipe, nslots, |
3246 | pos, 0); | | 3246 | pos, 0); |
3247 | usb_syncmem(&sed->dma, sed->offs, | | 3247 | usb_syncmem(&sed->dma, sed->offs, |
3248 | sizeof(sed->ed), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3248 | sizeof(sed->ed), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3249 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); | | 3249 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); |
3250 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | | 3250 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), |
3251 | sizeof(sed->ed.ed_flags), | | 3251 | sizeof(sed->ed.ed_flags), |
3252 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3252 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3253 | if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) != | | 3253 | if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) != |
3254 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) | | 3254 | (O32TOH(sed->ed.ed_headp) & OHCI_HEADMASK)) |
3255 | usb_delay_ms_locked(&sc->sc_bus, 2, &sc->sc_lock); | | 3255 | usb_delay_ms_locked(&sc->sc_bus, 2, &sc->sc_lock); |
3256 | | | 3256 | |
3257 | for (p = sc->sc_eds[pos]; p && p->next != sed; p = p->next) | | 3257 | for (p = sc->sc_eds[pos]; p && p->next != sed; p = p->next) |
3258 | continue; | | 3258 | continue; |
3259 | KASSERT(p); | | 3259 | KASSERT(p); |
3260 | p->next = sed->next; | | 3260 | p->next = sed->next; |
3261 | p->ed.ed_nexted = sed->ed.ed_nexted; | | 3261 | p->ed.ed_nexted = sed->ed.ed_nexted; |
3262 | usb_syncmem(&p->dma, p->offs + offsetof(ohci_ed_t, ed_nexted), | | 3262 | usb_syncmem(&p->dma, p->offs + offsetof(ohci_ed_t, ed_nexted), |
3263 | sizeof(p->ed.ed_nexted), | | 3263 | sizeof(p->ed.ed_nexted), |
3264 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3264 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3265 | | | 3265 | |
3266 | for (j = 0; j < nslots; j++) | | 3266 | for (j = 0; j < nslots; j++) |
3267 | --sc->sc_bws[(pos * nslots + j) % OHCI_NO_INTRS]; | | 3267 | --sc->sc_bws[(pos * nslots + j) % OHCI_NO_INTRS]; |
3268 | | | 3268 | |
3269 | ohci_free_std_locked(sc, opipe->tail.td); | | 3269 | ohci_free_std_locked(sc, opipe->tail.td); |
3270 | ohci_free_sed_locked(sc, opipe->sed); | | 3270 | ohci_free_sed_locked(sc, opipe->sed); |
3271 | } | | 3271 | } |
3272 | | | 3272 | |
3273 | Static usbd_status | | 3273 | Static usbd_status |
3274 | ohci_device_setintr(ohci_softc_t *sc, struct ohci_pipe *opipe, int ival) | | 3274 | ohci_device_setintr(ohci_softc_t *sc, struct ohci_pipe *opipe, int ival) |
3275 | { | | 3275 | { |
3276 | int i, j, best; | | 3276 | int i, j, best; |
3277 | u_int npoll, slow, shigh, nslots; | | 3277 | u_int npoll, slow, shigh, nslots; |
3278 | u_int bestbw, bw; | | 3278 | u_int bestbw, bw; |
3279 | ohci_soft_ed_t *hsed, *sed = opipe->sed; | | 3279 | ohci_soft_ed_t *hsed, *sed = opipe->sed; |
3280 | | | 3280 | |
3281 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3281 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3282 | | | 3282 | |
3283 | DPRINTFN(2, "pipe=%#jx", (uintptr_t)opipe, 0, 0, 0); | | 3283 | DPRINTFN(2, "pipe=%#jx", (uintptr_t)opipe, 0, 0, 0); |
3284 | if (ival == 0) { | | 3284 | if (ival == 0) { |
3285 | printf("ohci_setintr: 0 interval\n"); | | 3285 | printf("ohci_setintr: 0 interval\n"); |
3286 | return USBD_INVAL; | | 3286 | return USBD_INVAL; |
3287 | } | | 3287 | } |
3288 | | | 3288 | |
3289 | npoll = OHCI_NO_INTRS; | | 3289 | npoll = OHCI_NO_INTRS; |
3290 | while (npoll > ival) | | 3290 | while (npoll > ival) |
3291 | npoll /= 2; | | 3291 | npoll /= 2; |
3292 | DPRINTFN(2, "ival=%jd npoll=%jd", ival, npoll, 0, 0); | | 3292 | DPRINTFN(2, "ival=%jd npoll=%jd", ival, npoll, 0, 0); |
3293 | | | 3293 | |
3294 | /* | | 3294 | /* |
3295 | * We now know which level in the tree the ED must go into. | | 3295 | * We now know which level in the tree the ED must go into. |
3296 | * Figure out which slot has most bandwidth left over. | | 3296 | * Figure out which slot has most bandwidth left over. |
3297 | * Slots to examine: | | 3297 | * Slots to examine: |
3298 | * npoll | | 3298 | * npoll |
3299 | * 1 0 | | 3299 | * 1 0 |
3300 | * 2 1 2 | | 3300 | * 2 1 2 |
3301 | * 4 3 4 5 6 | | 3301 | * 4 3 4 5 6 |
3302 | * 8 7 8 9 10 11 12 13 14 | | 3302 | * 8 7 8 9 10 11 12 13 14 |
3303 | * N (N-1) .. (N-1+N-1) | | 3303 | * N (N-1) .. (N-1+N-1) |
3304 | */ | | 3304 | */ |
3305 | slow = npoll-1; | | 3305 | slow = npoll-1; |
3306 | shigh = slow + npoll; | | 3306 | shigh = slow + npoll; |
3307 | nslots = OHCI_NO_INTRS / npoll; | | 3307 | nslots = OHCI_NO_INTRS / npoll; |
3308 | for (best = i = slow, bestbw = ~0; i < shigh; i++) { | | 3308 | for (best = i = slow, bestbw = ~0; i < shigh; i++) { |
3309 | bw = 0; | | 3309 | bw = 0; |
3310 | for (j = 0; j < nslots; j++) | | 3310 | for (j = 0; j < nslots; j++) |
3311 | bw += sc->sc_bws[(i * nslots + j) % OHCI_NO_INTRS]; | | 3311 | bw += sc->sc_bws[(i * nslots + j) % OHCI_NO_INTRS]; |
3312 | if (bw < bestbw) { | | 3312 | if (bw < bestbw) { |
3313 | best = i; | | 3313 | best = i; |
3314 | bestbw = bw; | | 3314 | bestbw = bw; |
3315 | } | | 3315 | } |
3316 | } | | 3316 | } |
3317 | DPRINTFN(2, "best=%jd(%jd..%jd) bestbw=%jd", best, slow, shigh, bestbw); | | 3317 | DPRINTFN(2, "best=%jd(%jd..%jd) bestbw=%jd", best, slow, shigh, bestbw); |
3318 | | | 3318 | |
3319 | mutex_enter(&sc->sc_lock); | | 3319 | mutex_enter(&sc->sc_lock); |
3320 | hsed = sc->sc_eds[best]; | | 3320 | hsed = sc->sc_eds[best]; |
3321 | sed->next = hsed->next; | | 3321 | sed->next = hsed->next; |
3322 | usb_syncmem(&hsed->dma, hsed->offs + offsetof(ohci_ed_t, ed_flags), | | 3322 | usb_syncmem(&hsed->dma, hsed->offs + offsetof(ohci_ed_t, ed_flags), |
3323 | sizeof(hsed->ed.ed_flags), | | 3323 | sizeof(hsed->ed.ed_flags), |
3324 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3324 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3325 | sed->ed.ed_nexted = hsed->ed.ed_nexted; | | 3325 | sed->ed.ed_nexted = hsed->ed.ed_nexted; |
3326 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | | 3326 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), |
3327 | sizeof(sed->ed.ed_flags), | | 3327 | sizeof(sed->ed.ed_flags), |
3328 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3328 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3329 | hsed->next = sed; | | 3329 | hsed->next = sed; |
3330 | hsed->ed.ed_nexted = HTOO32(sed->physaddr); | | 3330 | hsed->ed.ed_nexted = HTOO32(sed->physaddr); |
3331 | usb_syncmem(&hsed->dma, hsed->offs + offsetof(ohci_ed_t, ed_flags), | | 3331 | usb_syncmem(&hsed->dma, hsed->offs + offsetof(ohci_ed_t, ed_flags), |
3332 | sizeof(hsed->ed.ed_flags), | | 3332 | sizeof(hsed->ed.ed_flags), |
3333 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3333 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3334 | mutex_exit(&sc->sc_lock); | | 3334 | mutex_exit(&sc->sc_lock); |
3335 | | | 3335 | |
3336 | for (j = 0; j < nslots; j++) | | 3336 | for (j = 0; j < nslots; j++) |
3337 | ++sc->sc_bws[(best * nslots + j) % OHCI_NO_INTRS]; | | 3337 | ++sc->sc_bws[(best * nslots + j) % OHCI_NO_INTRS]; |
3338 | opipe->intr.nslots = nslots; | | 3338 | opipe->intr.nslots = nslots; |
3339 | opipe->intr.pos = best; | | 3339 | opipe->intr.pos = best; |
3340 | | | 3340 | |
3341 | DPRINTFN(5, "returns %#jx", (uintptr_t)opipe, 0, 0, 0); | | 3341 | DPRINTFN(5, "returns %#jx", (uintptr_t)opipe, 0, 0, 0); |
3342 | return USBD_NORMAL_COMPLETION; | | 3342 | return USBD_NORMAL_COMPLETION; |
3343 | } | | 3343 | } |
3344 | | | 3344 | |
3345 | /***********************/ | | 3345 | /***********************/ |
3346 | | | 3346 | |
3347 | Static int | | 3347 | Static int |
3348 | ohci_device_isoc_init(struct usbd_xfer *xfer) | | 3348 | ohci_device_isoc_init(struct usbd_xfer *xfer) |
3349 | { | | 3349 | { |
3350 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3350 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3351 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3351 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3352 | ohci_soft_itd_t *sitd; | | 3352 | ohci_soft_itd_t *sitd; |
3353 | size_t i; | | 3353 | size_t i; |
3354 | int err; | | 3354 | int err; |
3355 | | | 3355 | |
3356 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3356 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3357 | | | 3357 | |
3358 | DPRINTFN(1, "xfer %#jx len %jd flags %jd", (uintptr_t)xfer, | | 3358 | DPRINTFN(1, "xfer %#jx len %jd flags %jd", (uintptr_t)xfer, |
3359 | xfer->ux_length, xfer->ux_flags, 0); | | 3359 | xfer->ux_length, xfer->ux_flags, 0); |
3360 | | | 3360 | |
3361 | const size_t nfsitd = | | 3361 | const size_t nfsitd = |
3362 | (xfer->ux_nframes + OHCI_ITD_NOFFSET - 1) / OHCI_ITD_NOFFSET; | | 3362 | (xfer->ux_nframes + OHCI_ITD_NOFFSET - 1) / OHCI_ITD_NOFFSET; |
3363 | const size_t nbsitd = xfer->ux_bufsize / OHCI_PAGE_SIZE; | | 3363 | const size_t nbsitd = xfer->ux_bufsize / OHCI_PAGE_SIZE; |
3364 | const size_t nsitd = MAX(nfsitd, nbsitd) + 1; | | 3364 | const size_t nsitd = MAX(nfsitd, nbsitd) + 1; |
3365 | | | 3365 | |
3366 | ox->ox_sitds = kmem_zalloc(sizeof(ohci_soft_itd_t *) * nsitd, | | 3366 | ox->ox_sitds = kmem_zalloc(sizeof(ohci_soft_itd_t *) * nsitd, |
3367 | KM_SLEEP); | | 3367 | KM_SLEEP); |
3368 | ox->ox_nsitd = nsitd; | | 3368 | ox->ox_nsitd = nsitd; |
3369 | | | 3369 | |
3370 | for (i = 0; i < nsitd; i++) { | | 3370 | for (i = 0; i < nsitd; i++) { |
3371 | /* Allocate next ITD */ | | 3371 | /* Allocate next ITD */ |
3372 | sitd = ohci_alloc_sitd(sc); | | 3372 | sitd = ohci_alloc_sitd(sc); |
3373 | if (sitd == NULL) { | | 3373 | if (sitd == NULL) { |
3374 | err = ENOMEM; | | 3374 | err = ENOMEM; |
3375 | goto fail; | | 3375 | goto fail; |
3376 | } | | 3376 | } |
3377 | ox->ox_sitds[i] = sitd; | | 3377 | ox->ox_sitds[i] = sitd; |
3378 | sitd->xfer = xfer; | | 3378 | sitd->xfer = xfer; |
3379 | sitd->flags = 0; | | 3379 | sitd->flags = 0; |
3380 | } | | 3380 | } |
3381 | | | 3381 | |
3382 | return 0; | | 3382 | return 0; |
3383 | fail: | | 3383 | fail: |
3384 | for (; i > 0;) { | | 3384 | for (; i > 0;) { |
3385 | ohci_free_sitd(sc, ox->ox_sitds[--i]); | | 3385 | ohci_free_sitd(sc, ox->ox_sitds[--i]); |
3386 | } | | 3386 | } |
3387 | return err; | | 3387 | return err; |
3388 | } | | 3388 | } |
3389 | | | 3389 | |
3390 | Static void | | 3390 | Static void |
3391 | ohci_device_isoc_fini(struct usbd_xfer *xfer) | | 3391 | ohci_device_isoc_fini(struct usbd_xfer *xfer) |
3392 | { | | 3392 | { |
3393 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3393 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3394 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3394 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3395 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 3395 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
3396 | | | 3396 | |
3397 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3397 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3398 | | | 3398 | |
3399 | mutex_enter(&sc->sc_lock); | | 3399 | mutex_enter(&sc->sc_lock); |
3400 | for (size_t i = 0; i < ox->ox_nsitd; i++) { | | 3400 | for (size_t i = 0; i < ox->ox_nsitd; i++) { |
3401 | if (ox->ox_sitds[i] != opipe->tail.itd) { | | 3401 | if (ox->ox_sitds[i] != opipe->tail.itd) { |
3402 | ohci_free_sitd_locked(sc, ox->ox_sitds[i]); | | 3402 | ohci_free_sitd_locked(sc, ox->ox_sitds[i]); |
3403 | } | | 3403 | } |
3404 | } | | 3404 | } |
3405 | mutex_exit(&sc->sc_lock); | | 3405 | mutex_exit(&sc->sc_lock); |
3406 | | | 3406 | |
3407 | if (ox->ox_nsitd) { | | 3407 | if (ox->ox_nsitd) { |
3408 | const size_t sz = sizeof(ohci_soft_itd_t *) * ox->ox_nsitd; | | 3408 | const size_t sz = sizeof(ohci_soft_itd_t *) * ox->ox_nsitd; |
3409 | kmem_free(ox->ox_sitds, sz); | | 3409 | kmem_free(ox->ox_sitds, sz); |
3410 | } | | 3410 | } |
3411 | } | | 3411 | } |
3412 | | | 3412 | |
3413 | | | 3413 | |
3414 | usbd_status | | 3414 | usbd_status |
3415 | ohci_device_isoc_transfer(struct usbd_xfer *xfer) | | 3415 | ohci_device_isoc_transfer(struct usbd_xfer *xfer) |
3416 | { | | 3416 | { |
3417 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3417 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3418 | usbd_status __diagused err; | | 3418 | usbd_status __diagused err; |
3419 | | | 3419 | |
3420 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3420 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3421 | | | 3421 | |
3422 | DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 3422 | DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
3423 | | | 3423 | |
3424 | /* Put it on our queue, */ | | 3424 | /* Put it on our queue, */ |
3425 | mutex_enter(&sc->sc_lock); | | 3425 | mutex_enter(&sc->sc_lock); |
3426 | err = usb_insert_transfer(xfer); | | 3426 | err = usb_insert_transfer(xfer); |
3427 | mutex_exit(&sc->sc_lock); | | 3427 | mutex_exit(&sc->sc_lock); |
3428 | | | 3428 | |
3429 | KASSERT(err == USBD_NORMAL_COMPLETION); | | 3429 | KASSERT(err == USBD_NORMAL_COMPLETION); |
3430 | | | 3430 | |
3431 | /* insert into schedule, */ | | 3431 | /* insert into schedule, */ |
3432 | ohci_device_isoc_enter(xfer); | | 3432 | ohci_device_isoc_enter(xfer); |
3433 | | | 3433 | |
3434 | /* and start if the pipe wasn't running */ | | 3434 | /* and start if the pipe wasn't running */ |
3435 | return USBD_IN_PROGRESS; | | 3435 | return USBD_IN_PROGRESS; |
3436 | } | | 3436 | } |
3437 | | | 3437 | |
3438 | void | | 3438 | void |
3439 | ohci_device_isoc_enter(struct usbd_xfer *xfer) | | 3439 | ohci_device_isoc_enter(struct usbd_xfer *xfer) |
3440 | { | | 3440 | { |
3441 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); | | 3441 | struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer); |
3442 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 3442 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
3443 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3443 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3444 | ohci_soft_ed_t *sed = opipe->sed; | | 3444 | ohci_soft_ed_t *sed = opipe->sed; |
3445 | ohci_soft_itd_t *sitd, *nsitd, *tail; | | 3445 | ohci_soft_itd_t *sitd, *nsitd, *tail; |
3446 | ohci_physaddr_t buf, offs, noffs, bp0; | | 3446 | ohci_physaddr_t buf, offs, noffs, bp0; |
3447 | int i, ncur, nframes; | | 3447 | int i, ncur, nframes; |
3448 | | | 3448 | |
3449 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3449 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3450 | DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 3450 | DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
3451 | | | 3451 | |
3452 | mutex_enter(&sc->sc_lock); | | 3452 | mutex_enter(&sc->sc_lock); |
3453 | | | 3453 | |
3454 | if (sc->sc_dying) { | | 3454 | if (sc->sc_dying) { |
3455 | mutex_exit(&sc->sc_lock); | | 3455 | mutex_exit(&sc->sc_lock); |
3456 | return; | | 3456 | return; |
3457 | } | | 3457 | } |
3458 | | | 3458 | |
3459 | struct isoc *isoc = &opipe->isoc; | | 3459 | struct isoc *isoc = &opipe->isoc; |
3460 | | | 3460 | |
3461 | DPRINTFN(1, "used=%jd next=%jd xfer=%#jx nframes=%jd", | | 3461 | DPRINTFN(1, "used=%jd next=%jd xfer=%#jx nframes=%jd", |
3462 | isoc->inuse, isoc->next, (uintptr_t)xfer, xfer->ux_nframes); | | 3462 | isoc->inuse, isoc->next, (uintptr_t)xfer, xfer->ux_nframes); |
3463 | | | 3463 | |
3464 | if (isoc->next == -1) { | | 3464 | if (isoc->next == -1) { |
3465 | /* Not in use yet, schedule it a few frames ahead. */ | | 3465 | /* Not in use yet, schedule it a few frames ahead. */ |
3466 | isoc->next = O32TOH(sc->sc_hcca->hcca_frame_number) + 5; | | 3466 | isoc->next = O32TOH(sc->sc_hcca->hcca_frame_number) + 5; |
3467 | DPRINTFN(2,"start next=%jd", isoc->next, 0, 0, 0); | | 3467 | DPRINTFN(2,"start next=%jd", isoc->next, 0, 0, 0); |
3468 | } | | 3468 | } |
3469 | | | 3469 | |
3470 | sitd = opipe->tail.itd; | | 3470 | sitd = opipe->tail.itd; |
3471 | opipe->tail.itd = ox->ox_sitds[0]; | | 3471 | opipe->tail.itd = ox->ox_sitds[0]; |
3472 | ox->ox_sitds[0] = sitd; | | 3472 | ox->ox_sitds[0] = sitd; |
3473 | | | 3473 | |
3474 | buf = DMAADDR(&xfer->ux_dmabuf, 0); | | 3474 | buf = DMAADDR(&xfer->ux_dmabuf, 0); |
3475 | bp0 = OHCI_PAGE(buf); | | 3475 | bp0 = OHCI_PAGE(buf); |
3476 | offs = OHCI_PAGE_OFFSET(buf); | | 3476 | offs = OHCI_PAGE_OFFSET(buf); |
3477 | nframes = xfer->ux_nframes; | | 3477 | nframes = xfer->ux_nframes; |
3478 | xfer->ux_hcpriv = sitd; | | 3478 | xfer->ux_hcpriv = sitd; |
3479 | size_t j = 1; | | 3479 | size_t j = 1; |
3480 | for (i = ncur = 0; i < nframes; i++, ncur++) { | | 3480 | for (i = ncur = 0; i < nframes; i++, ncur++) { |
3481 | noffs = offs + xfer->ux_frlengths[i]; | | 3481 | noffs = offs + xfer->ux_frlengths[i]; |
3482 | if (ncur == OHCI_ITD_NOFFSET || /* all offsets used */ | | 3482 | if (ncur == OHCI_ITD_NOFFSET || /* all offsets used */ |
3483 | OHCI_PAGE(buf + noffs) > bp0 + OHCI_PAGE_SIZE) { /* too many page crossings */ | | 3483 | OHCI_PAGE(buf + noffs) > bp0 + OHCI_PAGE_SIZE) { /* too many page crossings */ |
3484 | | | 3484 | |
3485 | /* Allocate next ITD */ | | 3485 | /* Allocate next ITD */ |
3486 | nsitd = ox->ox_sitds[j++]; | | 3486 | nsitd = ox->ox_sitds[j++]; |
3487 | KASSERT(nsitd != NULL); | | 3487 | KASSERT(nsitd != NULL); |
3488 | KASSERT(j < ox->ox_nsitd); | | 3488 | KASSERT(j < ox->ox_nsitd); |
3489 | | | 3489 | |
3490 | /* Fill current ITD */ | | 3490 | /* Fill current ITD */ |
3491 | sitd->itd.itd_flags = HTOO32( | | 3491 | sitd->itd.itd_flags = HTOO32( |
3492 | OHCI_ITD_NOCC | | | 3492 | OHCI_ITD_NOCC | |
3493 | OHCI_ITD_SET_SF(isoc->next) | | | 3493 | OHCI_ITD_SET_SF(isoc->next) | |
3494 | OHCI_ITD_SET_DI(6) | /* delay intr a little */ | | 3494 | OHCI_ITD_SET_DI(6) | /* delay intr a little */ |
3495 | OHCI_ITD_SET_FC(ncur)); | | 3495 | OHCI_ITD_SET_FC(ncur)); |
3496 | sitd->itd.itd_bp0 = HTOO32(bp0); | | 3496 | sitd->itd.itd_bp0 = HTOO32(bp0); |
3497 | sitd->itd.itd_nextitd = HTOO32(nsitd->physaddr); | | 3497 | sitd->itd.itd_nextitd = HTOO32(nsitd->physaddr); |
3498 | sitd->itd.itd_be = HTOO32(bp0 + offs - 1); | | 3498 | sitd->itd.itd_be = HTOO32(bp0 + offs - 1); |
3499 | sitd->nextitd = nsitd; | | 3499 | sitd->nextitd = nsitd; |
3500 | sitd->xfer = xfer; | | 3500 | sitd->xfer = xfer; |
3501 | sitd->flags = 0; | | 3501 | sitd->flags = 0; |
3502 | #ifdef DIAGNOSTIC | | 3502 | #ifdef DIAGNOSTIC |
3503 | sitd->isdone = false; | | 3503 | sitd->isdone = false; |
3504 | #endif | | 3504 | #endif |
3505 | ohci_hash_add_itd(sc, sitd); | | 3505 | ohci_hash_add_itd(sc, sitd); |
3506 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), | | 3506 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), |
3507 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3507 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3508 | | | 3508 | |
3509 | sitd = nsitd; | | 3509 | sitd = nsitd; |
3510 | isoc->next = isoc->next + ncur; | | 3510 | isoc->next = isoc->next + ncur; |
3511 | bp0 = OHCI_PAGE(buf + offs); | | 3511 | bp0 = OHCI_PAGE(buf + offs); |
3512 | ncur = 0; | | 3512 | ncur = 0; |
3513 | } | | 3513 | } |
3514 | sitd->itd.itd_offset[ncur] = HTOO16(OHCI_ITD_MK_OFFS(offs)); | | 3514 | sitd->itd.itd_offset[ncur] = HTOO16(OHCI_ITD_MK_OFFS(offs)); |
3515 | /* XXX Sync */ | | | |
3516 | offs = noffs; | | 3515 | offs = noffs; |
3517 | } | | 3516 | } |
3518 | KASSERT(j <= ox->ox_nsitd); | | 3517 | KASSERT(j <= ox->ox_nsitd); |
3519 | | | 3518 | |
3520 | /* point at sentinel */ | | 3519 | /* point at sentinel */ |
3521 | tail = opipe->tail.itd; | | 3520 | tail = opipe->tail.itd; |
3522 | memset(&tail->itd, 0, sizeof(tail->itd)); | | 3521 | memset(&tail->itd, 0, sizeof(tail->itd)); |
3523 | tail->nextitd = NULL; | | 3522 | tail->nextitd = NULL; |
3524 | tail->xfer = NULL; | | 3523 | tail->xfer = NULL; |
3525 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->itd), | | 3524 | usb_syncmem(&tail->dma, tail->offs, sizeof(tail->itd), |
3526 | BUS_DMASYNC_PREWRITE); | | 3525 | BUS_DMASYNC_PREWRITE); |
3527 | | | 3526 | |
3528 | /* Fixup last used ITD */ | | 3527 | /* Fixup last used ITD */ |
3529 | sitd->itd.itd_flags = HTOO32( | | 3528 | sitd->itd.itd_flags = HTOO32( |
3530 | OHCI_ITD_NOCC | | | 3529 | OHCI_ITD_NOCC | |
3531 | OHCI_ITD_SET_SF(isoc->next) | | | 3530 | OHCI_ITD_SET_SF(isoc->next) | |
3532 | OHCI_ITD_SET_DI(0) | | | 3531 | OHCI_ITD_SET_DI(0) | |
3533 | OHCI_ITD_SET_FC(ncur)); | | 3532 | OHCI_ITD_SET_FC(ncur)); |
3534 | sitd->itd.itd_bp0 = HTOO32(bp0); | | 3533 | sitd->itd.itd_bp0 = HTOO32(bp0); |
3535 | sitd->itd.itd_nextitd = HTOO32(tail->physaddr); | | 3534 | sitd->itd.itd_nextitd = HTOO32(tail->physaddr); |
3536 | sitd->itd.itd_be = HTOO32(bp0 + offs - 1); | | 3535 | sitd->itd.itd_be = HTOO32(bp0 + offs - 1); |
3537 | sitd->nextitd = tail; | | 3536 | sitd->nextitd = tail; |
3538 | sitd->xfer = xfer; | | 3537 | sitd->xfer = xfer; |
3539 | sitd->flags = OHCI_CALL_DONE; | | 3538 | sitd->flags = OHCI_CALL_DONE; |
3540 | #ifdef DIAGNOSTIC | | 3539 | #ifdef DIAGNOSTIC |
3541 | sitd->isdone = false; | | 3540 | sitd->isdone = false; |
3542 | #endif | | 3541 | #endif |
3543 | ohci_hash_add_itd(sc, sitd); | | 3542 | ohci_hash_add_itd(sc, sitd); |
3544 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), | | 3543 | usb_syncmem(&sitd->dma, sitd->offs, sizeof(sitd->itd), |
3545 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3544 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3546 | | | 3545 | |
3547 | isoc->next = isoc->next + ncur; | | 3546 | isoc->next = isoc->next + ncur; |
3548 | isoc->inuse += nframes; | | 3547 | isoc->inuse += nframes; |
3549 | | | 3548 | |
3550 | /* XXX pretend we did it all */ | | 3549 | /* XXX pretend we did it all */ |
3551 | xfer->ux_actlen = offs; | | 3550 | xfer->ux_actlen = offs; |
3552 | xfer->ux_status = USBD_IN_PROGRESS; | | 3551 | xfer->ux_status = USBD_IN_PROGRESS; |
3553 | | | 3552 | |
3554 | #ifdef OHCI_DEBUG | | 3553 | #ifdef OHCI_DEBUG |
3555 | if (ohcidebug >= 5) { | | 3554 | if (ohcidebug >= 5) { |
3556 | DPRINTF("frame=%jd", O32TOH(sc->sc_hcca->hcca_frame_number), | | 3555 | DPRINTF("frame=%jd", O32TOH(sc->sc_hcca->hcca_frame_number), |
3557 | 0, 0, 0); | | 3556 | 0, 0, 0); |
3558 | ohci_dump_itds(sc, xfer->ux_hcpriv); | | 3557 | ohci_dump_itds(sc, xfer->ux_hcpriv); |
3559 | ohci_dump_ed(sc, sed); | | 3558 | ohci_dump_ed(sc, sed); |
3560 | } | | 3559 | } |
3561 | #endif | | 3560 | #endif |
3562 | | | 3561 | |
3563 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3562 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3564 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3563 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3565 | sed->ed.ed_tailp = HTOO32(tail->physaddr); | | 3564 | sed->ed.ed_tailp = HTOO32(tail->physaddr); |
3566 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); | | 3565 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); |
3567 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | | 3566 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), |
3568 | sizeof(sed->ed.ed_flags), | | 3567 | sizeof(sed->ed.ed_flags), |
3569 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3568 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3570 | mutex_exit(&sc->sc_lock); | | 3569 | mutex_exit(&sc->sc_lock); |
3571 | } | | 3570 | } |
3572 | | | 3571 | |
3573 | void | | 3572 | void |
3574 | ohci_device_isoc_abort(struct usbd_xfer *xfer) | | 3573 | ohci_device_isoc_abort(struct usbd_xfer *xfer) |
3575 | { | | 3574 | { |
3576 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); | | 3575 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe); |
3577 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); | | 3576 | ohci_softc_t *sc = OHCI_XFER2SC(xfer); |
3578 | ohci_soft_ed_t *sed; | | 3577 | ohci_soft_ed_t *sed; |
3579 | ohci_soft_itd_t *sitd; | | 3578 | ohci_soft_itd_t *sitd; |
3580 | | | 3579 | |
3581 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3580 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3582 | DPRINTFN(1, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 3581 | DPRINTFN(1, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
3583 | | | 3582 | |
3584 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3583 | KASSERT(mutex_owned(&sc->sc_lock)); |
3585 | | | 3584 | |
3586 | /* Transfer is already done. */ | | 3585 | /* Transfer is already done. */ |
3587 | if (xfer->ux_status != USBD_NOT_STARTED && | | 3586 | if (xfer->ux_status != USBD_NOT_STARTED && |
3588 | xfer->ux_status != USBD_IN_PROGRESS) { | | 3587 | xfer->ux_status != USBD_IN_PROGRESS) { |
3589 | printf("ohci_device_isoc_abort: early return\n"); | | 3588 | printf("ohci_device_isoc_abort: early return\n"); |
3590 | goto done; | | 3589 | goto done; |
3591 | } | | 3590 | } |
3592 | | | 3591 | |
3593 | /* Give xfer the requested abort code. */ | | 3592 | /* Give xfer the requested abort code. */ |
3594 | xfer->ux_status = USBD_CANCELLED; | | 3593 | xfer->ux_status = USBD_CANCELLED; |
3595 | | | 3594 | |
3596 | sed = opipe->sed; | | 3595 | sed = opipe->sed; |
3597 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3596 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3598 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); | | 3597 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
3599 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); /* force hardware skip */ | | 3598 | sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP); /* force hardware skip */ |
3600 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), | | 3599 | usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), |
3601 | sizeof(sed->ed.ed_flags), | | 3600 | sizeof(sed->ed.ed_flags), |
3602 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3601 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3603 | | | 3602 | |
3604 | sitd = xfer->ux_hcpriv; | | 3603 | sitd = xfer->ux_hcpriv; |
3605 | KASSERT(sitd); | | 3604 | KASSERT(sitd); |
3606 | | | 3605 | |
3607 | usb_delay_ms_locked(&sc->sc_bus, OHCI_ITD_NOFFSET, &sc->sc_lock); | | 3606 | usb_delay_ms_locked(&sc->sc_bus, OHCI_ITD_NOFFSET, &sc->sc_lock); |
3608 | | | 3607 | |
3609 | for (; sitd->xfer == xfer; sitd = sitd->nextitd) { | | 3608 | for (; sitd->xfer == xfer; sitd = sitd->nextitd) { |
3610 | ohci_hash_rem_itd(sc, sitd); | | 3609 | ohci_hash_rem_itd(sc, sitd); |
3611 | #ifdef DIAGNOSTIC | | 3610 | #ifdef DIAGNOSTIC |
3612 | DPRINTFN(1, "abort sets done sitd=%#jx", (uintptr_t)sitd, | | 3611 | DPRINTFN(1, "abort sets done sitd=%#jx", (uintptr_t)sitd, |
3613 | 0, 0, 0); | | 3612 | 0, 0, 0); |
3614 | sitd->isdone = true; | | 3613 | sitd->isdone = true; |
3615 | #endif | | 3614 | #endif |
3616 | } | | 3615 | } |
3617 | | | 3616 | |
3618 | /* Run callback. */ | | 3617 | /* Run callback. */ |
3619 | usb_transfer_complete(xfer); | | 3618 | usb_transfer_complete(xfer); |
3620 | | | 3619 | |
3621 | sed->ed.ed_headp = HTOO32(sitd->physaddr); /* unlink TDs */ | | 3620 | sed->ed.ed_headp = HTOO32(sitd->physaddr); /* unlink TDs */ |
3622 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); /* remove hardware skip */ | | 3621 | sed->ed.ed_flags &= HTOO32(~OHCI_ED_SKIP); /* remove hardware skip */ |
3623 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), | | 3622 | usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), |
3624 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | | 3623 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
3625 | | | 3624 | |
3626 | done: | | 3625 | done: |
3627 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3626 | KASSERT(mutex_owned(&sc->sc_lock)); |
3628 | } | | 3627 | } |
3629 | | | 3628 | |
3630 | void | | 3629 | void |
3631 | ohci_device_isoc_done(struct usbd_xfer *xfer) | | 3630 | ohci_device_isoc_done(struct usbd_xfer *xfer) |
3632 | { | | 3631 | { |
3633 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3632 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3634 | DPRINTFN(1, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); | | 3633 | DPRINTFN(1, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0); |
3635 | } | | 3634 | } |
3636 | | | 3635 | |
3637 | usbd_status | | 3636 | usbd_status |
3638 | ohci_setup_isoc(struct usbd_pipe *pipe) | | 3637 | ohci_setup_isoc(struct usbd_pipe *pipe) |
3639 | { | | 3638 | { |
3640 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 3639 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
3641 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 3640 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
3642 | struct isoc *isoc = &opipe->isoc; | | 3641 | struct isoc *isoc = &opipe->isoc; |
3643 | | | 3642 | |
3644 | isoc->next = -1; | | 3643 | isoc->next = -1; |
3645 | isoc->inuse = 0; | | 3644 | isoc->inuse = 0; |
3646 | | | 3645 | |
3647 | mutex_enter(&sc->sc_lock); | | 3646 | mutex_enter(&sc->sc_lock); |
3648 | ohci_add_ed(sc, opipe->sed, sc->sc_isoc_head); | | 3647 | ohci_add_ed(sc, opipe->sed, sc->sc_isoc_head); |
3649 | mutex_exit(&sc->sc_lock); | | 3648 | mutex_exit(&sc->sc_lock); |
3650 | | | 3649 | |
3651 | return USBD_NORMAL_COMPLETION; | | 3650 | return USBD_NORMAL_COMPLETION; |
3652 | } | | 3651 | } |
3653 | | | 3652 | |
3654 | void | | 3653 | void |
3655 | ohci_device_isoc_close(struct usbd_pipe *pipe) | | 3654 | ohci_device_isoc_close(struct usbd_pipe *pipe) |
3656 | { | | 3655 | { |
3657 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); | | 3656 | struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(pipe); |
3658 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); | | 3657 | ohci_softc_t *sc = OHCI_PIPE2SC(pipe); |
3659 | | | 3658 | |
3660 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3659 | KASSERT(mutex_owned(&sc->sc_lock)); |
3661 | | | 3660 | |
3662 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); | | 3661 | OHCIHIST_FUNC(); OHCIHIST_CALLED(); |
3663 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); | | 3662 | DPRINTF("pipe=%#jx", (uintptr_t)pipe, 0, 0, 0); |
3664 | ohci_close_pipe(pipe, sc->sc_isoc_head); | | 3663 | ohci_close_pipe(pipe, sc->sc_isoc_head); |
3665 | #ifdef DIAGNOSTIC | | 3664 | #ifdef DIAGNOSTIC |
3666 | opipe->tail.itd->isdone = true; | | 3665 | opipe->tail.itd->isdone = true; |
3667 | #endif | | 3666 | #endif |
3668 | ohci_free_sitd_locked(sc, opipe->tail.itd); | | 3667 | ohci_free_sitd_locked(sc, opipe->tail.itd); |
3669 | } | | 3668 | } |