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