| @@ -1,1581 +1,1582 @@ | | | @@ -1,1581 +1,1582 @@ |
1 | /* $NetBSD: ahci.c,v 1.22 2020/04/05 20:59:38 skrll Exp $ */ | | 1 | /* $NetBSD: ahci.c,v 1.23 2021/01/05 16:30:37 skrll Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. | | 4 | * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or | | 7 | * Redistribution and use in source and binary forms, with or |
8 | * without modification, are permitted provided that the following | | 8 | * without modification, are permitted provided that the following |
9 | * conditions are met: | | 9 | * conditions are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above | | 12 | * 2. Redistributions in binary form must reproduce the above |
13 | * copyright notice, this list of conditions and the following | | 13 | * copyright notice, this list of conditions and the following |
14 | * disclaimer in the documentation and/or other materials provided | | 14 | * disclaimer in the documentation and/or other materials provided |
15 | * with the distribution. | | 15 | * with the distribution. |
16 | * 3. The names of the authors may not be used to endorse or promote | | 16 | * 3. The names of the authors may not be used to endorse or promote |
17 | * products derived from this software without specific prior | | 17 | * products derived from this software without specific prior |
18 | * written permission. | | 18 | * written permission. |
19 | * | | 19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY | | 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY |
21 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | | 21 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
22 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | | 22 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
23 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS | | 23 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
25 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | | 25 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
26 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | | 26 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, |
27 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 27 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | | 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR |
29 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | | 29 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
30 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY | | 30 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
31 | * OF SUCH DAMAGE. | | 31 | * OF SUCH DAMAGE. |
32 | */ | | 32 | */ |
33 | /* | | 33 | /* |
34 | * Copyright (c) 2001 The NetBSD Foundation, Inc. | | 34 | * Copyright (c) 2001 The NetBSD Foundation, Inc. |
35 | * All rights reserved. | | 35 | * All rights reserved. |
36 | * | | 36 | * |
37 | * This code is derived from software contributed to The NetBSD Foundation | | 37 | * This code is derived from software contributed to The NetBSD Foundation |
38 | * by Tetsuya Isaki. | | 38 | * by Tetsuya Isaki. |
39 | * | | 39 | * |
40 | * Redistribution and use in source and binary forms, with or without | | 40 | * Redistribution and use in source and binary forms, with or without |
41 | * modification, are permitted provided that the following conditions | | 41 | * modification, are permitted provided that the following conditions |
42 | * are met: | | 42 | * are met: |
43 | * 1. Redistributions of source code must retain the above copyright | | 43 | * 1. Redistributions of source code must retain the above copyright |
44 | * notice, this list of conditions and the following disclaimer. | | 44 | * notice, this list of conditions and the following disclaimer. |
45 | * 2. Redistributions in binary form must reproduce the above copyright | | 45 | * 2. Redistributions in binary form must reproduce the above copyright |
46 | * notice, this list of conditions and the following disclaimer in the | | 46 | * notice, this list of conditions and the following disclaimer in the |
47 | * documentation and/or other materials provided with the distribution. | | 47 | * documentation and/or other materials provided with the distribution. |
48 | * | | 48 | * |
49 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 49 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
50 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 50 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
51 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 51 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
52 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 52 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
53 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 53 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
54 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 54 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
55 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 55 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
56 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 56 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
57 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 57 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
58 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 58 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
59 | * POSSIBILITY OF SUCH DAMAGE. | | 59 | * POSSIBILITY OF SUCH DAMAGE. |
60 | */ | | 60 | */ |
61 | | | 61 | |
62 | /* | | 62 | /* |
63 | * !! HIGHLY EXPERIMENTAL CODE !! | | 63 | * !! HIGHLY EXPERIMENTAL CODE !! |
64 | */ | | 64 | */ |
65 | | | 65 | |
66 | #include <sys/cdefs.h> | | 66 | #include <sys/cdefs.h> |
67 | __KERNEL_RCSID(0, "$NetBSD: ahci.c,v 1.22 2020/04/05 20:59:38 skrll Exp $"); | | 67 | __KERNEL_RCSID(0, "$NetBSD: ahci.c,v 1.23 2021/01/05 16:30:37 skrll Exp $"); |
68 | | | 68 | |
69 | #include <sys/param.h> | | 69 | #include <sys/param.h> |
70 | #include <sys/systm.h> | | 70 | #include <sys/systm.h> |
71 | #include <sys/kernel.h> | | 71 | #include <sys/kernel.h> |
72 | #include <sys/proc.h> | | 72 | #include <sys/proc.h> |
73 | #include <sys/device.h> | | 73 | #include <sys/device.h> |
74 | #include <sys/kmem.h> | | 74 | #include <sys/kmem.h> |
75 | | | 75 | |
76 | #include <sys/bus.h> | | 76 | #include <sys/bus.h> |
77 | #include <machine/cpu.h> | | 77 | #include <machine/cpu.h> |
78 | | | 78 | |
79 | #include <dev/usb/usb.h> | | 79 | #include <dev/usb/usb.h> |
80 | #include <dev/usb/usbdi.h> | | 80 | #include <dev/usb/usbdi.h> |
81 | #include <dev/usb/usbdivar.h> | | 81 | #include <dev/usb/usbdivar.h> |
82 | #include <dev/usb/usb_mem.h> | | 82 | #include <dev/usb/usb_mem.h> |
83 | #include <dev/usb/usbdevs.h> | | 83 | #include <dev/usb/usbdevs.h> |
84 | #include <dev/usb/usbroothub.h> | | 84 | #include <dev/usb/usbroothub.h> |
85 | | | 85 | |
86 | #include <mips/adm5120/include/adm5120reg.h> | | 86 | #include <mips/adm5120/include/adm5120reg.h> |
87 | #include <mips/adm5120/include/adm5120var.h> | | 87 | #include <mips/adm5120/include/adm5120var.h> |
88 | #include <mips/adm5120/include/adm5120_obiovar.h> | | 88 | #include <mips/adm5120/include/adm5120_obiovar.h> |
89 | | | 89 | |
90 | #include <mips/adm5120/dev/ahcireg.h> | | 90 | #include <mips/adm5120/dev/ahcireg.h> |
91 | #include <mips/adm5120/dev/ahcivar.h> | | 91 | #include <mips/adm5120/dev/ahcivar.h> |
92 | | | 92 | |
93 | static usbd_status ahci_open(struct usbd_pipe *); | | 93 | static usbd_status ahci_open(struct usbd_pipe *); |
94 | static void ahci_softintr(void *); | | 94 | static void ahci_softintr(void *); |
95 | static void ahci_poll(struct usbd_bus *); | | 95 | static void ahci_poll(struct usbd_bus *); |
96 | static void ahci_poll_hub(void *); | | 96 | static void ahci_poll_hub(void *); |
97 | static void ahci_poll_device(void *arg); | | 97 | static void ahci_poll_device(void *arg); |
98 | static struct usbd_xfer * | | 98 | static struct usbd_xfer * |
99 | ahci_allocx(struct usbd_bus *, unsigned int); | | 99 | ahci_allocx(struct usbd_bus *, unsigned int); |
100 | static void ahci_freex(struct usbd_bus *, struct usbd_xfer *); | | 100 | static void ahci_freex(struct usbd_bus *, struct usbd_xfer *); |
101 | static void ahci_abortx(struct usbd_xfer *); | | 101 | static void ahci_abortx(struct usbd_xfer *); |
102 | | | 102 | |
103 | static void ahci_get_lock(struct usbd_bus *, kmutex_t **); | | 103 | static void ahci_get_lock(struct usbd_bus *, kmutex_t **); |
104 | static int ahci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *, | | 104 | static int ahci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *, |
105 | void *, int); | | 105 | void *, int); |
106 | | | 106 | |
107 | static usbd_status ahci_root_intr_transfer(struct usbd_xfer *); | | 107 | static usbd_status ahci_root_intr_transfer(struct usbd_xfer *); |
108 | static usbd_status ahci_root_intr_start(struct usbd_xfer *); | | 108 | static usbd_status ahci_root_intr_start(struct usbd_xfer *); |
109 | static void ahci_root_intr_abort(struct usbd_xfer *); | | 109 | static void ahci_root_intr_abort(struct usbd_xfer *); |
110 | static void ahci_root_intr_close(struct usbd_pipe *); | | 110 | static void ahci_root_intr_close(struct usbd_pipe *); |
111 | static void ahci_root_intr_done(struct usbd_xfer *); | | 111 | static void ahci_root_intr_done(struct usbd_xfer *); |
112 | | | 112 | |
113 | static usbd_status ahci_device_ctrl_transfer(struct usbd_xfer *); | | 113 | static usbd_status ahci_device_ctrl_transfer(struct usbd_xfer *); |
114 | static usbd_status ahci_device_ctrl_start(struct usbd_xfer *); | | 114 | static usbd_status ahci_device_ctrl_start(struct usbd_xfer *); |
115 | static void ahci_device_ctrl_abort(struct usbd_xfer *); | | 115 | static void ahci_device_ctrl_abort(struct usbd_xfer *); |
116 | static void ahci_device_ctrl_close(struct usbd_pipe *); | | 116 | static void ahci_device_ctrl_close(struct usbd_pipe *); |
117 | static void ahci_device_ctrl_done(struct usbd_xfer *); | | 117 | static void ahci_device_ctrl_done(struct usbd_xfer *); |
118 | | | 118 | |
119 | static usbd_status ahci_device_intr_transfer(struct usbd_xfer *); | | 119 | static usbd_status ahci_device_intr_transfer(struct usbd_xfer *); |
120 | static usbd_status ahci_device_intr_start(struct usbd_xfer *); | | 120 | static usbd_status ahci_device_intr_start(struct usbd_xfer *); |
121 | static void ahci_device_intr_abort(struct usbd_xfer *); | | 121 | static void ahci_device_intr_abort(struct usbd_xfer *); |
122 | static void ahci_device_intr_close(struct usbd_pipe *); | | 122 | static void ahci_device_intr_close(struct usbd_pipe *); |
123 | static void ahci_device_intr_done(struct usbd_xfer *); | | 123 | static void ahci_device_intr_done(struct usbd_xfer *); |
124 | | | 124 | |
125 | static usbd_status ahci_device_isoc_transfer(struct usbd_xfer *); | | 125 | static usbd_status ahci_device_isoc_transfer(struct usbd_xfer *); |
126 | static usbd_status ahci_device_isoc_start(struct usbd_xfer *); | | 126 | static usbd_status ahci_device_isoc_start(struct usbd_xfer *); |
127 | static void ahci_device_isoc_abort(struct usbd_xfer *); | | 127 | static void ahci_device_isoc_abort(struct usbd_xfer *); |
128 | static void ahci_device_isoc_close(struct usbd_pipe *); | | 128 | static void ahci_device_isoc_close(struct usbd_pipe *); |
129 | static void ahci_device_isoc_done(struct usbd_xfer *); | | 129 | static void ahci_device_isoc_done(struct usbd_xfer *); |
130 | | | 130 | |
131 | static usbd_status ahci_device_bulk_transfer(struct usbd_xfer *); | | 131 | static usbd_status ahci_device_bulk_transfer(struct usbd_xfer *); |
132 | static usbd_status ahci_device_bulk_start(struct usbd_xfer *); | | 132 | static usbd_status ahci_device_bulk_start(struct usbd_xfer *); |
133 | static void ahci_device_bulk_abort(struct usbd_xfer *); | | 133 | static void ahci_device_bulk_abort(struct usbd_xfer *); |
134 | static void ahci_device_bulk_close(struct usbd_pipe *); | | 134 | static void ahci_device_bulk_close(struct usbd_pipe *); |
135 | static void ahci_device_bulk_done(struct usbd_xfer *); | | 135 | static void ahci_device_bulk_done(struct usbd_xfer *); |
136 | | | 136 | |
137 | static int ahci_transaction(struct ahci_softc *, | | 137 | static int ahci_transaction(struct ahci_softc *, |
138 | struct usbd_pipe *, uint8_t, int, u_char *, uint8_t); | | 138 | struct usbd_pipe *, uint8_t, int, u_char *, uint8_t); |
139 | static void ahci_noop(struct usbd_pipe *); | | 139 | static void ahci_noop(struct usbd_pipe *); |
140 | static void ahci_device_clear_toggle(struct usbd_pipe *); | | 140 | static void ahci_device_clear_toggle(struct usbd_pipe *); |
141 | | | 141 | |
142 | extern int usbdebug; | | 142 | extern int usbdebug; |
143 | extern int uhubdebug; | | 143 | extern int uhubdebug; |
144 | extern int umassdebug; | | 144 | extern int umassdebug; |
145 | int ahci_dummy; | | 145 | int ahci_dummy; |
146 | | | 146 | |
147 | #define AHCI_DEBUG | | 147 | #define AHCI_DEBUG |
148 | | | 148 | |
149 | #ifdef AHCI_DEBUG | | 149 | #ifdef AHCI_DEBUG |
150 | #define D_TRACE (0x0001) /* function trace */ | | 150 | #define D_TRACE (0x0001) /* function trace */ |
151 | #define D_MSG (0x0002) /* debug messages */ | | 151 | #define D_MSG (0x0002) /* debug messages */ |
152 | #define D_XFER (0x0004) /* transfer messages (noisy!) */ | | 152 | #define D_XFER (0x0004) /* transfer messages (noisy!) */ |
153 | #define D_MEM (0x0008) /* memory allocation */ | | 153 | #define D_MEM (0x0008) /* memory allocation */ |
154 | | | 154 | |
155 | int ahci_debug = 0; | | 155 | int ahci_debug = 0; |
156 | #define DPRINTF(z,x) if((ahci_debug&(z))!=0)printf x | | 156 | #define DPRINTF(z,x) if((ahci_debug&(z))!=0)printf x |
157 | void print_req(usb_device_request_t *); | | 157 | void print_req(usb_device_request_t *); |
158 | void print_req_hub(usb_device_request_t *); | | 158 | void print_req_hub(usb_device_request_t *); |
159 | void print_dumpreg(struct ahci_softc *); | | 159 | void print_dumpreg(struct ahci_softc *); |
160 | void print_xfer(struct usbd_xfer *); | | 160 | void print_xfer(struct usbd_xfer *); |
161 | #else | | 161 | #else |
162 | #define DPRINTF(z,x) | | 162 | #define DPRINTF(z,x) |
163 | #endif | | 163 | #endif |
164 | | | 164 | |
165 | | | 165 | |
166 | struct usbd_bus_methods ahci_bus_methods = { | | 166 | struct usbd_bus_methods ahci_bus_methods = { |
167 | .ubm_open = ahci_open, | | 167 | .ubm_open = ahci_open, |
168 | .ubm_softint = ahci_softintr, | | 168 | .ubm_softint = ahci_softintr, |
169 | .ubm_dopoll = ahci_poll, | | 169 | .ubm_dopoll = ahci_poll, |
170 | .ubm_allocx = ahci_allocx, | | 170 | .ubm_allocx = ahci_allocx, |
171 | .ubm_freex = ahci_freex, | | 171 | .ubm_freex = ahci_freex, |
172 | .ubm_abortx = ahci_abortx, | | 172 | .ubm_abortx = ahci_abortx, |
173 | .ubm_getlock = ahci_get_lock, | | 173 | .ubm_getlock = ahci_get_lock, |
174 | .ubm_rhctrl = ahci_roothub_ctrl, | | 174 | .ubm_rhctrl = ahci_roothub_ctrl, |
175 | }; | | 175 | }; |
176 | | | 176 | |
177 | struct usbd_pipe_methods ahci_root_intr_methods = { | | 177 | struct usbd_pipe_methods ahci_root_intr_methods = { |
178 | .upm_transfer = ahci_root_intr_transfer, | | 178 | .upm_transfer = ahci_root_intr_transfer, |
179 | .upm_start = ahci_root_intr_start, | | 179 | .upm_start = ahci_root_intr_start, |
180 | .upm_abort = ahci_root_intr_abort, | | 180 | .upm_abort = ahci_root_intr_abort, |
181 | .upm_close = ahci_root_intr_close, | | 181 | .upm_close = ahci_root_intr_close, |
182 | .upm_cleartoggle = ahci_noop, | | 182 | .upm_cleartoggle = ahci_noop, |
183 | .upm_done = ahci_root_intr_done, | | 183 | .upm_done = ahci_root_intr_done, |
184 | }; | | 184 | }; |
185 | | | 185 | |
186 | struct usbd_pipe_methods ahci_device_ctrl_methods = { | | 186 | struct usbd_pipe_methods ahci_device_ctrl_methods = { |
187 | .upm_transfer = ahci_device_ctrl_transfer, | | 187 | .upm_transfer = ahci_device_ctrl_transfer, |
188 | .upm_start = ahci_device_ctrl_start, | | 188 | .upm_start = ahci_device_ctrl_start, |
189 | .upm_abort = ahci_device_ctrl_abort, | | 189 | .upm_abort = ahci_device_ctrl_abort, |
190 | .upm_close = ahci_device_ctrl_close, | | 190 | .upm_close = ahci_device_ctrl_close, |
191 | .upm_cleartoggle = ahci_noop, | | 191 | .upm_cleartoggle = ahci_noop, |
192 | .upm_done = ahci_device_ctrl_done, | | 192 | .upm_done = ahci_device_ctrl_done, |
193 | }; | | 193 | }; |
194 | | | 194 | |
195 | struct usbd_pipe_methods ahci_device_intr_methods = { | | 195 | struct usbd_pipe_methods ahci_device_intr_methods = { |
196 | .upm_transfer = ahci_device_intr_transfer, | | 196 | .upm_transfer = ahci_device_intr_transfer, |
197 | .upm_start = ahci_device_intr_start, | | 197 | .upm_start = ahci_device_intr_start, |
198 | .upm_abort = ahci_device_intr_abort, | | 198 | .upm_abort = ahci_device_intr_abort, |
199 | .upm_close = ahci_device_intr_close, | | 199 | .upm_close = ahci_device_intr_close, |
200 | .upm_cleartoggle = ahci_device_clear_toggle, | | 200 | .upm_cleartoggle = ahci_device_clear_toggle, |
201 | .upm_done = ahci_device_intr_done, | | 201 | .upm_done = ahci_device_intr_done, |
202 | }; | | 202 | }; |
203 | | | 203 | |
204 | struct usbd_pipe_methods ahci_device_isoc_methods = { | | 204 | struct usbd_pipe_methods ahci_device_isoc_methods = { |
205 | .upm_transfer = ahci_device_isoc_transfer, | | 205 | .upm_transfer = ahci_device_isoc_transfer, |
206 | .upm_start = ahci_device_isoc_start, | | 206 | .upm_start = ahci_device_isoc_start, |
207 | .upm_abort = ahci_device_isoc_abort, | | 207 | .upm_abort = ahci_device_isoc_abort, |
208 | .upm_close = ahci_device_isoc_close, | | 208 | .upm_close = ahci_device_isoc_close, |
209 | .upm_cleartoggle = ahci_noop, | | 209 | .upm_cleartoggle = ahci_noop, |
210 | .upm_done = ahci_device_isoc_done, | | 210 | .upm_done = ahci_device_isoc_done, |
211 | }; | | 211 | }; |
212 | | | 212 | |
213 | struct usbd_pipe_methods ahci_device_bulk_methods = { | | 213 | struct usbd_pipe_methods ahci_device_bulk_methods = { |
214 | .upm_transfer = ahci_device_bulk_transfer, | | 214 | .upm_transfer = ahci_device_bulk_transfer, |
215 | .upm_start = ahci_device_bulk_start, | | 215 | .upm_start = ahci_device_bulk_start, |
216 | .upm_abort = ahci_device_bulk_abort, | | 216 | .upm_abort = ahci_device_bulk_abort, |
217 | .upm_close = ahci_device_bulk_close, | | 217 | .upm_close = ahci_device_bulk_close, |
218 | .upm_cleartoggle = ahci_device_clear_toggle, | | 218 | .upm_cleartoggle = ahci_device_clear_toggle, |
219 | .upm_done = ahci_device_bulk_done, | | 219 | .upm_done = ahci_device_bulk_done, |
220 | }; | | 220 | }; |
221 | | | 221 | |
222 | struct ahci_pipe { | | 222 | struct ahci_pipe { |
223 | struct usbd_pipe pipe; | | 223 | struct usbd_pipe pipe; |
224 | uint32_t toggle; | | 224 | uint32_t toggle; |
225 | }; | | 225 | }; |
226 | | | 226 | |
227 | static int ahci_match(device_t, cfdata_t, void *); | | 227 | static int ahci_match(device_t, cfdata_t, void *); |
228 | static void ahci_attach(device_t, device_t, void *); | | 228 | static void ahci_attach(device_t, device_t, void *); |
229 | | | 229 | |
230 | CFATTACH_DECL_NEW(ahci, sizeof(struct ahci_softc), | | 230 | CFATTACH_DECL_NEW(ahci, sizeof(struct ahci_softc), |
231 | ahci_match, ahci_attach, NULL, NULL); | | 231 | ahci_match, ahci_attach, NULL, NULL); |
232 | | | 232 | |
233 | static int | | 233 | static int |
234 | ahci_match(device_t parent, struct cfdata *cf, void *aux) | | 234 | ahci_match(device_t parent, struct cfdata *cf, void *aux) |
235 | { | | 235 | { |
236 | struct obio_attach_args *aa = aux; | | 236 | struct obio_attach_args *aa = aux; |
237 | | | 237 | |
238 | if (strcmp(aa->oba_name, cf->cf_name) == 0) | | 238 | if (strcmp(aa->oba_name, cf->cf_name) == 0) |
239 | return 1; | | 239 | return 1; |
240 | | | 240 | |
241 | return 0; | | 241 | return 0; |
242 | } | | 242 | } |
243 | | | 243 | |
244 | #define REG_READ(o) bus_space_read_4(sc->sc_st, sc->sc_ioh, (o)) | | 244 | #define REG_READ(o) bus_space_read_4(sc->sc_st, sc->sc_ioh, (o)) |
245 | #define REG_WRITE(o,v) bus_space_write_4(sc->sc_st, sc->sc_ioh, (o),(v)) | | 245 | #define REG_WRITE(o,v) bus_space_write_4(sc->sc_st, sc->sc_ioh, (o),(v)) |
246 | | | 246 | |
247 | /* | | 247 | /* |
248 | * Attach SL11H/SL811HS. Return 0 if success. | | 248 | * Attach SL11H/SL811HS. Return 0 if success. |
249 | */ | | 249 | */ |
250 | void | | 250 | void |
251 | ahci_attach(device_t parent, device_t self, void *aux) | | 251 | ahci_attach(device_t parent, device_t self, void *aux) |
252 | { | | 252 | { |
253 | struct obio_attach_args *aa = aux; | | 253 | struct obio_attach_args *aa = aux; |
254 | struct ahci_softc *sc = device_private(self); | | 254 | struct ahci_softc *sc = device_private(self); |
255 | | | 255 | |
256 | printf("\n"); | | 256 | printf("\n"); |
257 | sc->sc_dmat = aa->oba_dt; | | 257 | sc->sc_dmat = aa->oba_dt; |
258 | sc->sc_st = aa->oba_st; | | 258 | sc->sc_st = aa->oba_st; |
259 | | | 259 | |
260 | /* Initialize sc */ | | 260 | /* Initialize sc */ |
261 | sc->sc_bus.ub_revision = USBREV_1_1; | | 261 | sc->sc_bus.ub_revision = USBREV_1_1; |
262 | sc->sc_bus.ub_methods = &ahci_bus_methods; | | 262 | sc->sc_bus.ub_methods = &ahci_bus_methods; |
263 | sc->sc_bus.ub_pipesize = sizeof(struct ahci_pipe); | | 263 | sc->sc_bus.ub_pipesize = sizeof(struct ahci_pipe); |
264 | sc->sc_bus.ub_dmatag = sc->sc_dmat; | | 264 | sc->sc_bus.ub_dmatag = sc->sc_dmat; |
265 | sc->sc_bus.ub_usedma = true; | | 265 | sc->sc_bus.ub_usedma = true; |
266 | | | 266 | |
267 | /* Map the device. */ | | 267 | /* Map the device. */ |
268 | if (bus_space_map(sc->sc_st, aa->oba_addr, | | 268 | if (bus_space_map(sc->sc_st, aa->oba_addr, |
269 | 512, 0, &sc->sc_ioh) != 0) { | | 269 | 512, 0, &sc->sc_ioh) != 0) { |
270 | aprint_error_dev(self, "unable to map device\n"); | | 270 | aprint_error_dev(self, "unable to map device\n"); |
271 | return; | | 271 | return; |
272 | } | | 272 | } |
273 | | | 273 | |
274 | /* Hook up the interrupt handler. */ | | 274 | /* Hook up the interrupt handler. */ |
275 | sc->sc_ih = adm5120_intr_establish(aa->oba_irq, INTR_IRQ, ahci_intr, sc); | | 275 | sc->sc_ih = adm5120_intr_establish(aa->oba_irq, INTR_IRQ, ahci_intr, sc); |
276 | | | 276 | |
277 | if (sc->sc_ih == NULL) { | | 277 | if (sc->sc_ih == NULL) { |
278 | aprint_error_dev(self, | | 278 | aprint_error_dev(self, |
279 | "unable to register interrupt handler\n"); | | 279 | "unable to register interrupt handler\n"); |
280 | return; | | 280 | return; |
281 | } | | 281 | } |
282 | | | 282 | |
283 | SIMPLEQ_INIT(&sc->sc_free_xfers); | | 283 | SIMPLEQ_INIT(&sc->sc_free_xfers); |
284 | | | 284 | |
285 | callout_init(&sc->sc_poll_handle, 0); | | 285 | callout_init(&sc->sc_poll_handle, 0); |
286 | callout_setfunc(&sc->sc_poll_handle, ahci_poll_hub, sc); | | 286 | callout_setfunc(&sc->sc_poll_handle, ahci_poll_hub, sc); |
287 | | | 287 | |
288 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | | 288 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); |
289 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED /* XXXNH */); | | 289 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED /* XXXNH */); |
290 | | | 290 | |
291 | REG_WRITE(ADMHCD_REG_INTENABLE, 0); /* disable interrupts */ | | 291 | REG_WRITE(ADMHCD_REG_INTENABLE, 0); /* disable interrupts */ |
292 | REG_WRITE(ADMHCD_REG_CONTROL, ADMHCD_SW_RESET); /* reset */ | | 292 | REG_WRITE(ADMHCD_REG_CONTROL, ADMHCD_SW_RESET); /* reset */ |
293 | delay_ms(10); | | 293 | delay_ms(10); |
294 | while (REG_READ(ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET) | | 294 | while (REG_READ(ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET) |
295 | delay_ms(1); | | 295 | delay_ms(1); |
296 | | | 296 | |
297 | REG_WRITE(ADMHCD_REG_CONTROL, ADMHCD_HOST_EN); | | 297 | REG_WRITE(ADMHCD_REG_CONTROL, ADMHCD_HOST_EN); |
298 | REG_WRITE(ADMHCD_REG_HOSTHEAD, 0x00000000); | | 298 | REG_WRITE(ADMHCD_REG_HOSTHEAD, 0x00000000); |
299 | REG_WRITE(ADMHCD_REG_FMINTERVAL, 0x20002edf); | | 299 | REG_WRITE(ADMHCD_REG_FMINTERVAL, 0x20002edf); |
300 | REG_WRITE(ADMHCD_REG_LSTHRESH, 0x628); | | 300 | REG_WRITE(ADMHCD_REG_LSTHRESH, 0x628); |
301 | REG_WRITE(ADMHCD_REG_RHDESCR, ADMHCD_NPS | ADMHCD_LPSC); | | 301 | REG_WRITE(ADMHCD_REG_RHDESCR, ADMHCD_NPS | ADMHCD_LPSC); |
302 | REG_WRITE(ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP); | | 302 | REG_WRITE(ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP); |
303 | | | 303 | |
304 | REG_WRITE(ADMHCD_REG_INTENABLE, 0); /* XXX: enable interrupts */ | | 304 | REG_WRITE(ADMHCD_REG_INTENABLE, 0); /* XXX: enable interrupts */ |
305 | | | 305 | |
306 | #ifdef USB_DEBUG | | 306 | #ifdef USB_DEBUG |
307 | /* usbdebug = 0x7f; | | 307 | /* usbdebug = 0x7f; |
308 | uhubdebug = 0x7f; | | 308 | uhubdebug = 0x7f; |
309 | umassdebug = 0xffffffff; */ | | 309 | umassdebug = 0xffffffff; */ |
310 | #endif | | 310 | #endif |
311 | | | 311 | |
312 | /* Attach USB devices */ | | 312 | /* Attach USB devices */ |
313 | sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint); | | 313 | sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint); |
314 | | | 314 | |
315 | } | | 315 | } |
316 | | | 316 | |
317 | int | | 317 | int |
318 | ahci_intr(void *arg) | | 318 | ahci_intr(void *arg) |
319 | { | | 319 | { |
320 | #if 0 | | 320 | #if 0 |
321 | struct ahci_softc *sc = arg; | | 321 | struct ahci_softc *sc = arg; |
322 | uint8_t r; | | 322 | uint8_t r; |
323 | #ifdef AHCI_DEBUG | | 323 | #ifdef AHCI_DEBUG |
324 | char bitbuf[256]; | | 324 | char bitbuf[256]; |
325 | #endif | | 325 | #endif |
326 | | | 326 | |
327 | r = sl11read(sc, SL11_ISR); | | 327 | r = sl11read(sc, SL11_ISR); |
328 | | | 328 | |
329 | sl11write(sc, SL11_ISR, SL11_ISR_DATA | SL11_ISR_SOFTIMER); | | 329 | sl11write(sc, SL11_ISR, SL11_ISR_DATA | SL11_ISR_SOFTIMER); |
330 | | | 330 | |
331 | if ((r & SL11_ISR_RESET)) { | | 331 | if ((r & SL11_ISR_RESET)) { |
332 | sc->sc_flags |= AHCDF_RESET; | | 332 | sc->sc_flags |= AHCDF_RESET; |
333 | sl11write(sc, SL11_ISR, SL11_ISR_RESET); | | 333 | sl11write(sc, SL11_ISR, SL11_ISR_RESET); |
334 | } | | 334 | } |
335 | if ((r & SL11_ISR_INSERT)) { | | 335 | if ((r & SL11_ISR_INSERT)) { |
336 | sc->sc_flags |= AHCDF_INSERT; | | 336 | sc->sc_flags |= AHCDF_INSERT; |
337 | sl11write(sc, SL11_ISR, SL11_ISR_INSERT); | | 337 | sl11write(sc, SL11_ISR, SL11_ISR_INSERT); |
338 | } | | 338 | } |
339 | | | 339 | |
340 | #ifdef AHCI_DEBUG | | 340 | #ifdef AHCI_DEBUG |
341 | snprintb(bitbuf, sizeof(bitbuf), | | 341 | snprintb(bitbuf, sizeof(bitbuf), |
342 | ((sl11read(sc, SL11_CTRL) & SL11_CTRL_SUSPEND) | | 342 | ((sl11read(sc, SL11_CTRL) & SL11_CTRL_SUSPEND) |
343 | ? "\20\x8""D+\7RESUME\6INSERT\5SOF\4res\3""BABBLE\2USBB\1USBA" | | 343 | ? "\20\x8""D+\7RESUME\6INSERT\5SOF\4res\3""BABBLE\2USBB\1USBA" |
344 | : "\20\x8""D+\7RESET\6INSERT\5SOF\4res\3""BABBLE\2USBB\1USBA"), | | 344 | : "\20\x8""D+\7RESET\6INSERT\5SOF\4res\3""BABBLE\2USBB\1USBA"), |
345 | r); | | 345 | r); |
346 | | | 346 | |
347 | DPRINTF(D_XFER, ("I=%s ", bitbuf)); | | 347 | DPRINTF(D_XFER, ("I=%s ", bitbuf)); |
348 | #endif /* AHCI_DEBUG */ | | 348 | #endif /* AHCI_DEBUG */ |
349 | #endif | | 349 | #endif |
350 | | | 350 | |
351 | return 0; | | 351 | return 0; |
352 | } | | 352 | } |
353 | | | 353 | |
354 | usbd_status | | 354 | usbd_status |
355 | ahci_open(struct usbd_pipe *pipe) | | 355 | ahci_open(struct usbd_pipe *pipe) |
356 | { | | 356 | { |
357 | struct usbd_device *dev = pipe->up_dev; | | 357 | struct usbd_device *dev = pipe->up_dev; |
358 | struct ahci_pipe *apipe = (struct ahci_pipe *)pipe; | | 358 | struct ahci_pipe *apipe = (struct ahci_pipe *)pipe; |
359 | usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc; | | 359 | usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc; |
360 | uint8_t rhaddr = dev->ud_bus->ub_rhaddr; | | 360 | uint8_t rhaddr = dev->ud_bus->ub_rhaddr; |
361 | | | 361 | |
362 | DPRINTF(D_TRACE, ("ahci_open(addr=%d,ep=%d,scaddr=%d)", | | 362 | DPRINTF(D_TRACE, ("ahci_open(addr=%d,ep=%d,scaddr=%d)", |
363 | dev->ud_addr, ed->bEndpointAddress, rhaddr)); | | 363 | dev->ud_addr, ed->bEndpointAddress, rhaddr)); |
364 | | | 364 | |
365 | apipe->toggle=0; | | 365 | apipe->toggle=0; |
366 | | | 366 | |
367 | if (dev->ud_addr == rhaddr) { | | 367 | if (dev->ud_addr == rhaddr) { |
368 | switch (ed->bEndpointAddress) { | | 368 | switch (ed->bEndpointAddress) { |
369 | case USB_CONTROL_ENDPOINT: | | 369 | case USB_CONTROL_ENDPOINT: |
370 | pipe->up_methods = &roothub_ctrl_methods; | | 370 | pipe->up_methods = &roothub_ctrl_methods; |
371 | break; | | 371 | break; |
372 | case UE_DIR_IN | USBROOTHUB_INTR_ENDPT: | | 372 | case UE_DIR_IN | USBROOTHUB_INTR_ENDPT: |
373 | pipe->up_methods = &ahci_root_intr_methods; | | 373 | pipe->up_methods = &ahci_root_intr_methods; |
374 | break; | | 374 | break; |
375 | default: | | 375 | default: |
376 | printf("open:endpointErr!\n"); | | 376 | printf("open:endpointErr!\n"); |
377 | return USBD_INVAL; | | 377 | return USBD_INVAL; |
378 | } | | 378 | } |
379 | } else { | | 379 | } else { |
380 | switch (ed->bmAttributes & UE_XFERTYPE) { | | 380 | switch (ed->bmAttributes & UE_XFERTYPE) { |
381 | case UE_CONTROL: | | 381 | case UE_CONTROL: |
382 | DPRINTF(D_MSG, ("control ")); | | 382 | DPRINTF(D_MSG, ("control ")); |
383 | pipe->up_methods = &ahci_device_ctrl_methods; | | 383 | pipe->up_methods = &ahci_device_ctrl_methods; |
384 | break; | | 384 | break; |
385 | case UE_INTERRUPT: | | 385 | case UE_INTERRUPT: |
386 | DPRINTF(D_MSG, ("interrupt ")); | | 386 | DPRINTF(D_MSG, ("interrupt ")); |
387 | pipe->up_methods = &ahci_device_intr_methods; | | 387 | pipe->up_methods = &ahci_device_intr_methods; |
388 | break; | | 388 | break; |
389 | case UE_ISOCHRONOUS: | | 389 | case UE_ISOCHRONOUS: |
390 | DPRINTF(D_MSG, ("isochronous ")); | | 390 | DPRINTF(D_MSG, ("isochronous ")); |
391 | pipe->up_methods = &ahci_device_isoc_methods; | | 391 | pipe->up_methods = &ahci_device_isoc_methods; |
392 | break; | | 392 | break; |
393 | case UE_BULK: | | 393 | case UE_BULK: |
394 | DPRINTF(D_MSG, ("bluk ")); | | 394 | DPRINTF(D_MSG, ("bluk ")); |
395 | pipe->up_methods = &ahci_device_bulk_methods; | | 395 | pipe->up_methods = &ahci_device_bulk_methods; |
396 | break; | | 396 | break; |
397 | } | | 397 | } |
398 | } | | 398 | } |
399 | return USBD_NORMAL_COMPLETION; | | 399 | return USBD_NORMAL_COMPLETION; |
400 | } | | 400 | } |
401 | | | 401 | |
402 | void | | 402 | void |
403 | ahci_softintr(void *arg) | | 403 | ahci_softintr(void *arg) |
404 | { | | 404 | { |
405 | DPRINTF(D_TRACE, ("%s()", __func__)); | | 405 | DPRINTF(D_TRACE, ("%s()", __func__)); |
406 | } | | 406 | } |
407 | | | 407 | |
408 | void | | 408 | void |
409 | ahci_poll(struct usbd_bus *bus) | | 409 | ahci_poll(struct usbd_bus *bus) |
410 | { | | 410 | { |
411 | DPRINTF(D_TRACE, ("%s()", __func__)); | | 411 | DPRINTF(D_TRACE, ("%s()", __func__)); |
412 | } | | 412 | } |
413 | | | 413 | |
414 | #define AHCI_BUS2SC(bus) ((bus)->ub_hcpriv) | | 414 | #define AHCI_BUS2SC(bus) ((bus)->ub_hcpriv) |
415 | #define AHCI_PIPE2SC(pipe) AHCI_BUS2SC((pipe)->up_dev->ud_bus) | | 415 | #define AHCI_PIPE2SC(pipe) AHCI_BUS2SC((pipe)->up_dev->ud_bus) |
416 | #define AHCI_XFER2SC(xfer) AHCI_BUS2SC((xfer)->ux_bus) | | 416 | #define AHCI_XFER2SC(xfer) AHCI_BUS2SC((xfer)->ux_bus) |
417 | #define AHCI_APIPE2SC(ap) AHCI_BUS2SC((d)->pipe.up_dev->ud_bus) | | 417 | #define AHCI_APIPE2SC(ap) AHCI_BUS2SC((d)->pipe.up_dev->ud_bus) |
418 | | | 418 | |
419 | /* | | 419 | /* |
420 | * Emulation of interrupt transfer for status change endpoint | | 420 | * Emulation of interrupt transfer for status change endpoint |
421 | * of root hub. | | 421 | * of root hub. |
422 | */ | | 422 | */ |
423 | void | | 423 | void |
424 | ahci_poll_hub(void *arg) | | 424 | ahci_poll_hub(void *arg) |
425 | { | | 425 | { |
426 | struct ahci_softc *sc = arg; | | 426 | struct ahci_softc *sc = arg; |
427 | struct usbd_xfer *xfer; | | 427 | struct usbd_xfer *xfer; |
428 | u_char *p; | | 428 | u_char *p; |
429 | static int p0_state=0; | | 429 | static int p0_state=0; |
430 | static int p1_state=0; | | 430 | static int p1_state=0; |
431 | | | 431 | |
432 | mutex_enter(&sc->sc_lock); | | 432 | mutex_enter(&sc->sc_lock); |
433 | | | 433 | |
434 | /* | | 434 | /* |
435 | * If the intr xfer has completed or been synchronously | | 435 | * If the intr xfer has completed or been synchronously |
436 | * aborted, we have nothing to do. | | 436 | * aborted, we have nothing to do. |
437 | */ | | 437 | */ |
438 | xfer = sc->sc_intr_xfer; | | 438 | xfer = sc->sc_intr_xfer; |
439 | if (xfer == NULL) | | 439 | if (xfer == NULL) |
440 | goto out; | | 440 | goto out; |
441 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); | | 441 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); |
442 | | | 442 | |
443 | /* | | 443 | /* |
444 | * If the intr xfer for which we were scheduled is done, and | | 444 | * If the intr xfer for which we were scheduled is done, and |
445 | * another intr xfer has been submitted, let that one be dealt | | 445 | * another intr xfer has been submitted, let that one be dealt |
446 | * with when the callout fires again. | | 446 | * with when the callout fires again. |
447 | * | | 447 | * |
448 | * The call to callout_pending is racy, but the the transition | | 448 | * The call to callout_pending is racy, but the the transition |
449 | * from pending to invoking happens atomically. The | | 449 | * from pending to invoking happens atomically. The |
450 | * callout_ack ensures callout_invoking does not return true | | 450 | * callout_ack ensures callout_invoking does not return true |
451 | * due to this invocation of the callout; the lock ensures the | | 451 | * due to this invocation of the callout; the lock ensures the |
452 | * next invocation of the callout cannot callout_ack (unless it | | 452 | * next invocation of the callout cannot callout_ack (unless it |
453 | * had already run to completion and nulled sc->sc_intr_xfer, | | 453 | * had already run to completion and nulled sc->sc_intr_xfer, |
454 | * in which case would have bailed out already). | | 454 | * in which case would have bailed out already). |
455 | */ | | 455 | */ |
456 | callout_ack(&sc->sc_poll_handle); | | 456 | callout_ack(&sc->sc_poll_handle); |
457 | if (callout_pending(&sc->sc_poll_handle) || | | 457 | if (callout_pending(&sc->sc_poll_handle) || |
458 | callout_invoking(&sc->sc_poll_handle)) | | 458 | callout_invoking(&sc->sc_poll_handle)) |
459 | goto out; | | 459 | goto out; |
460 | | | 460 | |
461 | /* USB spec 11.13.3 (p.260) */ | | 461 | /* USB spec 11.13.3 (p.260) */ |
462 | p = KERNADDR(&xfer->ux_dmabuf, 0); | | 462 | p = KERNADDR(&xfer->ux_dmabuf, 0); |
463 | p[0] = 0; | | 463 | p[0] = 0; |
464 | if ((REG_READ(ADMHCD_REG_PORTSTATUS0) & ADMHCD_CCS) != p0_state) { | | 464 | if ((REG_READ(ADMHCD_REG_PORTSTATUS0) & ADMHCD_CCS) != p0_state) { |
465 | p[0] = 2; | | 465 | p[0] = 2; |
466 | DPRINTF(D_TRACE, ("!")); | | 466 | DPRINTF(D_TRACE, ("!")); |
467 | p0_state=(REG_READ(ADMHCD_REG_PORTSTATUS0) & ADMHCD_CCS); | | 467 | p0_state=(REG_READ(ADMHCD_REG_PORTSTATUS0) & ADMHCD_CCS); |
468 | }; | | 468 | }; |
469 | if ((REG_READ(ADMHCD_REG_PORTSTATUS1) & ADMHCD_CCS) != p1_state) { | | 469 | if ((REG_READ(ADMHCD_REG_PORTSTATUS1) & ADMHCD_CCS) != p1_state) { |
470 | p[0] = 2; | | 470 | p[0] = 2; |
471 | DPRINTF(D_TRACE, ("@")); | | 471 | DPRINTF(D_TRACE, ("@")); |
472 | p1_state=(REG_READ(ADMHCD_REG_PORTSTATUS1) & ADMHCD_CCS); | | 472 | p1_state=(REG_READ(ADMHCD_REG_PORTSTATUS1) & ADMHCD_CCS); |
473 | }; | | 473 | }; |
474 | | | 474 | |
475 | /* no change, return NAK and try again later */ | | 475 | /* no change, return NAK and try again later */ |
476 | if (p[0] == 0) { | | 476 | if (p[0] == 0) { |
477 | callout_schedule(&sc->sc_poll_handle, sc->sc_interval); | | 477 | callout_schedule(&sc->sc_poll_handle, sc->sc_interval); |
478 | goto out; | | 478 | goto out; |
479 | } | | 479 | } |
480 | | | 480 | |
481 | /* | | 481 | /* |
482 | * Interrupt completed, and the xfer has not been completed or | | 482 | * Interrupt completed, and the xfer has not been completed or |
483 | * synchronously aborted. Complete the xfer now. | | 483 | * synchronously aborted. Complete the xfer now. |
484 | * | | 484 | * |
485 | * XXX Set ux_isdone if DIAGNOSTIC? | | 485 | * XXX Set ux_isdone if DIAGNOSTIC? |
486 | */ | | 486 | */ |
487 | xfer->ux_actlen = 1; | | 487 | xfer->ux_actlen = 1; |
488 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 488 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
489 | usb_transfer_complete(xfer); | | 489 | usb_transfer_complete(xfer); |
490 | | | 490 | |
491 | out: mutex_exit(&sc->sc_lock); | | 491 | out: mutex_exit(&sc->sc_lock); |
492 | } | | 492 | } |
493 | | | 493 | |
494 | struct usbd_xfer * | | 494 | struct usbd_xfer * |
495 | ahci_allocx(struct usbd_bus *bus, unsigned int nframes) | | 495 | ahci_allocx(struct usbd_bus *bus, unsigned int nframes) |
496 | { | | 496 | { |
497 | struct ahci_softc *sc = AHCI_BUS2SC(bus); | | 497 | struct ahci_softc *sc = AHCI_BUS2SC(bus); |
498 | struct usbd_xfer *xfer; | | 498 | struct usbd_xfer *xfer; |
499 | | | 499 | |
500 | DPRINTF(D_MEM, ("SLallocx")); | | 500 | DPRINTF(D_MEM, ("SLallocx")); |
501 | | | 501 | |
502 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); | | 502 | xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers); |
503 | if (xfer) { | | 503 | if (xfer) { |
504 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, ux_next); | | 504 | SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, ux_next); |
505 | #ifdef DIAGNOSTIC | | 505 | #ifdef DIAGNOSTIC |
506 | if (xfer->ux_state != XFER_FREE) { | | 506 | if (xfer->ux_state != XFER_FREE) { |
507 | printf("ahci_allocx: xfer=%p not free, 0x%08x\n", | | 507 | printf("ahci_allocx: xfer=%p not free, 0x%08x\n", |
508 | xfer, xfer->ux_state); | | 508 | xfer, xfer->ux_state); |
509 | } | | 509 | } |
510 | #endif | | 510 | #endif |
511 | } else { | | 511 | } else { |
512 | xfer = kmem_alloc(sizeof(*xfer), KM_SLEEP); | | 512 | xfer = kmem_alloc(sizeof(*xfer), KM_SLEEP); |
513 | } | | 513 | } |
514 | | | 514 | |
515 | memset(xfer, 0, sizeof(*xfer)); | | 515 | memset(xfer, 0, sizeof(*xfer)); |
516 | #ifdef DIAGNOSTIC | | 516 | #ifdef DIAGNOSTIC |
517 | xfer->ux_state = XFER_BUSY; | | 517 | xfer->ux_state = XFER_BUSY; |
518 | #endif | | 518 | #endif |
519 | | | 519 | |
520 | return xfer; | | 520 | return xfer; |
521 | } | | 521 | } |
522 | | | 522 | |
523 | void | | 523 | void |
524 | ahci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) | | 524 | ahci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer) |
525 | { | | 525 | { |
526 | struct ahci_softc *sc = AHCI_BUS2SC(bus); | | 526 | struct ahci_softc *sc = AHCI_BUS2SC(bus); |
527 | | | 527 | |
528 | DPRINTF(D_MEM, ("SLfreex")); | | 528 | DPRINTF(D_MEM, ("SLfreex")); |
529 | | | 529 | |
530 | #ifdef DIAGNOSTIC | | 530 | #ifdef DIAGNOSTIC |
531 | if (xfer->ux_state != XFER_BUSY && | | 531 | if (xfer->ux_state != XFER_BUSY && |
532 | xfer->ux_status != USBD_NOT_STARTED) { | | 532 | xfer->ux_status != USBD_NOT_STARTED) { |
533 | printf("ahci_freex: xfer=%p not busy, 0x%08x\n", | | 533 | printf("ahci_freex: xfer=%p not busy, 0x%08x\n", |
534 | xfer, xfer->ux_state); | | 534 | xfer, xfer->ux_state); |
535 | return; | | 535 | return; |
536 | } | | 536 | } |
537 | xfer->ux_state = XFER_FREE; | | 537 | xfer->ux_state = XFER_FREE; |
538 | #endif | | 538 | #endif |
539 | SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, ux_next); | | 539 | SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, ux_next); |
540 | } | | 540 | } |
541 | | | 541 | |
542 | static void | | 542 | static void |
543 | ahci_get_lock(struct usbd_bus *bus, kmutex_t **lock) | | 543 | ahci_get_lock(struct usbd_bus *bus, kmutex_t **lock) |
544 | { | | 544 | { |
545 | struct ahci_softc *sc = AHCI_BUS2SC(bus); | | 545 | struct ahci_softc *sc = AHCI_BUS2SC(bus); |
546 | | | 546 | |
547 | *lock = &sc->sc_lock; | | 547 | *lock = &sc->sc_lock; |
548 | } | | 548 | } |
549 | | | 549 | |
550 | void | | 550 | void |
551 | ahci_noop(struct usbd_pipe *pipe) | | 551 | ahci_noop(struct usbd_pipe *pipe) |
552 | { | | 552 | { |
553 | DPRINTF(D_TRACE, ("%s()", __func__)); | | 553 | DPRINTF(D_TRACE, ("%s()", __func__)); |
554 | } | | 554 | } |
555 | | | 555 | |
556 | /* | | 556 | /* |
557 | * Data structures and routines to emulate the root hub. | | 557 | * Data structures and routines to emulate the root hub. |
558 | */ | | 558 | */ |
559 | | | 559 | |
560 | static int | | 560 | static int |
561 | ahci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req, | | 561 | ahci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req, |
562 | void *buf, int buflen) | | 562 | void *buf, int buflen) |
563 | { | | 563 | { |
564 | struct ahci_softc *sc = AHCI_BUS2SC(bus); | | 564 | struct ahci_softc *sc = AHCI_BUS2SC(bus); |
565 | uint16_t len, value, index; | | 565 | uint16_t len, value, index; |
566 | usb_port_status_t ps; | | 566 | usb_port_status_t ps; |
567 | int totlen = 0; | | 567 | int totlen = 0; |
568 | int status; | | 568 | int status; |
569 | | | 569 | |
570 | DPRINTF(D_TRACE, ("SLRCstart ")); | | 570 | DPRINTF(D_TRACE, ("SLRCstart ")); |
571 | | | 571 | |
572 | len = UGETW(req->wLength); | | 572 | len = UGETW(req->wLength); |
573 | value = UGETW(req->wValue); | | 573 | value = UGETW(req->wValue); |
574 | index = UGETW(req->wIndex); | | 574 | index = UGETW(req->wIndex); |
575 | | | 575 | |
576 | #define C(x,y) ((x) | ((y) << 8)) | | 576 | #define C(x,y) ((x) | ((y) << 8)) |
577 | switch (C(req->bRequest, req->bmRequestType)) { | | 577 | switch (C(req->bRequest, req->bmRequestType)) { |
578 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): | | 578 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): |
579 | switch (value) { | | 579 | switch (value) { |
580 | #define sd ((usb_string_descriptor_t *)buf) | | 580 | #define sd ((usb_string_descriptor_t *)buf) |
581 | case C(2, UDESC_STRING): | | 581 | case C(2, UDESC_STRING): |
582 | /* Product */ | | 582 | /* Product */ |
583 | totlen = usb_makestrdesc(sd, len, "ADM5120 root hub"); | | 583 | totlen = usb_makestrdesc(sd, len, "ADM5120 root hub"); |
584 | break; | | 584 | break; |
585 | default: | | 585 | default: |
586 | printf("unknownGetDescriptor=%x", value); | | 586 | printf("unknownGetDescriptor=%x", value); |
587 | /* FALLTHROUGH */ | | 587 | /* FALLTHROUGH */ |
588 | case C(0, UDESC_DEVICE): | | 588 | case C(0, UDESC_DEVICE): |
589 | case C(1, UDESC_STRING): | | 589 | case C(1, UDESC_STRING): |
590 | /* default from usbroothub */ | | 590 | /* default from usbroothub */ |
591 | return buflen; | | 591 | return buflen; |
592 | } | | 592 | } |
593 | break; | | 593 | break; |
594 | /* | | 594 | /* |
595 | * Hub specific requests | | 595 | * Hub specific requests |
596 | */ | | 596 | */ |
597 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): | | 597 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): |
598 | /* Clear Hub Feature, 11.16.2.1, not supported */ | | 598 | /* Clear Hub Feature, 11.16.2.1, not supported */ |
599 | DPRINTF(D_MSG, ("ClearHubFeature not supported\n")); | | 599 | DPRINTF(D_MSG, ("ClearHubFeature not supported\n")); |
600 | break; | | 600 | break; |
601 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): | | 601 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): |
602 | | | 602 | |
603 | #define WPS(x) REG_WRITE(ADMHCD_REG_PORTSTATUS0+(index-1)*4, (x)) | | 603 | #define WPS(x) REG_WRITE(ADMHCD_REG_PORTSTATUS0+(index-1)*4, (x)) |
604 | /* Clear Port Feature, 11.16.2.2 */ | | 604 | /* Clear Port Feature, 11.16.2.2 */ |
605 | if (index != 1 && index != 2 ) { | | 605 | if (index != 1 && index != 2 ) { |
606 | return -1; | | 606 | return -1; |
607 | } | | 607 | } |
608 | switch (value) { | | 608 | switch (value) { |
609 | case UHF_PORT_POWER: | | 609 | case UHF_PORT_POWER: |
610 | DPRINTF(D_MSG, ("POWER_OFF ")); | | 610 | DPRINTF(D_MSG, ("POWER_OFF ")); |
611 | WPS(ADMHCD_LSDA); | | 611 | WPS(ADMHCD_LSDA); |
612 | break; | | 612 | break; |
613 | case UHF_PORT_SUSPEND: | | 613 | case UHF_PORT_SUSPEND: |
614 | DPRINTF(D_MSG, ("SUSPEND ")); | | 614 | DPRINTF(D_MSG, ("SUSPEND ")); |
615 | WPS(ADMHCD_POCI); | | 615 | WPS(ADMHCD_POCI); |
616 | break; | | 616 | break; |
617 | case UHF_PORT_ENABLE: | | 617 | case UHF_PORT_ENABLE: |
618 | DPRINTF(D_MSG, ("ENABLE ")); | | 618 | DPRINTF(D_MSG, ("ENABLE ")); |
619 | WPS(ADMHCD_CCS); | | 619 | WPS(ADMHCD_CCS); |
620 | break; | | 620 | break; |
621 | case UHF_C_PORT_CONNECTION: | | 621 | case UHF_C_PORT_CONNECTION: |
622 | WPS(ADMHCD_CSC); | | 622 | WPS(ADMHCD_CSC); |
623 | break; | | 623 | break; |
624 | case UHF_C_PORT_RESET: | | 624 | case UHF_C_PORT_RESET: |
625 | WPS(ADMHCD_PRSC); | | 625 | WPS(ADMHCD_PRSC); |
626 | break; | | 626 | break; |
627 | case UHF_C_PORT_SUSPEND: | | 627 | case UHF_C_PORT_SUSPEND: |
628 | WPS(ADMHCD_PSSC); | | 628 | WPS(ADMHCD_PSSC); |
629 | break; | | 629 | break; |
630 | case UHF_C_PORT_ENABLE: | | 630 | case UHF_C_PORT_ENABLE: |
631 | WPS(ADMHCD_PESC); | | 631 | WPS(ADMHCD_PESC); |
632 | break; | | 632 | break; |
633 | case UHF_C_PORT_OVER_CURRENT: | | 633 | case UHF_C_PORT_OVER_CURRENT: |
634 | WPS(ADMHCD_OCIC); | | 634 | WPS(ADMHCD_OCIC); |
635 | break; | | 635 | break; |
636 | default: | | 636 | default: |
637 | printf("ClrPortFeatERR:value=0x%x ", value); | | 637 | printf("ClrPortFeatERR:value=0x%x ", value); |
638 | return -1; | | 638 | return -1; |
639 | } | | 639 | } |
640 | //DPRINTF(D_XFER, ("CH=%04x ", sc->sc_change)); | | 640 | //DPRINTF(D_XFER, ("CH=%04x ", sc->sc_change)); |
641 | #undef WPS | | 641 | #undef WPS |
642 | break; | | 642 | break; |
643 | case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER): | | 643 | case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER): |
644 | /* Get Bus State, 11.16.2.3, not supported */ | | 644 | /* Get Bus State, 11.16.2.3, not supported */ |
645 | /* shall return a STALL... */ | | 645 | /* shall return a STALL... */ |
646 | break; | | 646 | break; |
647 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): | | 647 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): |
648 | /* Get Hub Descriptor, 11.16.2.4 */ | | 648 | /* Get Hub Descriptor, 11.16.2.4 */ |
649 | DPRINTF(D_MSG, ("UR_GET_DESCRIPTOR RCD")); | | 649 | DPRINTF(D_MSG, ("UR_GET_DESCRIPTOR RCD")); |
650 | if ((value&0xff) != 0) { | | 650 | if ((value&0xff) != 0) { |
651 | return -1; | | 651 | return -1; |
652 | } | | 652 | } |
653 | usb_hub_descriptor_t hubd; | | 653 | usb_hub_descriptor_t hubd; |
654 | | | 654 | |
655 | totlen = uimin(buflen, sizeof(hubd)); | | 655 | totlen = uimin(buflen, sizeof(hubd)); |
656 | memcpy(&hubd, buf, totlen); | | 656 | memcpy(&hubd, buf, totlen); |
657 | hubd.bNbrPorts = 2; | | 657 | hubd.bNbrPorts = 2; |
658 | USETW(hubd.wHubCharacteristics, 0); | | 658 | USETW(hubd.wHubCharacteristics, 0); |
659 | hubd.bPwrOn2PwrGood = 0; | | 659 | hubd.bPwrOn2PwrGood = 0; |
660 | memcpy(buf, &hubd, totlen); | | 660 | memcpy(buf, &hubd, totlen); |
661 | break; | | 661 | break; |
662 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): | | 662 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): |
663 | /* Get Hub Status, 11.16.2.5 */ | | 663 | /* Get Hub Status, 11.16.2.5 */ |
664 | DPRINTF(D_MSG, ("UR_GET_STATUS RCD")); | | 664 | DPRINTF(D_MSG, ("UR_GET_STATUS RCD")); |
665 | if (len != 4) { | | 665 | if (len != 4) { |
666 | return -1; | | 666 | return -1; |
667 | } | | 667 | } |
668 | memset(buf, 0, len); | | 668 | memset(buf, 0, len); |
669 | totlen = len; | | 669 | totlen = len; |
670 | break; | | 670 | break; |
671 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): | | 671 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): |
672 | /* Get Port Status, 11.16.2.6 */ | | 672 | /* Get Port Status, 11.16.2.6 */ |
673 | if ((index != 1 && index != 2) || len != 4) { | | 673 | if ((index != 1 && index != 2) || len != 4) { |
674 | printf("index=%d,len=%d ", index, len); | | 674 | printf("index=%d,len=%d ", index, len); |
675 | return -1; | | 675 | return -1; |
676 | } | | 676 | } |
677 | status = REG_READ(ADMHCD_REG_PORTSTATUS0+(index-1)*4); | | 677 | status = REG_READ(ADMHCD_REG_PORTSTATUS0+(index-1)*4); |
678 | DPRINTF(D_MSG, ("UR_GET_STATUS RCO=%x ", status)); | | 678 | DPRINTF(D_MSG, ("UR_GET_STATUS RCO=%x ", status)); |
679 | | | 679 | |
680 | //DPRINTF(D_XFER, ("ST=%04x,CH=%04x ", status, sc->sc_change)); | | 680 | //DPRINTF(D_XFER, ("ST=%04x,CH=%04x ", status, sc->sc_change)); |
681 | USETW(ps.wPortStatus, status & (UPS_CURRENT_CONNECT_STATUS|UPS_PORT_ENABLED|UPS_SUSPEND|UPS_OVERCURRENT_INDICATOR|UPS_RESET|UPS_PORT_POWER|UPS_LOW_SPEED)); | | 681 | USETW(ps.wPortStatus, status & (UPS_CURRENT_CONNECT_STATUS|UPS_PORT_ENABLED|UPS_SUSPEND|UPS_OVERCURRENT_INDICATOR|UPS_RESET|UPS_PORT_POWER|UPS_LOW_SPEED)); |
682 | USETW(ps.wPortChange, (status>>16) & (UPS_C_CONNECT_STATUS|UPS_C_PORT_ENABLED|UPS_C_SUSPEND|UPS_C_OVERCURRENT_INDICATOR|UPS_C_PORT_RESET)); | | 682 | USETW(ps.wPortChange, (status>>16) & (UPS_C_CONNECT_STATUS|UPS_C_PORT_ENABLED|UPS_C_SUSPEND|UPS_C_OVERCURRENT_INDICATOR|UPS_C_PORT_RESET)); |
683 | totlen = uimin(len, sizeof(ps)); | | 683 | totlen = uimin(len, sizeof(ps)); |
684 | memcpy(buf, &ps, totlen); | | 684 | memcpy(buf, &ps, totlen); |
685 | break; | | 685 | break; |
686 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): | | 686 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): |
687 | /* Set Hub Descriptor, 11.16.2.7, not supported */ | | 687 | /* Set Hub Descriptor, 11.16.2.7, not supported */ |
688 | /* STALL ? */ | | 688 | /* STALL ? */ |
689 | return -1; | | 689 | return -1; |
690 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): | | 690 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): |
691 | /* Set Hub Feature, 11.16.2.8, not supported */ | | 691 | /* Set Hub Feature, 11.16.2.8, not supported */ |
692 | break; | | 692 | break; |
693 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): | | 693 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): |
694 | #define WPS(x) REG_WRITE(ADMHCD_REG_PORTSTATUS0+(index-1)*4, (x)) | | 694 | #define WPS(x) REG_WRITE(ADMHCD_REG_PORTSTATUS0+(index-1)*4, (x)) |
695 | /* Set Port Feature, 11.16.2.9 */ | | 695 | /* Set Port Feature, 11.16.2.9 */ |
696 | if ((index != 1) && (index !=2)) { | | 696 | if ((index != 1) && (index !=2)) { |
697 | printf("index=%d ", index); | | 697 | printf("index=%d ", index); |
698 | return -1; | | 698 | return -1; |
699 | } | | 699 | } |
700 | switch (value) { | | 700 | switch (value) { |
701 | case UHF_PORT_RESET: | | 701 | case UHF_PORT_RESET: |
702 | DPRINTF(D_MSG, ("PORT_RESET ")); | | 702 | DPRINTF(D_MSG, ("PORT_RESET ")); |
703 | WPS(ADMHCD_PRS); | | 703 | WPS(ADMHCD_PRS); |
704 | break; | | 704 | break; |
705 | case UHF_PORT_POWER: | | 705 | case UHF_PORT_POWER: |
706 | DPRINTF(D_MSG, ("PORT_POWER ")); | | 706 | DPRINTF(D_MSG, ("PORT_POWER ")); |
707 | WPS(ADMHCD_PPS); | | 707 | WPS(ADMHCD_PPS); |
708 | break; | | 708 | break; |
709 | case UHF_PORT_ENABLE: | | 709 | case UHF_PORT_ENABLE: |
710 | DPRINTF(D_MSG, ("PORT_ENABLE ")); | | 710 | DPRINTF(D_MSG, ("PORT_ENABLE ")); |
711 | WPS(ADMHCD_PES); | | 711 | WPS(ADMHCD_PES); |
712 | break; | | 712 | break; |
713 | default: | | 713 | default: |
714 | printf("SetPortFeatERR=0x%x ", value); | | 714 | printf("SetPortFeatERR=0x%x ", value); |
715 | return -1; | | 715 | return -1; |
716 | } | | 716 | } |
717 | #undef WPS | | 717 | #undef WPS |
718 | break; | | 718 | break; |
719 | default: | | 719 | default: |
720 | DPRINTF(D_MSG, ("ioerr(UR=%02x,UT=%02x) ", | | 720 | DPRINTF(D_MSG, ("ioerr(UR=%02x,UT=%02x) ", |
721 | req->bRequest, req->bmRequestType)); | | 721 | req->bRequest, req->bmRequestType)); |
722 | /* default from usbroothub */ | | 722 | /* default from usbroothub */ |
723 | return buflen; | | 723 | return buflen; |
724 | } | | 724 | } |
725 | | | 725 | |
726 | return totlen; | | 726 | return totlen; |
727 | } | | 727 | } |
728 | | | 728 | |
729 | static usbd_status | | 729 | static usbd_status |
730 | ahci_root_intr_transfer(struct usbd_xfer *xfer) | | 730 | ahci_root_intr_transfer(struct usbd_xfer *xfer) |
731 | { | | 731 | { |
732 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); | | 732 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); |
733 | usbd_status error; | | 733 | usbd_status error; |
734 | | | 734 | |
735 | DPRINTF(D_TRACE, ("SLRItransfer ")); | | 735 | DPRINTF(D_TRACE, ("SLRItransfer ")); |
736 | | | 736 | |
737 | /* Insert last in queue */ | | 737 | /* Insert last in queue */ |
738 | mutex_enter(&sc->sc_lock); | | 738 | mutex_enter(&sc->sc_lock); |
739 | error = usb_insert_transfer(xfer); | | 739 | error = usb_insert_transfer(xfer); |
740 | mutex_exit(&sc->sc_lock); | | 740 | mutex_exit(&sc->sc_lock); |
741 | if (error) | | 741 | if (error) |
742 | return error; | | 742 | return error; |
743 | | | 743 | |
744 | /* | | 744 | /* |
745 | * Pipe isn't running (otherwise error would be USBD_INPROG), | | 745 | * Pipe isn't running (otherwise error would be USBD_INPROG), |
746 | * start first. | | 746 | * start first. |
747 | */ | | 747 | */ |
748 | return ahci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 748 | return ahci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
749 | } | | 749 | } |
750 | | | 750 | |
751 | static usbd_status | | 751 | static usbd_status |
752 | ahci_root_intr_start(struct usbd_xfer *xfer) | | 752 | ahci_root_intr_start(struct usbd_xfer *xfer) |
753 | { | | 753 | { |
754 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); | | 754 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); |
755 | | | 755 | |
756 | DPRINTF(D_TRACE, ("SLRIstart ")); | | 756 | DPRINTF(D_TRACE, ("SLRIstart ")); |
757 | | | 757 | |
758 | mutex_enter(&sc->sc_lock); | | 758 | mutex_enter(&sc->sc_lock); |
759 | KASSERT(sc->sc_intr_xfer == NULL); | | 759 | KASSERT(sc->sc_intr_xfer == NULL); |
760 | sc->sc_interval = MS_TO_TICKS(xfer->ux_pipe->up_endpoint->ue_edesc->bInterval); | | 760 | sc->sc_interval = MS_TO_TICKS(xfer->ux_pipe->up_endpoint->ue_edesc->bInterval); |
761 | callout_schedule(&sc->sc_poll_handle, sc->sc_interval); | | 761 | callout_schedule(&sc->sc_poll_handle, sc->sc_interval); |
762 | sc->sc_intr_xfer = xfer; | | 762 | sc->sc_intr_xfer = xfer; |
763 | xfer->ux_status = USBD_IN_PROGRESS; | | 763 | xfer->ux_status = USBD_IN_PROGRESS; |
764 | mutex_exit(&sc->sc_lock); | | 764 | mutex_exit(&sc->sc_lock); |
765 | | | 765 | |
766 | return USBD_IN_PROGRESS; | | 766 | return USBD_IN_PROGRESS; |
767 | } | | 767 | } |
768 | | | 768 | |
769 | static void | | 769 | static void |
770 | ahci_root_intr_abort(struct usbd_xfer *xfer) | | 770 | ahci_root_intr_abort(struct usbd_xfer *xfer) |
771 | { | | 771 | { |
772 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); | | 772 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); |
773 | | | 773 | |
774 | DPRINTF(D_TRACE, ("SLRIabort ")); | | 774 | DPRINTF(D_TRACE, ("SLRIabort ")); |
775 | | | 775 | |
776 | KASSERT(mutex_owned(&sc->sc_lock)); | | 776 | KASSERT(mutex_owned(&sc->sc_lock)); |
777 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); | | 777 | KASSERT(xfer->ux_pipe->up_intrxfer == xfer); |
778 | | | 778 | |
779 | /* | | 779 | /* |
780 | * Try to stop the callout before it starts. If we got in too | | 780 | * Try to stop the callout before it starts. If we got in too |
781 | * late, too bad; but if the callout had yet to run and time | | 781 | * late, too bad; but if the callout had yet to run and time |
782 | * out the xfer, cancel it ourselves. | | 782 | * out the xfer, cancel it ourselves. |
783 | */ | | 783 | */ |
784 | callout_stop(&sc->sc_poll_handle); | | 784 | callout_stop(&sc->sc_poll_handle); |
785 | if (sc->sc_intr_xfer == NULL) | | 785 | if (sc->sc_intr_xfer == NULL) |
786 | return; | | 786 | return; |
787 | | | 787 | |
788 | KASSERT(sc->sc_intr_xfer == xfer); | | 788 | KASSERT(sc->sc_intr_xfer == xfer); |
789 | xfer->ux_status = USBD_CANCELLED; | | 789 | xfer->ux_status = USBD_CANCELLED; |
790 | usb_transfer_complete(xfer); | | 790 | usb_transfer_complete(xfer); |
791 | } | | 791 | } |
792 | | | 792 | |
793 | static void | | 793 | static void |
794 | ahci_root_intr_close(struct usbd_pipe *pipe) | | 794 | ahci_root_intr_close(struct usbd_pipe *pipe) |
795 | { | | 795 | { |
796 | struct ahci_softc *sc __diagused = AHCI_PIPE2SC(pipe); | | 796 | struct ahci_softc *sc __diagused = AHCI_PIPE2SC(pipe); |
797 | | | 797 | |
798 | DPRINTF(D_TRACE, ("SLRIclose ")); | | 798 | DPRINTF(D_TRACE, ("SLRIclose ")); |
799 | | | 799 | |
800 | KASSERT(mutex_owned(&sc->sc_lock)); | | 800 | KASSERT(mutex_owned(&sc->sc_lock)); |
801 | | | 801 | |
802 | /* | | 802 | /* |
803 | * The caller must arrange to have aborted the pipe already, so | | 803 | * The caller must arrange to have aborted the pipe already, so |
804 | * there can be no intr xfer in progress. The callout may | | 804 | * there can be no intr xfer in progress. The callout may |
805 | * still be pending from a prior intr xfer -- if it has already | | 805 | * still be pending from a prior intr xfer -- if it has already |
806 | * fired, it will see there is nothing to do, and do nothing. | | 806 | * fired, it will see there is nothing to do, and do nothing. |
807 | */ | | 807 | */ |
808 | KASSERT(sc->sc_intr_xfer == NULL); | | 808 | KASSERT(sc->sc_intr_xfer == NULL); |
809 | KASSERT(!callout_pending(&sc->sc_poll_handle)); | | 809 | KASSERT(!callout_pending(&sc->sc_poll_handle)); |
810 | } | | 810 | } |
811 | | | 811 | |
812 | static void | | 812 | static void |
813 | ahci_root_intr_done(struct usbd_xfer *xfer) | | 813 | ahci_root_intr_done(struct usbd_xfer *xfer) |
814 | { | | 814 | { |
815 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); | | 815 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); |
816 | | | 816 | |
817 | //DPRINTF(D_XFER, ("RIdn ")); | | 817 | //DPRINTF(D_XFER, ("RIdn ")); |
818 | | | 818 | |
819 | KASSERT(mutex_owned(&sc->sc_lock)); | | 819 | KASSERT(mutex_owned(&sc->sc_lock)); |
820 | | | 820 | |
821 | /* Claim the xfer so it doesn't get completed again. */ | | 821 | /* Claim the xfer so it doesn't get completed again. */ |
822 | KASSERT(sc->sc_intr_xfer == xfer); | | 822 | KASSERT(sc->sc_intr_xfer == xfer); |
823 | KASSERT(xfer->ux_status != USBD_IN_PROGRESS); | | 823 | KASSERT(xfer->ux_status != USBD_IN_PROGRESS); |
824 | sc->sc_intr_xfer = NULL; | | 824 | sc->sc_intr_xfer = NULL; |
825 | } | | 825 | } |
826 | | | 826 | |
827 | static usbd_status | | 827 | static usbd_status |
828 | ahci_device_ctrl_transfer(struct usbd_xfer *xfer) | | 828 | ahci_device_ctrl_transfer(struct usbd_xfer *xfer) |
829 | { | | 829 | { |
830 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); | | 830 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); |
831 | usbd_status error; | | 831 | usbd_status error; |
832 | | | 832 | |
833 | DPRINTF(D_TRACE, ("C")); | | 833 | DPRINTF(D_TRACE, ("C")); |
834 | | | 834 | |
835 | mutex_enter(&sc->sc_lock); | | 835 | mutex_enter(&sc->sc_lock); |
836 | error = usb_insert_transfer(xfer); | | 836 | error = usb_insert_transfer(xfer); |
837 | mutex_exit(&sc->sc_lock); | | 837 | mutex_exit(&sc->sc_lock); |
838 | if (error) | | 838 | if (error) |
839 | return error; | | 839 | return error; |
840 | | | 840 | |
841 | return ahci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 841 | return ahci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
842 | } | | 842 | } |
843 | | | 843 | |
844 | static usbd_status | | 844 | static usbd_status |
845 | ahci_device_ctrl_start(struct usbd_xfer *xfer) | | 845 | ahci_device_ctrl_start(struct usbd_xfer *xfer) |
846 | { | | 846 | { |
847 | usbd_status status = USBD_NORMAL_COMPLETION; | | 847 | usbd_status status = USBD_NORMAL_COMPLETION; |
848 | int s, err; | | 848 | int s, err; |
849 | static struct admhcd_ed ep_v __attribute__((aligned(16))), *ep; | | 849 | static struct admhcd_ed ep_v __attribute__((aligned(16))), *ep; |
850 | static struct admhcd_td td_v[4] __attribute__((aligned(16))), *td, *td1, *td2, *td3; | | 850 | static struct admhcd_td td_v[4] __attribute__((aligned(16))), *td, *td1, *td2, *td3; |
851 | static usb_dma_t reqdma; | | 851 | static usb_dma_t reqdma; |
852 | struct usbd_pipe *pipe = xfer->ux_pipe; | | 852 | struct usbd_pipe *pipe = xfer->ux_pipe; |
853 | usb_device_request_t *req = &xfer->ux_request; | | 853 | usb_device_request_t *req = &xfer->ux_request; |
854 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); | | 854 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); |
855 | int len, isread; | | 855 | int len, isread; |
856 | | | 856 | |
857 | | | 857 | |
858 | #if 0 | | 858 | #if 0 |
859 | struct ahci_pipe *apipe = (struct ahci_pipe *)xfer->ux_pipe; | | 859 | struct ahci_pipe *apipe = (struct ahci_pipe *)xfer->ux_pipe; |
860 | #endif | | 860 | #endif |
861 | mutex_enter(&sc->sc_lock); | | 861 | mutex_enter(&sc->sc_lock); |
862 | /* printf("ctrl_start>>>\n"); */ | | 862 | /* printf("ctrl_start>>>\n"); */ |
863 | | | 863 | |
864 | #ifdef DIAGNOSTIC | | 864 | #ifdef DIAGNOSTIC |
865 | if (!(xfer->ux_rqflags & URQ_REQUEST)) { | | 865 | if (!(xfer->ux_rqflags & URQ_REQUEST)) { |
866 | /* XXX panic */ | | 866 | /* XXX panic */ |
867 | printf("ahci_device_ctrl_transfer: not a request\n"); | | 867 | printf("ahci_device_ctrl_transfer: not a request\n"); |
868 | return USBD_INVAL; | | 868 | return USBD_INVAL; |
869 | } | | 869 | } |
870 | #endif | | 870 | #endif |
871 | | | 871 | |
872 | #define KSEG1ADDR(x) (0xa0000000 | (((uint32_t)x) & 0x1fffffff)) | | 872 | #define KSEG1ADDR(x) (0xa0000000 | (((uint32_t)x) & 0x1fffffff)) |
873 | DPRINTF(D_TRACE, ("st ")); | | 873 | DPRINTF(D_TRACE, ("st ")); |
874 | if (!ep) { | | 874 | if (!ep) { |
875 | ep = (struct admhcd_ed *)KSEG1ADDR(&ep_v); | | 875 | ep = (struct admhcd_ed *)KSEG1ADDR(&ep_v); |
876 | td = (struct admhcd_td *)KSEG1ADDR(&td_v[0]); | | 876 | td = (struct admhcd_td *)KSEG1ADDR(&td_v[0]); |
877 | td1 = (struct admhcd_td *)KSEG1ADDR(&td_v[1]); | | 877 | td1 = (struct admhcd_td *)KSEG1ADDR(&td_v[1]); |
878 | td2 = (struct admhcd_td *)KSEG1ADDR(&td_v[2]); | | 878 | td2 = (struct admhcd_td *)KSEG1ADDR(&td_v[2]); |
879 | td3 = (struct admhcd_td *)KSEG1ADDR(&td_v[3]); | | 879 | td3 = (struct admhcd_td *)KSEG1ADDR(&td_v[3]); |
880 | err = usb_allocmem(&sc->sc_bus, | | 880 | err = usb_allocmem(&sc->sc_bus, |
881 | sizeof(usb_device_request_t), | | 881 | sizeof(usb_device_request_t), |
882 | 0, USBMALLOC_COHERENT, &reqdma); | | 882 | 0, USBMALLOC_COHERENT, &reqdma); |
883 | if (err) | | 883 | if (err) |
884 | return USBD_NOMEM; | | 884 | return USBD_NOMEM; |
885 | | | 885 | |
886 | /* printf("ep: %p\n",ep); */ | | 886 | /* printf("ep: %p\n",ep); */ |
887 | }; | | 887 | }; |
888 | | | 888 | |
889 | ep->control = pipe->up_dev->ud_addr | \ | | 889 | ep->control = pipe->up_dev->ud_addr | \ |
890 | ((pipe->up_dev->ud_speed==USB_SPEED_FULL)?ADMHCD_ED_SPEED:0) | \ | | 890 | ((pipe->up_dev->ud_speed==USB_SPEED_FULL)?ADMHCD_ED_SPEED:0) | \ |
891 | ((UGETW(pipe->up_endpoint->ue_edesc->wMaxPacketSize))<<ADMHCD_ED_MAXSHIFT); | | 891 | ((UGETW(pipe->up_endpoint->ue_edesc->wMaxPacketSize))<<ADMHCD_ED_MAXSHIFT); |
892 | memcpy(KERNADDR(&reqdma, 0), req, sizeof *req); | | 892 | memcpy(KERNADDR(&reqdma, 0), req, sizeof(*req)); |
893 | /* printf("status: %x\n",REG_READ(ADMHCD_REG_PORTSTATUS0)); | | 893 | /* printf("status: %x\n",REG_READ(ADMHCD_REG_PORTSTATUS0)); |
894 | printf("ep_control: %x\n",ep->control); | | 894 | printf("ep_control: %x\n",ep->control); |
895 | printf("speed: %x\n",pipe->up_dev->ud_speed); | | 895 | printf("speed: %x\n",pipe->up_dev->ud_speed); |
896 | printf("req: %p\n",req); | | 896 | printf("req: %p\n",req); |
897 | printf("dmabuf: %p\n",xfer->ux_dmabuf.block); */ | | 897 | printf("dmabuf: %p\n",xfer->ux_dmabuf.block); */ |
898 | | | 898 | |
899 | isread = req->bmRequestType & UT_READ; | | 899 | isread = req->bmRequestType & UT_READ; |
900 | len = UGETW(req->wLength); | | 900 | len = UGETW(req->wLength); |
901 | | | 901 | |
902 | ep->next = ep; | | 902 | ep->next = ep; |
903 | | | 903 | |
904 | td->buffer = DMAADDR(&reqdma,0) | 0xa0000000; | | 904 | td->buffer = DMAADDR(&reqdma,0) | 0xa0000000; |
905 | td->buflen=sizeof(*req); | | 905 | td->buflen=sizeof(*req); |
906 | td->control=ADMHCD_TD_SETUP | ADMHCD_TD_DATA0 | ADMHCD_TD_OWN; | | 906 | td->control=ADMHCD_TD_SETUP | ADMHCD_TD_DATA0 | ADMHCD_TD_OWN; |
907 | | | 907 | |
908 | if (len) { | | 908 | if (len) { |
909 | td->next = td1; | | 909 | td->next = td1; |
910 | | | 910 | |
911 | td1->buffer = DMAADDR(&xfer->ux_dmabuf,0) | 0xa0000000; | | 911 | td1->buffer = DMAADDR(&xfer->ux_dmabuf,0) | 0xa0000000; |
912 | td1->buflen = len; | | 912 | td1->buflen = len; |
913 | td1->next = td2; | | 913 | td1->next = td2; |
914 | td1->control= (isread?ADMHCD_TD_IN:ADMHCD_TD_OUT) | ADMHCD_TD_DATA1 | ADMHCD_TD_R | ADMHCD_TD_OWN; | | 914 | td1->control= (isread?ADMHCD_TD_IN:ADMHCD_TD_OUT) | ADMHCD_TD_DATA1 | ADMHCD_TD_R | ADMHCD_TD_OWN; |
915 | } else { | | 915 | } else { |
916 | td1->control = 0; | | 916 | td1->control = 0; |
917 | td->next = td2; | | 917 | td->next = td2; |
918 | }; | | 918 | }; |
919 | | | 919 | |
920 | td2->buffer = 0; | | 920 | td2->buffer = 0; |
921 | td2->buflen= 0; | | 921 | td2->buflen= 0; |
922 | td2->next = td3; | | 922 | td2->next = td3; |
923 | td2->control = (isread?ADMHCD_TD_OUT:ADMHCD_TD_IN) | ADMHCD_TD_DATA1 | ADMHCD_TD_OWN; | | 923 | td2->control = (isread?ADMHCD_TD_OUT:ADMHCD_TD_IN) | ADMHCD_TD_DATA1 | ADMHCD_TD_OWN; |
924 | | | 924 | |
925 | td3->buffer = 0; | | 925 | td3->buffer = 0; |
926 | td3->buflen= 0; | | 926 | td3->buflen= 0; |
927 | td3->next = 0; | | 927 | td3->next = 0; |
928 | td3->control = 0; | | 928 | td3->control = 0; |
929 | | | 929 | |
930 | ep->head = td; | | 930 | ep->head = td; |
931 | ep->tail = td3; | | 931 | ep->tail = td3; |
932 | /* | | 932 | /* |
933 | printf("ep: %p\n",ep); | | 933 | printf("ep: %p\n",ep); |
934 | printf("ep->next: %p\n",ep->next); | | 934 | printf("ep->next: %p\n",ep->next); |
935 | printf("ep->head: %p\n",ep->head); | | 935 | printf("ep->head: %p\n",ep->head); |
936 | printf("ep->tail: %p\n",ep->tail); | | 936 | printf("ep->tail: %p\n",ep->tail); |
937 | printf("td: %p\n",td); | | 937 | printf("td: %p\n",td); |
938 | printf("td->next: %p\n",td->next); | | 938 | printf("td->next: %p\n",td->next); |
939 | printf("td->buffer: %x\n",td->buffer); | | 939 | printf("td->buffer: %x\n",td->buffer); |
940 | printf("td->buflen: %x\n",td->buflen); | | 940 | printf("td->buflen: %x\n",td->buflen); |
941 | printf("td1: %p\n",td1); | | 941 | printf("td1: %p\n",td1); |
942 | printf("td1->next: %p\n",td1->next); | | 942 | printf("td1->next: %p\n",td1->next); |
943 | printf("td2: %p\n",td2); | | 943 | printf("td2: %p\n",td2); |
944 | printf("td2->next: %p\n",td2->next); | | 944 | printf("td2->next: %p\n",td2->next); |
945 | printf("td3: %p\n",td3); | | 945 | printf("td3: %p\n",td3); |
946 | printf("td3->next: %p\n",td3->next); | | 946 | printf("td3->next: %p\n",td3->next); |
947 | */ | | 947 | */ |
948 | | | 948 | |
949 | REG_WRITE(ADMHCD_REG_HOSTHEAD, (uint32_t)ep); | | 949 | REG_WRITE(ADMHCD_REG_HOSTHEAD, (uint32_t)ep); |
950 | REG_WRITE(ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP | ADMHCD_DMA_EN); | | 950 | REG_WRITE(ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP | ADMHCD_DMA_EN); |
951 | /* printf("1: %x %x %x %x\n", ep->control, td->control, td1->control, td2->control); */ | | 951 | /* printf("1: %x %x %x %x\n", ep->control, td->control, td1->control, td2->control); */ |
952 | s=100; | | 952 | s=100; |
953 | while (s--) { | | 953 | while (s--) { |
954 | delay_ms(10); | | 954 | delay_ms(10); |
955 | /* printf("%x %x %x %x\n", ep->control, td->control, td1->control, td2->control);*/ | | 955 | /* printf("%x %x %x %x\n", ep->control, td->control, td1->control, td2->control);*/ |
956 | status = USBD_TIMEOUT; | | 956 | status = USBD_TIMEOUT; |
957 | if (td->control & ADMHCD_TD_OWN) continue; | | 957 | if (td->control & ADMHCD_TD_OWN) continue; |
958 | | | 958 | |
959 | err = (td->control & ADMHCD_TD_ERRMASK)>>ADMHCD_TD_ERRSHIFT; | | 959 | err = (td->control & ADMHCD_TD_ERRMASK)>>ADMHCD_TD_ERRSHIFT; |
960 | if (err) { | | 960 | if (err) { |
961 | status = USBD_IOERROR; | | 961 | status = USBD_IOERROR; |
962 | break; | | 962 | break; |
963 | }; | | 963 | }; |
964 | | | 964 | |
965 | status = USBD_TIMEOUT; | | 965 | status = USBD_TIMEOUT; |
966 | if (td1->control & ADMHCD_TD_OWN) continue; | | 966 | if (td1->control & ADMHCD_TD_OWN) continue; |
967 | err = (td1->control & ADMHCD_TD_ERRMASK)>>ADMHCD_TD_ERRSHIFT; | | 967 | err = (td1->control & ADMHCD_TD_ERRMASK)>>ADMHCD_TD_ERRSHIFT; |
968 | if (err) { | | 968 | if (err) { |
969 | status = USBD_IOERROR; | | 969 | status = USBD_IOERROR; |
970 | break; | | 970 | break; |
971 | }; | | 971 | }; |
972 | | | 972 | |
973 | status = USBD_TIMEOUT; | | 973 | status = USBD_TIMEOUT; |
974 | if (td2->control & ADMHCD_TD_OWN) continue; | | 974 | if (td2->control & ADMHCD_TD_OWN) continue; |
975 | err = (td2->control & ADMHCD_TD_ERRMASK)>>ADMHCD_TD_ERRSHIFT; | | 975 | err = (td2->control & ADMHCD_TD_ERRMASK)>>ADMHCD_TD_ERRSHIFT; |
976 | if (err) { | | 976 | if (err) { |
977 | status = USBD_IOERROR; | | 977 | status = USBD_IOERROR; |
978 | }; | | 978 | }; |
979 | status = USBD_NORMAL_COMPLETION; | | 979 | status = USBD_NORMAL_COMPLETION; |
980 | break; | | 980 | break; |
981 | | | 981 | |
982 | }; | | 982 | }; |
983 | REG_WRITE(ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP); | | 983 | REG_WRITE(ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP); |
984 | | | 984 | |
985 | xfer->ux_actlen = len; | | 985 | xfer->ux_actlen = len; |
986 | xfer->ux_status = status; | | 986 | xfer->ux_status = status; |
987 | | | 987 | |
988 | /* printf("ctrl_start<<<\n"); */ | | 988 | /* printf("ctrl_start<<<\n"); */ |
989 | | | 989 | |
990 | usb_transfer_complete(xfer); | | 990 | usb_transfer_complete(xfer); |
991 | mutex_exit(&sc->sc_lock); | | 991 | mutex_exit(&sc->sc_lock); |
992 | | | 992 | |
993 | usb_freemem(&sc->sc_bus, &reqdma); | | 993 | usb_freemem(&sc->sc_bus, &reqdma); |
994 | | | 994 | |
995 | return USBD_NORMAL_COMPLETION; | | 995 | return USBD_NORMAL_COMPLETION; |
996 | } | | 996 | } |
997 | | | 997 | |
998 | static void | | 998 | static void |
999 | ahci_device_ctrl_abort(struct usbd_xfer *xfer) | | 999 | ahci_device_ctrl_abort(struct usbd_xfer *xfer) |
1000 | { | | 1000 | { |
1001 | DPRINTF(D_TRACE, ("Cab ")); | | 1001 | DPRINTF(D_TRACE, ("Cab ")); |
1002 | usbd_xfer_abort(xfer); | | 1002 | usbd_xfer_abort(xfer); |
1003 | } | | 1003 | } |
1004 | | | 1004 | |
1005 | static void | | 1005 | static void |
1006 | ahci_device_ctrl_close(struct usbd_pipe *pipe) | | 1006 | ahci_device_ctrl_close(struct usbd_pipe *pipe) |
1007 | { | | 1007 | { |
1008 | DPRINTF(D_TRACE, ("Ccl ")); | | 1008 | DPRINTF(D_TRACE, ("Ccl ")); |
1009 | } | | 1009 | } |
1010 | | | 1010 | |
1011 | static void | | 1011 | static void |
1012 | ahci_device_ctrl_done(struct usbd_xfer *xfer) | | 1012 | ahci_device_ctrl_done(struct usbd_xfer *xfer) |
1013 | { | | 1013 | { |
1014 | DPRINTF(D_TRACE, ("Cdn ")); | | 1014 | DPRINTF(D_TRACE, ("Cdn ")); |
1015 | } | | 1015 | } |
1016 | | | 1016 | |
1017 | static usbd_status | | 1017 | static usbd_status |
1018 | ahci_device_intr_transfer(struct usbd_xfer *xfer) | | 1018 | ahci_device_intr_transfer(struct usbd_xfer *xfer) |
1019 | { | | 1019 | { |
1020 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); | | 1020 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); |
1021 | usbd_status error; | | 1021 | usbd_status error; |
1022 | | | 1022 | |
1023 | DPRINTF(D_TRACE, ("INTRtrans ")); | | 1023 | DPRINTF(D_TRACE, ("INTRtrans ")); |
1024 | | | 1024 | |
1025 | mutex_enter(&sc->sc_lock); | | 1025 | mutex_enter(&sc->sc_lock); |
1026 | error = usb_insert_transfer(xfer); | | 1026 | error = usb_insert_transfer(xfer); |
1027 | mutex_exit(&sc->sc_lock); | | 1027 | mutex_exit(&sc->sc_lock); |
1028 | if (error) | | 1028 | if (error) |
1029 | return error; | | 1029 | return error; |
1030 | | | 1030 | |
1031 | return ahci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 1031 | return ahci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
1032 | } | | 1032 | } |
1033 | | | 1033 | |
1034 | static usbd_status | | 1034 | static usbd_status |
1035 | ahci_device_intr_start(struct usbd_xfer *xfer) | | 1035 | ahci_device_intr_start(struct usbd_xfer *xfer) |
1036 | { | | 1036 | { |
1037 | struct usbd_pipe *pipe = xfer->ux_pipe; | | 1037 | struct usbd_pipe *pipe = xfer->ux_pipe; |
1038 | struct ahci_xfer *sx; | | 1038 | struct ahci_xfer *sx; |
1039 | | | 1039 | |
1040 | DPRINTF(D_TRACE, ("INTRstart ")); | | 1040 | DPRINTF(D_TRACE, ("INTRstart ")); |
1041 | | | 1041 | |
1042 | sx = kmem_intr_alloc(sizeof(*sx), KM_NOSLEEP); | | 1042 | sx = kmem_intr_alloc(sizeof(*sx), KM_NOSLEEP); |
1043 | if (sx == NULL) | | 1043 | if (sx == NULL) |
1044 | goto reterr; | | 1044 | goto reterr; |
1045 | memset(sx, 0, sizeof(*sx)); | | 1045 | memset(sx, 0, sizeof(*sx)); |
1046 | sx->sx_xfer = xfer; | | 1046 | sx->sx_xfer = xfer; |
1047 | xfer->ux_hcpriv = sx; | | 1047 | xfer->ux_hcpriv = sx; |
1048 | | | 1048 | |
1049 | /* initialize callout */ | | 1049 | /* initialize callout */ |
1050 | callout_init(&sx->sx_callout_t, 0); | | 1050 | callout_init(&sx->sx_callout_t, 0); |
1051 | callout_reset(&sx->sx_callout_t, | | 1051 | callout_reset(&sx->sx_callout_t, |
1052 | MS_TO_TICKS(pipe->up_endpoint->ue_edesc->bInterval), | | 1052 | MS_TO_TICKS(pipe->up_endpoint->ue_edesc->bInterval), |
1053 | ahci_poll_device, sx); | | 1053 | ahci_poll_device, sx); |
1054 | | | 1054 | |
1055 | /* ACK */ | | 1055 | /* ACK */ |
1056 | return USBD_IN_PROGRESS; | | 1056 | return USBD_IN_PROGRESS; |
1057 | | | 1057 | |
1058 | reterr: | | 1058 | reterr: |
1059 | return USBD_IOERROR; | | 1059 | return USBD_IOERROR; |
1060 | } | | 1060 | } |
1061 | | | 1061 | |
1062 | static void | | 1062 | static void |
1063 | ahci_poll_device(void *arg) | | 1063 | ahci_poll_device(void *arg) |
1064 | { | | 1064 | { |
1065 | struct ahci_xfer *sx = (struct ahci_xfer *)arg; | | 1065 | struct ahci_xfer *sx = (struct ahci_xfer *)arg; |
1066 | struct usbd_xfer *xfer = sx->sx_xfer; | | 1066 | struct usbd_xfer *xfer = sx->sx_xfer; |
1067 | struct usbd_pipe *pipe = xfer->ux_pipe; | | 1067 | struct usbd_pipe *pipe = xfer->ux_pipe; |
1068 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); | | 1068 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); |
1069 | void *buf; | | 1069 | void *buf; |
1070 | int pid; | | 1070 | int pid; |
1071 | int r; | | 1071 | int r; |
1072 | | | 1072 | |
1073 | DPRINTF(D_TRACE, ("pldev")); | | 1073 | DPRINTF(D_TRACE, ("pldev")); |
1074 | | | 1074 | |
1075 | callout_reset(&sx->sx_callout_t, | | 1075 | callout_reset(&sx->sx_callout_t, |
1076 | MS_TO_TICKS(pipe->up_endpoint->ue_edesc->bInterval), | | 1076 | MS_TO_TICKS(pipe->up_endpoint->ue_edesc->bInterval), |
1077 | ahci_poll_device, sx); | | 1077 | ahci_poll_device, sx); |
1078 | | | 1078 | |
1079 | /* interrupt transfer */ | | 1079 | /* interrupt transfer */ |
1080 | pid = (UE_GET_DIR(pipe->up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN) | | 1080 | pid = (UE_GET_DIR(pipe->up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN) |
1081 | ? ADMHCD_TD_IN : ADMHCD_TD_OUT; | | 1081 | ? ADMHCD_TD_IN : ADMHCD_TD_OUT; |
1082 | buf = KERNADDR(&xfer->ux_dmabuf, 0); | | 1082 | buf = KERNADDR(&xfer->ux_dmabuf, 0); |
1083 | | | 1083 | |
1084 | r = ahci_transaction(sc, pipe, pid, xfer->ux_length, buf, 0/*toggle*/); | | 1084 | r = ahci_transaction(sc, pipe, pid, xfer->ux_length, buf, 0/*toggle*/); |
1085 | if (r < 0) { | | 1085 | if (r < 0) { |
1086 | DPRINTF(D_MSG, ("%s error", __func__)); | | 1086 | DPRINTF(D_MSG, ("%s error", __func__)); |
1087 | return; | | 1087 | return; |
1088 | } | | 1088 | } |
1089 | /* no change, return NAK */ | | 1089 | /* no change, return NAK */ |
1090 | if (r == 0) | | 1090 | if (r == 0) |
1091 | return; | | 1091 | return; |
1092 | | | 1092 | |
1093 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 1093 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
1094 | mutex_enter(&sc->sc_lock); | | 1094 | mutex_enter(&sc->sc_lock); |
1095 | usb_transfer_complete(xfer); | | 1095 | usb_transfer_complete(xfer); |
1096 | mutex_exit(&sc->sc_lock); | | 1096 | mutex_exit(&sc->sc_lock); |
1097 | } | | 1097 | } |
1098 | | | 1098 | |
1099 | static void | | 1099 | static void |
1100 | ahci_device_intr_abort(struct usbd_xfer *xfer) | | 1100 | ahci_device_intr_abort(struct usbd_xfer *xfer) |
1101 | { | | 1101 | { |
1102 | struct ahci_xfer *sx; | | 1102 | struct ahci_xfer *sx; |
1103 | | | 1103 | |
1104 | DPRINTF(D_TRACE, ("INTRabort ")); | | 1104 | DPRINTF(D_TRACE, ("INTRabort ")); |
1105 | | | 1105 | |
1106 | sx = xfer->ux_hcpriv; | | 1106 | sx = xfer->ux_hcpriv; |
1107 | if (sx) { | | 1107 | if (sx) { |
1108 | callout_stop(&sx->sx_callout_t); | | 1108 | callout_stop(&sx->sx_callout_t); |
1109 | kmem_intr_free(sx, sizeof(*sx)); | | 1109 | kmem_intr_free(sx, sizeof(*sx)); |
1110 | xfer->ux_hcpriv = NULL; | | 1110 | xfer->ux_hcpriv = NULL; |
1111 | } else { | | 1111 | } else { |
1112 | printf("%s: sx == NULL!\n", __func__); | | 1112 | printf("%s: sx == NULL!\n", __func__); |
1113 | } | | 1113 | } |
1114 | usbd_xfer_abort(xfer); | | 1114 | usbd_xfer_abort(xfer); |
1115 | } | | 1115 | } |
1116 | | | 1116 | |
1117 | static void | | 1117 | static void |
1118 | ahci_device_intr_close(struct usbd_pipe *pipe) | | 1118 | ahci_device_intr_close(struct usbd_pipe *pipe) |
1119 | { | | 1119 | { |
1120 | DPRINTF(D_TRACE, ("INTRclose ")); | | 1120 | DPRINTF(D_TRACE, ("INTRclose ")); |
1121 | } | | 1121 | } |
1122 | | | 1122 | |
1123 | static void | | 1123 | static void |
1124 | ahci_device_intr_done(struct usbd_xfer *xfer) | | 1124 | ahci_device_intr_done(struct usbd_xfer *xfer) |
1125 | { | | 1125 | { |
1126 | DPRINTF(D_TRACE, ("INTRdone ")); | | 1126 | DPRINTF(D_TRACE, ("INTRdone ")); |
1127 | } | | 1127 | } |
1128 | | | 1128 | |
1129 | static usbd_status | | 1129 | static usbd_status |
1130 | ahci_device_isoc_transfer(struct usbd_xfer *xfer) | | 1130 | ahci_device_isoc_transfer(struct usbd_xfer *xfer) |
1131 | { | | 1131 | { |
1132 | DPRINTF(D_TRACE, ("S")); | | 1132 | DPRINTF(D_TRACE, ("S")); |
1133 | return USBD_NORMAL_COMPLETION; | | 1133 | return USBD_NORMAL_COMPLETION; |
1134 | } | | 1134 | } |
1135 | | | 1135 | |
1136 | static usbd_status | | 1136 | static usbd_status |
1137 | ahci_device_isoc_start(struct usbd_xfer *xfer) | | 1137 | ahci_device_isoc_start(struct usbd_xfer *xfer) |
1138 | { | | 1138 | { |
1139 | DPRINTF(D_TRACE, ("st ")); | | 1139 | DPRINTF(D_TRACE, ("st ")); |
1140 | return USBD_NORMAL_COMPLETION; | | 1140 | return USBD_NORMAL_COMPLETION; |
1141 | } | | 1141 | } |
1142 | | | 1142 | |
1143 | static void | | 1143 | static void |
1144 | ahci_device_isoc_abort(struct usbd_xfer *xfer) | | 1144 | ahci_device_isoc_abort(struct usbd_xfer *xfer) |
1145 | { | | 1145 | { |
1146 | DPRINTF(D_TRACE, ("Sab ")); | | 1146 | DPRINTF(D_TRACE, ("Sab ")); |
1147 | } | | 1147 | } |
1148 | | | 1148 | |
1149 | static void | | 1149 | static void |
1150 | ahci_device_isoc_close(struct usbd_pipe *pipe) | | 1150 | ahci_device_isoc_close(struct usbd_pipe *pipe) |
1151 | { | | 1151 | { |
1152 | DPRINTF(D_TRACE, ("Scl ")); | | 1152 | DPRINTF(D_TRACE, ("Scl ")); |
1153 | } | | 1153 | } |
1154 | | | 1154 | |
1155 | static void | | 1155 | static void |
1156 | ahci_device_isoc_done(struct usbd_xfer *xfer) | | 1156 | ahci_device_isoc_done(struct usbd_xfer *xfer) |
1157 | { | | 1157 | { |
1158 | DPRINTF(D_TRACE, ("Sdn ")); | | 1158 | DPRINTF(D_TRACE, ("Sdn ")); |
1159 | } | | 1159 | } |
1160 | | | 1160 | |
1161 | static usbd_status | | 1161 | static usbd_status |
1162 | ahci_device_bulk_transfer(struct usbd_xfer *xfer) | | 1162 | ahci_device_bulk_transfer(struct usbd_xfer *xfer) |
1163 | { | | 1163 | { |
1164 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); | | 1164 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); |
1165 | usbd_status error; | | 1165 | usbd_status error; |
1166 | | | 1166 | |
1167 | DPRINTF(D_TRACE, ("B")); | | 1167 | DPRINTF(D_TRACE, ("B")); |
1168 | | | 1168 | |
1169 | mutex_enter(&sc->sc_lock); | | 1169 | mutex_enter(&sc->sc_lock); |
1170 | error = usb_insert_transfer(xfer); | | 1170 | error = usb_insert_transfer(xfer); |
1171 | mutex_exit(&sc->sc_lock); | | 1171 | mutex_exit(&sc->sc_lock); |
1172 | if (error) | | 1172 | if (error) |
1173 | return error; | | 1173 | return error; |
1174 | | | 1174 | |
1175 | return ahci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); | | 1175 | return ahci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue)); |
1176 | } | | 1176 | } |
1177 | | | 1177 | |
1178 | static usbd_status | | 1178 | static usbd_status |
1179 | ahci_device_bulk_start(struct usbd_xfer *xfer) | | 1179 | ahci_device_bulk_start(struct usbd_xfer *xfer) |
1180 | { | | 1180 | { |
1181 | #define NBULK_TDS 32 | | 1181 | #define NBULK_TDS 32 |
1182 | static volatile int level = 0; | | 1182 | static volatile int level = 0; |
1183 | usbd_status status = USBD_NORMAL_COMPLETION; | | 1183 | usbd_status status = USBD_NORMAL_COMPLETION; |
1184 | int s, err; | | 1184 | int s, err; |
1185 | static struct admhcd_ed ep_v __attribute__((aligned(16))), *ep; | | 1185 | static struct admhcd_ed ep_v __attribute__((aligned(16))), *ep; |
1186 | static struct admhcd_td td_v[NBULK_TDS] __attribute__((aligned(16))), *td[NBULK_TDS]; | | 1186 | static struct admhcd_td td_v[NBULK_TDS] __attribute__((aligned(16))), *td[NBULK_TDS]; |
1187 | struct usbd_pipe *pipe = xfer->ux_pipe; | | 1187 | struct usbd_pipe *pipe = xfer->ux_pipe; |
1188 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); | | 1188 | struct ahci_softc *sc = AHCI_XFER2SC(xfer); |
1189 | int endpt, i, len, tlen, segs, offset, isread, toggle, short_ok; | | 1189 | int endpt, i, len, tlen, segs, offset, isread, toggle, short_ok; |
1190 | struct ahci_pipe *apipe = (struct ahci_pipe *)xfer->ux_pipe; | | 1190 | struct ahci_pipe *apipe = (struct ahci_pipe *)xfer->ux_pipe; |
1191 | | | 1191 | |
1192 | #define KSEG1ADDR(x) (0xa0000000 | (((uint32_t)x) & 0x1fffffff)) | | 1192 | #define KSEG1ADDR(x) (0xa0000000 | (((uint32_t)x) & 0x1fffffff)) |
1193 | DPRINTF(D_TRACE, ("st ")); | | 1193 | DPRINTF(D_TRACE, ("st ")); |
1194 | | | 1194 | |
1195 | #ifdef DIAGNOSTIC | | 1195 | #ifdef DIAGNOSTIC |
1196 | if (xfer->ux_rqflags & URQ_REQUEST) { | | 1196 | if (xfer->ux_rqflags & URQ_REQUEST) { |
1197 | /* XXX panic */ | | 1197 | /* XXX panic */ |
1198 | printf("ohci_device_bulk_start: a request\n"); | | 1198 | printf("ohci_device_bulk_start: a request\n"); |
1199 | return USBD_INVAL; | | 1199 | return USBD_INVAL; |
1200 | } | | 1200 | } |
1201 | #endif | | 1201 | #endif |
1202 | | | 1202 | |
1203 | mutex_enter(&sc->sc_lock); | | 1203 | mutex_enter(&sc->sc_lock); |
1204 | level++; | | 1204 | level++; |
1205 | /* printf("bulk_start>>>\n"); */ | | 1205 | /* printf("bulk_start>>>\n"); */ |
1206 | | | 1206 | |
1207 | if (!ep) { | | 1207 | if (!ep) { |
1208 | ep = (struct admhcd_ed *)KSEG1ADDR(&ep_v); | | 1208 | ep = (struct admhcd_ed *)KSEG1ADDR(&ep_v); |
1209 | for (i=0; i<NBULK_TDS; i++) { | | 1209 | for (i=0; i<NBULK_TDS; i++) { |
1210 | td[i] = (struct admhcd_td *)KSEG1ADDR(&td_v[i]); | | 1210 | td[i] = (struct admhcd_td *)KSEG1ADDR(&td_v[i]); |
1211 | }; | | 1211 | }; |
1212 | /* printf("ep: %p\n",ep);*/ | | 1212 | /* printf("ep: %p\n",ep);*/ |
1213 | }; | | 1213 | }; |
1214 | if (apipe->toggle == 0) { | | 1214 | if (apipe->toggle == 0) { |
1215 | toggle = ADMHCD_TD_DATA0; | | 1215 | toggle = ADMHCD_TD_DATA0; |
1216 | } else { | | 1216 | } else { |
1217 | toggle = apipe->toggle; | | 1217 | toggle = apipe->toggle; |
1218 | }; | | 1218 | }; |
1219 | | | 1219 | |
1220 | endpt = pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 1220 | endpt = pipe->up_endpoint->ue_edesc->bEndpointAddress; |
1221 | ep->control = pipe->up_dev->ud_addr | ((endpt & 0xf) << ADMHCD_ED_EPSHIFT)|\ | | 1221 | ep->control = pipe->up_dev->ud_addr | ((endpt & 0xf) << ADMHCD_ED_EPSHIFT)|\ |
1222 | ((pipe->up_dev->ud_speed==USB_SPEED_FULL)?ADMHCD_ED_SPEED:0) | \ | | 1222 | ((pipe->up_dev->ud_speed==USB_SPEED_FULL)?ADMHCD_ED_SPEED:0) | \ |
1223 | ((UGETW(pipe->up_endpoint->ue_edesc->wMaxPacketSize))<<ADMHCD_ED_MAXSHIFT); | | 1223 | ((UGETW(pipe->up_endpoint->ue_edesc->wMaxPacketSize))<<ADMHCD_ED_MAXSHIFT); |
1224 | | | 1224 | |
1225 | short_ok = xfer->ux_flags & USBD_SHORT_XFER_OK?ADMHCD_TD_R:0; | | 1225 | short_ok = xfer->ux_flags & USBD_SHORT_XFER_OK?ADMHCD_TD_R:0; |
1226 | /* printf("level: %d\n",level); | | 1226 | /* printf("level: %d\n",level); |
1227 | printf("short_xfer: %x\n",short_ok); | | 1227 | printf("short_xfer: %x\n",short_ok); |
1228 | printf("ep_control: %x\n",ep->control); | | 1228 | printf("ep_control: %x\n",ep->control); |
1229 | printf("speed: %x\n",pipe->up_dev->ud_speed); | | 1229 | printf("speed: %x\n",pipe->up_dev->ud_speed); |
1230 | printf("dmabuf: %p\n",xfer->ux_dmabuf.block); */ | | 1230 | printf("dmabuf: %p\n",xfer->ux_dmabuf.block); */ |
1231 | | | 1231 | |
1232 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; | | 1232 | isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
1233 | len = xfer->ux_length; | | 1233 | len = xfer->ux_length; |
1234 | | | 1234 | |
1235 | ep->next = ep; | | 1235 | ep->next = ep; |
1236 | | | 1236 | |
1237 | i = 0; | | 1237 | i = 0; |
1238 | offset = 0; | | 1238 | offset = 0; |
1239 | while ((len>0) || (i==0)) { | | 1239 | while (len > 0) || i == 0) { |
1240 | tlen = uimin(len,4096); | | 1240 | tlen = uimin(len,4096); |
1241 | td[i]->buffer = DMAADDR(&xfer->ux_dmabuf,offset) | 0xa0000000; | | 1241 | td[i]->buffer = DMAADDR(&xfer->ux_dmabuf, offset) | 0xa0000000; |
1242 | td[i]->buflen=tlen; | | 1242 | td[i]->buflen = tlen; |
1243 | td[i]->control=(isread?ADMHCD_TD_IN:ADMHCD_TD_OUT) | toggle | ADMHCD_TD_OWN | short_ok; | | 1243 | td[i]->control = (isread ? ADMHCD_TD_IN : ADMHCD_TD_OUT) | |
1244 | td[i]->len=tlen; | | 1244 | toggle | ADMHCD_TD_OWN | short_ok; |
| | | 1245 | td[i]->len = tlen; |
1245 | toggle = ADMHCD_TD_TOGGLE; | | 1246 | toggle = ADMHCD_TD_TOGGLE; |
1246 | len -= tlen; | | 1247 | len -= tlen; |
1247 | offset += tlen; | | 1248 | offset += tlen; |
1248 | td[i]->next = td[i+1]; | | 1249 | td[i]->next = td[i + 1]; |
1249 | i++; | | 1250 | i++; |
1250 | }; | | 1251 | }; |
1251 | | | 1252 | |
1252 | td[i]->buffer = 0; | | 1253 | td[i]->buffer = 0; |
1253 | td[i]->buflen = 0; | | 1254 | td[i]->buflen = 0; |
1254 | td[i]->control = 0; | | 1255 | td[i]->control = 0; |
1255 | td[i]->next = 0; | | 1256 | td[i]->next = 0; |
1256 | | | 1257 | |
1257 | ep->head = td[0]; | | 1258 | ep->head = td[0]; |
1258 | ep->tail = td[i]; | | 1259 | ep->tail = td[i]; |
1259 | segs = i; | | 1260 | segs = i; |
1260 | len = 0; | | 1261 | len = 0; |
1261 | | | 1262 | |
1262 | if (xfer->ux_length) | | 1263 | if (xfer->ux_length) |
1263 | usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length, | | 1264 | usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length, |
1264 | isread ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); | | 1265 | isread ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); |
1265 | | | 1266 | |
1266 | /* printf("segs: %d\n",segs); | | 1267 | /* printf("segs: %d\n",segs); |
1267 | printf("ep: %p\n",ep); | | 1268 | printf("ep: %p\n",ep); |
1268 | printf("ep->control: %x\n",ep->control); | | 1269 | printf("ep->control: %x\n",ep->control); |
1269 | printf("ep->next: %p\n",ep->next); | | 1270 | printf("ep->next: %p\n",ep->next); |
1270 | printf("ep->head: %p\n",ep->head); | | 1271 | printf("ep->head: %p\n",ep->head); |
1271 | printf("ep->tail: %p\n",ep->tail); | | 1272 | printf("ep->tail: %p\n",ep->tail); |
1272 | for (i=0; i<segs; i++) { | | 1273 | for (i=0; i<segs; i++) { |
1273 | printf("td[%d]: %p\n",i,td[i]); | | 1274 | printf("td[%d]: %p\n",i,td[i]); |
1274 | printf("td[%d]->control: %x\n",i,td[i]->control); | | 1275 | printf("td[%d]->control: %x\n",i,td[i]->control); |
1275 | printf("td[%d]->next: %p\n",i,td[i]->next); | | 1276 | printf("td[%d]->next: %p\n",i,td[i]->next); |
1276 | printf("td[%d]->buffer: %x\n",i,td[i]->buffer); | | 1277 | printf("td[%d]->buffer: %x\n",i,td[i]->buffer); |
1277 | printf("td[%d]->buflen: %x\n",i,td[i]->buflen); | | 1278 | printf("td[%d]->buflen: %x\n",i,td[i]->buflen); |
1278 | }; */ | | 1279 | }; */ |
1279 | | | 1280 | |
1280 | REG_WRITE(ADMHCD_REG_HOSTHEAD, (uint32_t)ep); | | 1281 | REG_WRITE(ADMHCD_REG_HOSTHEAD, (uint32_t)ep); |
1281 | REG_WRITE(ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP | ADMHCD_DMA_EN); | | 1282 | REG_WRITE(ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP | ADMHCD_DMA_EN); |
1282 | i = 0; | | 1283 | i = 0; |
1283 | /* printf("1: %x %d %x %x\n", ep->control, i, td[i]->control, td[i]->buflen); */ | | 1284 | /* printf("1: %x %d %x %x\n", ep->control, i, td[i]->control, td[i]->buflen); */ |
1284 | s=100; | | 1285 | s=100; |
1285 | err = 0; | | 1286 | err = 0; |
1286 | while (s--) { | | 1287 | while (s--) { |
1287 | /* printf("%x %d %x %x\n", ep->control, i, td[i]->control, td[i]->buflen); */ | | 1288 | /* printf("%x %d %x %x\n", ep->control, i, td[i]->control, td[i]->buflen); */ |
1288 | status = USBD_TIMEOUT; | | 1289 | status = USBD_TIMEOUT; |
1289 | if (td[i]->control & ADMHCD_TD_OWN) { | | 1290 | if (td[i]->control & ADMHCD_TD_OWN) { |
1290 | delay_ms(3); | | 1291 | delay_ms(3); |
1291 | continue; | | 1292 | continue; |
1292 | }; | | 1293 | }; |
1293 | | | 1294 | |
1294 | len += td[i]->len - td[i]->buflen; | | 1295 | len += td[i]->len - td[i]->buflen; |
1295 | | | 1296 | |
1296 | err = (td[i]->control & ADMHCD_TD_ERRMASK)>>ADMHCD_TD_ERRSHIFT; | | 1297 | err = (td[i]->control & ADMHCD_TD_ERRMASK)>>ADMHCD_TD_ERRSHIFT; |
1297 | if (err) { | | 1298 | if (err) { |
1298 | status = USBD_IOERROR; | | 1299 | status = USBD_IOERROR; |
1299 | break; | | 1300 | break; |
1300 | }; | | 1301 | }; |
1301 | | | 1302 | |
1302 | i++; | | 1303 | i++; |
1303 | if (i==segs) { | | 1304 | if (i==segs) { |
1304 | status = USBD_NORMAL_COMPLETION; | | 1305 | status = USBD_NORMAL_COMPLETION; |
1305 | break; | | 1306 | break; |
1306 | }; | | 1307 | }; |
1307 | | | 1308 | |
1308 | }; | | 1309 | }; |
1309 | REG_WRITE(ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP); | | 1310 | REG_WRITE(ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP); |
1310 | | | 1311 | |
1311 | apipe->toggle = ((uint32_t)ep->head & 2)?ADMHCD_TD_DATA1:ADMHCD_TD_DATA0; | | 1312 | apipe->toggle = ((uint32_t)ep->head & 2)?ADMHCD_TD_DATA1:ADMHCD_TD_DATA0; |
1312 | /* printf("bulk_transfer_done: status: %x, err: %x, len: %x, toggle: %x\n", status,err,len,apipe->toggle); */ | | 1313 | /* printf("bulk_transfer_done: status: %x, err: %x, len: %x, toggle: %x\n", status,err,len,apipe->toggle); */ |
1313 | | | 1314 | |
1314 | if (short_ok && (err == 0x9 || err == 0xd)) { | | 1315 | if (short_ok && (err == 0x9 || err == 0xd)) { |
1315 | /* printf("bulk_transfer_done: short_transfer fix\n"); */ | | 1316 | /* printf("bulk_transfer_done: short_transfer fix\n"); */ |
1316 | status = USBD_NORMAL_COMPLETION; | | 1317 | status = USBD_NORMAL_COMPLETION; |
1317 | }; | | 1318 | }; |
1318 | xfer->ux_actlen = len; | | 1319 | xfer->ux_actlen = len; |
1319 | xfer->ux_status = status; | | 1320 | xfer->ux_status = status; |
1320 | | | 1321 | |
1321 | level--; | | 1322 | level--; |
1322 | /* printf("bulk_start<<<\n"); */ | | 1323 | /* printf("bulk_start<<<\n"); */ |
1323 | | | 1324 | |
1324 | if (xfer->ux_length) | | 1325 | if (xfer->ux_length) |
1325 | usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length, | | 1326 | usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length, |
1326 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); | | 1327 | isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
1327 | | | 1328 | |
1328 | usb_transfer_complete(xfer); | | 1329 | usb_transfer_complete(xfer); |
1329 | mutex_exit(&sc->sc_lock); | | 1330 | mutex_exit(&sc->sc_lock); |
1330 | | | 1331 | |
1331 | return USBD_NORMAL_COMPLETION; | | 1332 | return USBD_NORMAL_COMPLETION; |
1332 | } | | 1333 | } |
1333 | | | 1334 | |
1334 | static void | | 1335 | static void |
1335 | ahci_device_bulk_abort(struct usbd_xfer *xfer) | | 1336 | ahci_device_bulk_abort(struct usbd_xfer *xfer) |
1336 | { | | 1337 | { |
1337 | DPRINTF(D_TRACE, ("Bab ")); | | 1338 | DPRINTF(D_TRACE, ("Bab ")); |
1338 | usbd_xfer_abort(xfer); | | 1339 | usbd_xfer_abort(xfer); |
1339 | } | | 1340 | } |
1340 | | | 1341 | |
1341 | static void | | 1342 | static void |
1342 | ahci_device_bulk_close(struct usbd_pipe *pipe) | | 1343 | ahci_device_bulk_close(struct usbd_pipe *pipe) |
1343 | { | | 1344 | { |
1344 | DPRINTF(D_TRACE, ("Bcl ")); | | 1345 | DPRINTF(D_TRACE, ("Bcl ")); |
1345 | } | | 1346 | } |
1346 | | | 1347 | |
1347 | static void | | 1348 | static void |
1348 | ahci_device_bulk_done(struct usbd_xfer *xfer) | | 1349 | ahci_device_bulk_done(struct usbd_xfer *xfer) |
1349 | { | | 1350 | { |
1350 | DPRINTF(D_TRACE, ("Bdn ")); | | 1351 | DPRINTF(D_TRACE, ("Bdn ")); |
1351 | } | | 1352 | } |
1352 | | | 1353 | |
1353 | #define DATA0_RD (0x03) | | 1354 | #define DATA0_RD (0x03) |
1354 | #define DATA0_WR (0x07) | | 1355 | #define DATA0_WR (0x07) |
1355 | #define AHCI_TIMEOUT (5000) | | 1356 | #define AHCI_TIMEOUT (5000) |
1356 | | | 1357 | |
1357 | /* | | 1358 | /* |
1358 | * Do a transaction. | | 1359 | * Do a transaction. |
1359 | * return 1 if ACK, 0 if NAK, -1 if error. | | 1360 | * return 1 if ACK, 0 if NAK, -1 if error. |
1360 | */ | | 1361 | */ |
1361 | static int | | 1362 | static int |
1362 | ahci_transaction(struct ahci_softc *sc, struct usbd_pipe *pipe, | | 1363 | ahci_transaction(struct ahci_softc *sc, struct usbd_pipe *pipe, |
1363 | uint8_t pid, int len, u_char *buf, uint8_t toggle) | | 1364 | uint8_t pid, int len, u_char *buf, uint8_t toggle) |
1364 | { | | 1365 | { |
1365 | return -1; | | 1366 | return -1; |
1366 | #if 0 | | 1367 | #if 0 |
1367 | #ifdef AHCI_DEBUG | | 1368 | #ifdef AHCI_DEBUG |
1368 | char str[64]; | | 1369 | char str[64]; |
1369 | int i; | | 1370 | int i; |
1370 | #endif | | 1371 | #endif |
1371 | int timeout; | | 1372 | int timeout; |
1372 | int ls_via_hub = 0; | | 1373 | int ls_via_hub = 0; |
1373 | int pl; | | 1374 | int pl; |
1374 | uint8_t isr; | | 1375 | uint8_t isr; |
1375 | uint8_t result = 0; | | 1376 | uint8_t result = 0; |
1376 | uint8_t devaddr = pipe->up_dev->ud_addr; | | 1377 | uint8_t devaddr = pipe->up_dev->ud_addr; |
1377 | uint8_t endpointaddr = pipe->up_endpoint->ue_edesc->bEndpointAddress; | | 1378 | uint8_t endpointaddr = pipe->up_endpoint->ue_edesc->bEndpointAddress; |
1378 | uint8_t endpoint; | | 1379 | uint8_t endpoint; |
1379 | uint8_t cmd = DATA0_RD; | | 1380 | uint8_t cmd = DATA0_RD; |
1380 | | | 1381 | |
1381 | endpoint = UE_GET_ADDR(endpointaddr); | | 1382 | endpoint = UE_GET_ADDR(endpointaddr); |
1382 | DPRINTF(D_XFER, ("\n(%x,%d%s%d,%d) ", | | 1383 | DPRINTF(D_XFER, ("\n(%x,%d%s%d,%d) ", |
1383 | pid, len, (pid == SL11_PID_IN) ? "<-" : "->", devaddr, endpoint)); | | 1384 | pid, len, (pid == SL11_PID_IN) ? "<-" : "->", devaddr, endpoint)); |
1384 | | | 1385 | |
1385 | /* Set registers */ | | 1386 | /* Set registers */ |
1386 | sl11write(sc, SL11_E0ADDR, 0x40); | | 1387 | sl11write(sc, SL11_E0ADDR, 0x40); |
1387 | sl11write(sc, SL11_E0LEN, len); | | 1388 | sl11write(sc, SL11_E0LEN, len); |
1388 | sl11write(sc, SL11_E0PID, (pid << 4) + endpoint); | | 1389 | sl11write(sc, SL11_E0PID, (pid << 4) + endpoint); |
1389 | sl11write(sc, SL11_E0DEV, devaddr); | | 1390 | sl11write(sc, SL11_E0DEV, devaddr); |
1390 | | | 1391 | |
1391 | /* Set buffer unless PID_IN */ | | 1392 | /* Set buffer unless PID_IN */ |
1392 | if (pid != SL11_PID_IN) { | | 1393 | if (pid != SL11_PID_IN) { |
1393 | if (len > 0) | | 1394 | if (len > 0) |
1394 | sl11write_region(sc, 0x40, buf, len); | | 1395 | sl11write_region(sc, 0x40, buf, len); |
1395 | cmd = DATA0_WR; | | 1396 | cmd = DATA0_WR; |
1396 | } | | 1397 | } |
1397 | | | 1398 | |
1398 | /* timing ? */ | | 1399 | /* timing ? */ |
1399 | pl = (len >> 3) + 3; | | 1400 | pl = (len >> 3) + 3; |
1400 | | | 1401 | |
1401 | /* Low speed device via HUB */ | | 1402 | /* Low speed device via HUB */ |
1402 | /* XXX does not work... */ | | 1403 | /* XXX does not work... */ |
1403 | if ((sc->sc_fullspeed) && pipe->up_dev->ud_speed == USB_SPEED_LOW) { | | 1404 | if ((sc->sc_fullspeed) && pipe->up_dev->ud_speed == USB_SPEED_LOW) { |
1404 | pl = len + 16; | | 1405 | pl = len + 16; |
1405 | cmd |= SL11_EPCTRL_PREAMBLE; | | 1406 | cmd |= SL11_EPCTRL_PREAMBLE; |
1406 | | | 1407 | |
1407 | /* | | 1408 | /* |
1408 | * SL811HS/T rev 1.2 has a bug, when it got PID_IN | | 1409 | * SL811HS/T rev 1.2 has a bug, when it got PID_IN |
1409 | * from LowSpeed device via HUB. | | 1410 | * from LowSpeed device via HUB. |
1410 | */ | | 1411 | */ |
1411 | if (sc->sc_sltype == SLTYPE_SL811HS_R12 && pid == SL11_PID_IN) { | | 1412 | if (sc->sc_sltype == SLTYPE_SL811HS_R12 && pid == SL11_PID_IN) { |
1412 | ls_via_hub = 1; | | 1413 | ls_via_hub = 1; |
1413 | DPRINTF(D_MSG, ("LSvH ")); | | 1414 | DPRINTF(D_MSG, ("LSvH ")); |
1414 | } | | 1415 | } |
1415 | } | | 1416 | } |
1416 | | | 1417 | |
1417 | /* timing ? */ | | 1418 | /* timing ? */ |
1418 | if (sl11read(sc, SL811_CSOF) <= (uint8_t)pl) | | 1419 | if (sl11read(sc, SL811_CSOF) <= (uint8_t)pl) |
1419 | cmd |= SL11_EPCTRL_SOF; | | 1420 | cmd |= SL11_EPCTRL_SOF; |
1420 | | | 1421 | |
1421 | /* Transfer */ | | 1422 | /* Transfer */ |
1422 | sl11write(sc, SL11_ISR, 0xff); | | 1423 | sl11write(sc, SL11_ISR, 0xff); |
1423 | sl11write(sc, SL11_E0CTRL, cmd | toggle); | | 1424 | sl11write(sc, SL11_E0CTRL, cmd | toggle); |
1424 | | | 1425 | |
1425 | /* Polling */ | | 1426 | /* Polling */ |
1426 | for (timeout = AHCI_TIMEOUT; timeout; timeout--) { | | 1427 | for (timeout = AHCI_TIMEOUT; timeout; timeout--) { |
1427 | isr = sl11read(sc, SL11_ISR); | | 1428 | isr = sl11read(sc, SL11_ISR); |
1428 | if ((isr & SL11_ISR_USBA)) | | 1429 | if ((isr & SL11_ISR_USBA)) |
1429 | break; | | 1430 | break; |
1430 | } | | 1431 | } |
1431 | | | 1432 | |
1432 | /* Check result status */ | | 1433 | /* Check result status */ |
1433 | result = sl11read(sc, SL11_E0STAT); | | 1434 | result = sl11read(sc, SL11_E0STAT); |
1434 | if (!(result & SL11_EPSTAT_NAK) && ls_via_hub) { | | 1435 | if (!(result & SL11_EPSTAT_NAK) && ls_via_hub) { |
1435 | /* Resend PID_IN within 20usec */ | | 1436 | /* Resend PID_IN within 20usec */ |
1436 | sl11write(sc, SL11_ISR, 0xff); | | 1437 | sl11write(sc, SL11_ISR, 0xff); |
1437 | sl11write(sc, SL11_E0CTRL, SL11_EPCTRL_ARM); | | 1438 | sl11write(sc, SL11_E0CTRL, SL11_EPCTRL_ARM); |
1438 | } | | 1439 | } |
1439 | | | 1440 | |
1440 | sl11write(sc, SL11_ISR, 0xff); | | 1441 | sl11write(sc, SL11_ISR, 0xff); |
1441 | | | 1442 | |
1442 | DPRINTF(D_XFER, ("t=%d i=%x ", AHCI_TIMEOUT - timeout, isr)); | | 1443 | DPRINTF(D_XFER, ("t=%d i=%x ", AHCI_TIMEOUT - timeout, isr)); |
1443 | #if AHCI_DEBUG | | 1444 | #if AHCI_DEBUG |
1444 | snprintb(str, sizeof(str), | | 1445 | snprintb(str, sizeof(str), |
1445 | "\20\x8STALL\7NAK\6OV\5SETUP\4DATA1\3TIMEOUT\2ERR\1ACK", result); | | 1446 | "\20\x8STALL\7NAK\6OV\5SETUP\4DATA1\3TIMEOUT\2ERR\1ACK", result); |
1446 | DPRINTF(D_XFER, ("STAT=%s ", str)); | | 1447 | DPRINTF(D_XFER, ("STAT=%s ", str)); |
1447 | #endif | | 1448 | #endif |
1448 | | | 1449 | |
1449 | if ((result & SL11_EPSTAT_ERROR)) | | 1450 | if ((result & SL11_EPSTAT_ERROR)) |
1450 | return -1; | | 1451 | return -1; |
1451 | | | 1452 | |
1452 | if ((result & SL11_EPSTAT_NAK)) | | 1453 | if ((result & SL11_EPSTAT_NAK)) |
1453 | return 0; | | 1454 | return 0; |
1454 | | | 1455 | |
1455 | /* Read buffer if PID_IN */ | | 1456 | /* Read buffer if PID_IN */ |
1456 | if (pid == SL11_PID_IN && len > 0) { | | 1457 | if (pid == SL11_PID_IN && len > 0) { |
1457 | sl11read_region(sc, buf, 0x40, len); | | 1458 | sl11read_region(sc, buf, 0x40, len); |
1458 | #if AHCI_DEBUG | | 1459 | #if AHCI_DEBUG |
1459 | for (i = 0; i < len; i++) | | 1460 | for (i = 0; i < len; i++) |
1460 | DPRINTF(D_XFER, ("%02X ", buf[i])); | | 1461 | DPRINTF(D_XFER, ("%02X ", buf[i])); |
1461 | #endif | | 1462 | #endif |
1462 | } | | 1463 | } |
1463 | | | 1464 | |
1464 | return 1; | | 1465 | return 1; |
1465 | #endif | | 1466 | #endif |
1466 | } | | 1467 | } |
1467 | | | 1468 | |
1468 | static void | | 1469 | static void |
1469 | ahci_abortx(struct usbd_xfer *xfer) | | 1470 | ahci_abortx(struct usbd_xfer *xfer) |
1470 | { | | 1471 | { |
1471 | /* | | 1472 | /* |
1472 | * XXX This is totally busted; there's no way it can possibly | | 1473 | * XXX This is totally busted; there's no way it can possibly |
1473 | * work! All transfers are busy-waited, it seems, so there is | | 1474 | * work! All transfers are busy-waited, it seems, so there is |
1474 | * no opportunity to abort. | | 1475 | * no opportunity to abort. |
1475 | */ | | 1476 | */ |
1476 | KASSERT(xfer->ux_status != USBD_IN_PROGRESS); | | 1477 | KASSERT(xfer->ux_status != USBD_IN_PROGRESS); |
1477 | } | | 1478 | } |
1478 | | | 1479 | |
1479 | void | | 1480 | void |
1480 | ahci_device_clear_toggle(struct usbd_pipe *pipe) | | 1481 | ahci_device_clear_toggle(struct usbd_pipe *pipe) |
1481 | { | | 1482 | { |
1482 | struct ahci_pipe *apipe = (struct ahci_pipe *)pipe; | | 1483 | struct ahci_pipe *apipe = (struct ahci_pipe *)pipe; |
1483 | apipe->toggle = 0; | | 1484 | apipe->toggle = 0; |
1484 | } | | 1485 | } |
1485 | | | 1486 | |
1486 | #ifdef AHCI_DEBUG | | 1487 | #ifdef AHCI_DEBUG |
1487 | void | | 1488 | void |
1488 | print_req(usb_device_request_t *r) | | 1489 | print_req(usb_device_request_t *r) |
1489 | { | | 1490 | { |
1490 | const char *xmes[]={ | | 1491 | const char *xmes[]={ |
1491 | "GETSTAT", | | 1492 | "GETSTAT", |
1492 | "CLRFEAT", | | 1493 | "CLRFEAT", |
1493 | "res", | | 1494 | "res", |
1494 | "SETFEAT", | | 1495 | "SETFEAT", |
1495 | "res", | | 1496 | "res", |
1496 | "SETADDR", | | 1497 | "SETADDR", |
1497 | "GETDESC", | | 1498 | "GETDESC", |
1498 | "SETDESC", | | 1499 | "SETDESC", |
1499 | "GETCONF", | | 1500 | "GETCONF", |
1500 | "SETCONF", | | 1501 | "SETCONF", |
1501 | "GETIN/F", | | 1502 | "GETIN/F", |
1502 | "SETIN/F", | | 1503 | "SETIN/F", |
1503 | "SYNC_FR" | | 1504 | "SYNC_FR" |
1504 | }; | | 1505 | }; |
1505 | int req, type, value, index, len; | | 1506 | int req, type, value, index, len; |
1506 | | | 1507 | |
1507 | req = r->bRequest; | | 1508 | req = r->bRequest; |
1508 | type = r->bmRequestType; | | 1509 | type = r->bmRequestType; |
1509 | value = UGETW(r->wValue); | | 1510 | value = UGETW(r->wValue); |
1510 | index = UGETW(r->wIndex); | | 1511 | index = UGETW(r->wIndex); |
1511 | len = UGETW(r->wLength); | | 1512 | len = UGETW(r->wLength); |
1512 | | | 1513 | |
1513 | printf("%x,%s,v=%d,i=%d,l=%d ", | | 1514 | printf("%x,%s,v=%d,i=%d,l=%d ", |
1514 | type, xmes[req], value, index, len); | | 1515 | type, xmes[req], value, index, len); |
1515 | } | | 1516 | } |
1516 | | | 1517 | |
1517 | void | | 1518 | void |
1518 | print_req_hub(usb_device_request_t *r) | | 1519 | print_req_hub(usb_device_request_t *r) |
1519 | { | | 1520 | { |
1520 | struct { | | 1521 | struct { |
1521 | int req; | | 1522 | int req; |
1522 | int type; | | 1523 | int type; |
1523 | const char *str; | | 1524 | const char *str; |
1524 | } conf[] = { | | 1525 | } conf[] = { |
1525 | { 1, 0x20, "ClrHubFeat" }, | | 1526 | { 1, 0x20, "ClrHubFeat" }, |
1526 | { 1, 0x23, "ClrPortFeat" }, | | 1527 | { 1, 0x23, "ClrPortFeat" }, |
1527 | { 2, 0xa3, "GetBusState" }, | | 1528 | { 2, 0xa3, "GetBusState" }, |
1528 | { 6, 0xa0, "GetHubDesc" }, | | 1529 | { 6, 0xa0, "GetHubDesc" }, |
1529 | { 0, 0xa0, "GetHubStat" }, | | 1530 | { 0, 0xa0, "GetHubStat" }, |
1530 | { 0, 0xa3, "GetPortStat" }, | | 1531 | { 0, 0xa3, "GetPortStat" }, |
1531 | { 7, 0x20, "SetHubDesc" }, | | 1532 | { 7, 0x20, "SetHubDesc" }, |
1532 | { 3, 0x20, "SetHubFeat" }, | | 1533 | { 3, 0x20, "SetHubFeat" }, |
1533 | { 3, 0x23, "SetPortFeat" }, | | 1534 | { 3, 0x23, "SetPortFeat" }, |
1534 | {-1, 0, NULL}, | | 1535 | {-1, 0, NULL}, |
1535 | }; | | 1536 | }; |
1536 | int i; | | 1537 | int i; |
1537 | int value, index, len; | | 1538 | int value, index, len; |
1538 | | | 1539 | |
1539 | value = UGETW(r->wValue); | | 1540 | value = UGETW(r->wValue); |
1540 | index = UGETW(r->wIndex); | | 1541 | index = UGETW(r->wIndex); |
1541 | len = UGETW(r->wLength); | | 1542 | len = UGETW(r->wLength); |
1542 | for (i = 0; ; i++) { | | 1543 | for (i = 0; ; i++) { |
1543 | if (conf[i].req == -1 ) | | 1544 | if (conf[i].req == -1 ) |
1544 | return print_req(r); | | 1545 | return print_req(r); |
1545 | if (r->bmRequestType == conf[i].type && r->bRequest == conf[i].req) { | | 1546 | if (r->bmRequestType == conf[i].type && r->bRequest == conf[i].req) { |
1546 | printf("%s", conf[i].str); | | 1547 | printf("%s", conf[i].str); |
1547 | break; | | 1548 | break; |
1548 | } | | 1549 | } |
1549 | } | | 1550 | } |
1550 | printf(",v=%d,i=%d,l=%d ", value, index, len); | | 1551 | printf(",v=%d,i=%d,l=%d ", value, index, len); |
1551 | } | | 1552 | } |
1552 | | | 1553 | |
1553 | void | | 1554 | void |
1554 | print_dumpreg(struct ahci_softc *sc) | | 1555 | print_dumpreg(struct ahci_softc *sc) |
1555 | { | | 1556 | { |
1556 | #if 0 | | 1557 | #if 0 |
1557 | printf("00=%02x,01=%02x,02=%02x,03=%02x,04=%02x," | | 1558 | printf("00=%02x,01=%02x,02=%02x,03=%02x,04=%02x," |
1558 | "08=%02x,09=%02x,0A=%02x,0B=%02x,0C=%02x,", | | 1559 | "08=%02x,09=%02x,0A=%02x,0B=%02x,0C=%02x,", |
1559 | sl11read(sc, 0), sl11read(sc, 1), | | 1560 | sl11read(sc, 0), sl11read(sc, 1), |
1560 | sl11read(sc, 2), sl11read(sc, 3), | | 1561 | sl11read(sc, 2), sl11read(sc, 3), |
1561 | sl11read(sc, 4), sl11read(sc, 8), | | 1562 | sl11read(sc, 4), sl11read(sc, 8), |
1562 | sl11read(sc, 9), sl11read(sc, 10), | | 1563 | sl11read(sc, 9), sl11read(sc, 10), |
1563 | sl11read(sc, 11), sl11read(sc, 12) | | 1564 | sl11read(sc, 11), sl11read(sc, 12) |
1564 | ); | | 1565 | ); |
1565 | printf("CR1=%02x,IER=%02x,0D=%02x,0E=%02x,0F=%02x ", | | 1566 | printf("CR1=%02x,IER=%02x,0D=%02x,0E=%02x,0F=%02x ", |
1566 | sl11read(sc, 5), sl11read(sc, 6), | | 1567 | sl11read(sc, 5), sl11read(sc, 6), |
1567 | sl11read(sc, 13), sl11read(sc, 14), sl11read(sc, 15) | | 1568 | sl11read(sc, 13), sl11read(sc, 14), sl11read(sc, 15) |
1568 | ); | | 1569 | ); |
1569 | #endif | | 1570 | #endif |
1570 | } | | 1571 | } |
1571 | | | 1572 | |
1572 | void | | 1573 | void |
1573 | print_xfer(struct usbd_xfer *xfer) | | 1574 | print_xfer(struct usbd_xfer *xfer) |
1574 | { | | 1575 | { |
1575 | printf("xfer: length=%d, actlen=%d, flags=%x, timeout=%d,", | | 1576 | printf("xfer: length=%d, actlen=%d, flags=%x, timeout=%d,", |
1576 | xfer->ux_length, xfer->ux_actlen, xfer->ux_flags, xfer->ux_timeout); | | 1577 | xfer->ux_length, xfer->ux_actlen, xfer->ux_flags, xfer->ux_timeout); |
1577 | printf("request{ "); | | 1578 | printf("request{ "); |
1578 | print_req_hub(&xfer->ux_request); | | 1579 | print_req_hub(&xfer->ux_request); |
1579 | printf("} "); | | 1580 | printf("} "); |
1580 | } | | 1581 | } |
1581 | #endif /* AHCI_DEBUG */ | | 1582 | #endif /* AHCI_DEBUG */ |