| @@ -1,1062 +1,1062 @@ | | | @@ -1,1062 +1,1062 @@ |
1 | /* $NetBSD: dwc_otg.c,v 1.32 2013/01/21 13:25:44 skrll Exp $ */ | | 1 | /* $NetBSD: dwc_otg.c,v 1.33 2013/01/22 13:03:25 skrll Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2012 Hans Petter Selasky. All rights reserved. | | 4 | * Copyright (c) 2012 Hans Petter Selasky. All rights reserved. |
5 | * Copyright (c) 2010-2011 Aleksandr Rybalko. All rights reserved. | | 5 | * Copyright (c) 2010-2011 Aleksandr Rybalko. All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * 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 copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * | | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | | 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | /*- | | 29 | /*- |
30 | * Copyright (c) 2013 The NetBSD Foundation, Inc. | | 30 | * Copyright (c) 2013 The NetBSD Foundation, Inc. |
31 | * All rights reserved. | | 31 | * All rights reserved. |
32 | * | | 32 | * |
33 | * This code is derived from software contributed to The NetBSD Foundation | | 33 | * This code is derived from software contributed to The NetBSD Foundation |
34 | * by Nick Hudson | | 34 | * by Nick Hudson |
35 | * | | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | | 36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions | | 37 | * modification, are permitted provided that the following conditions |
38 | * are met: | | 38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright | | 39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. | | 40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright | | 41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the | | 42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. | | 43 | * documentation and/or other materials provided with the distribution. |
44 | * | | 44 | * |
45 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 45 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
46 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 46 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
47 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 47 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
48 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 48 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
49 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 49 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
50 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 50 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
51 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 51 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
52 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 52 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
53 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 53 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
54 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 54 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
55 | * POSSIBILITY OF SUCH DAMAGE. | | 55 | * POSSIBILITY OF SUCH DAMAGE. |
56 | */ | | 56 | */ |
57 | | | 57 | |
58 | /* | | 58 | /* |
59 | * Designware USB 2.0 OTG | | 59 | * Designware USB 2.0 OTG |
60 | */ | | 60 | */ |
61 | | | 61 | |
62 | #include <sys/cdefs.h> | | 62 | #include <sys/cdefs.h> |
63 | __KERNEL_RCSID(0, "$NetBSD: dwc_otg.c,v 1.32 2013/01/21 13:25:44 skrll Exp $"); | | 63 | __KERNEL_RCSID(0, "$NetBSD: dwc_otg.c,v 1.33 2013/01/22 13:03:25 skrll Exp $"); |
64 | | | 64 | |
65 | #include <sys/param.h> | | 65 | #include <sys/param.h> |
66 | #include <sys/systm.h> | | 66 | #include <sys/systm.h> |
67 | #include <sys/kmem.h> | | 67 | #include <sys/kmem.h> |
68 | #include <sys/kernel.h> | | 68 | #include <sys/kernel.h> |
69 | #include <sys/device.h> | | 69 | #include <sys/device.h> |
70 | #include <sys/select.h> | | 70 | #include <sys/select.h> |
71 | #include <sys/proc.h> | | 71 | #include <sys/proc.h> |
72 | #include <sys/queue.h> | | 72 | #include <sys/queue.h> |
73 | #include <sys/cpu.h> | | 73 | #include <sys/cpu.h> |
74 | | | 74 | |
75 | #include <machine/endian.h> | | 75 | #include <machine/endian.h> |
76 | | | 76 | |
77 | #include <dev/usb/usb.h> | | 77 | #include <dev/usb/usb.h> |
78 | #include <dev/usb/usbdi.h> | | 78 | #include <dev/usb/usbdi.h> |
79 | #include <dev/usb/usbdivar.h> | | 79 | #include <dev/usb/usbdivar.h> |
80 | #include <dev/usb/usb_mem.h> | | 80 | #include <dev/usb/usb_mem.h> |
81 | | | 81 | |
82 | #include <dev/usb/dwc_otgreg.h> | | 82 | #include <dev/usb/dwc_otgreg.h> |
83 | #include <dev/usb/dwc_otgvar.h> | | 83 | #include <dev/usb/dwc_otgvar.h> |
84 | | | 84 | |
85 | #include <dev/usb/usbroothub_subr.h> | | 85 | #include <dev/usb/usbroothub_subr.h> |
86 | | | 86 | |
87 | #ifdef DOTG_COUNTERS | | 87 | #ifdef DOTG_COUNTERS |
88 | #define DOTG_EVCNT_ADD(a,b) ((void)((a).ev_count += (b))) | | 88 | #define DOTG_EVCNT_ADD(a,b) ((void)((a).ev_count += (b))) |
89 | #else | | 89 | #else |
90 | #define DOTG_EVCNT_ADD(a,b) do { } while (/*CONSTCOND*/0) | | 90 | #define DOTG_EVCNT_ADD(a,b) do { } while (/*CONSTCOND*/0) |
91 | #endif | | 91 | #endif |
92 | #define DOTG_EVCNT_INCR(a) DOTG_EVCNT_ADD((a), 1) | | 92 | #define DOTG_EVCNT_INCR(a) DOTG_EVCNT_ADD((a), 1) |
93 | | | 93 | |
94 | #ifdef DWC_OTG_DEBUG | | 94 | #ifdef DWC_OTG_DEBUG |
95 | #define DPRINTFN(n,fmt,...) do { \ | | 95 | #define DPRINTFN(n,fmt,...) do { \ |
96 | if (dwc_otgdebug >= (n)) { \ | | 96 | if (dwc_otgdebug >= (n)) { \ |
97 | printf("%s: " fmt, \ | | 97 | printf("%s: " fmt, \ |
98 | __FUNCTION__,## __VA_ARGS__); \ | | 98 | __FUNCTION__,## __VA_ARGS__); \ |
99 | } \ | | 99 | } \ |
100 | } while (0) | | 100 | } while (0) |
101 | #define DPRINTF(...) DPRINTFN(1, __VA_ARGS__) | | 101 | #define DPRINTF(...) DPRINTFN(1, __VA_ARGS__) |
102 | int dwc_otgdebug = 0; | | 102 | int dwc_otgdebug = 0; |
103 | #else | | 103 | #else |
104 | #define DPRINTF(...) do { } while (0) | | 104 | #define DPRINTF(...) do { } while (0) |
105 | #define DPRINTFN(...) do { } while (0) | | 105 | #define DPRINTFN(...) do { } while (0) |
106 | #endif | | 106 | #endif |
107 | | | 107 | |
108 | #define DWC_OTG_MSK_GINT_ENABLED \ | | 108 | #define DWC_OTG_MSK_GINT_ENABLED \ |
109 | (GINTMSK_ENUMDONEMSK | \ | | 109 | (GINTMSK_ENUMDONEMSK | \ |
110 | GINTMSK_USBRSTMSK | \ | | 110 | GINTMSK_USBRSTMSK | \ |
111 | GINTMSK_USBSUSPMSK | \ | | 111 | GINTMSK_USBSUSPMSK | \ |
112 | GINTMSK_IEPINTMSK | \ | | 112 | GINTMSK_IEPINTMSK | \ |
113 | GINTMSK_RXFLVLMSK | \ | | 113 | GINTMSK_RXFLVLMSK | \ |
114 | GINTMSK_SESSREQINTMSK | \ | | 114 | GINTMSK_SESSREQINTMSK | \ |
115 | GINTMSK_OTGINTMSK | \ | | 115 | GINTMSK_OTGINTMSK | \ |
116 | GINTMSK_HCHINTMSK | \ | | 116 | GINTMSK_HCHINTMSK | \ |
117 | GINTMSK_PRTINTMSK) | | 117 | GINTMSK_PRTINTMSK) |
118 | | | 118 | |
119 | #define DWC_OTG_BUS2SC(bus) ((bus)->hci_private) | | 119 | #define DWC_OTG_BUS2SC(bus) ((bus)->hci_private) |
120 | | | 120 | |
121 | #define DWC_OTG_XFER2SC(xfer) DWC_OTG_BUS2SC((xfer)->pipe->device->bus) | | 121 | #define DWC_OTG_XFER2SC(xfer) DWC_OTG_BUS2SC((xfer)->pipe->device->bus) |
122 | | | 122 | |
123 | #define DWC_OTG_TD2SC(td) DWC_OTG_XFER2SC((td)->xfer) | | 123 | #define DWC_OTG_TD2SC(td) DWC_OTG_XFER2SC((td)->xfer) |
124 | | | 124 | |
125 | #define DWC_OTG_DPIPE2SC(d) \ | | 125 | #define DWC_OTG_DPIPE2SC(d) \ |
126 | DWC_OTG_BUS2SC((d)->pipe.device->bus) | | 126 | DWC_OTG_BUS2SC((d)->pipe.device->bus) |
127 | | | 127 | |
128 | #define DWC_OTG_XFER2DXFER(x) (struct dwc_otg_xfer *)(x) | | 128 | #define DWC_OTG_XFER2DXFER(x) (struct dwc_otg_xfer *)(x) |
129 | | | 129 | |
130 | #define DWC_OTG_XFER2DPIPE(x) (struct dwc_otg_pipe *)(x)->pipe; | | 130 | #define DWC_OTG_XFER2DPIPE(x) (struct dwc_otg_pipe *)(x)->pipe; |
131 | | | 131 | |
132 | #define usbd_copy_in(d, o, b, s) \ | | 132 | #define usbd_copy_in(d, o, b, s) \ |
133 | memcpy(((char *)(d) + (o)), (b), (s)) | | 133 | memcpy(((char *)(d) + (o)), (b), (s)) |
134 | | | 134 | |
135 | #define usbd_copy_out(d, o, b, s) \ | | 135 | #define usbd_copy_out(d, o, b, s) \ |
136 | memcpy((b), ((char *)(d) + (o)), (s)) | | 136 | memcpy((b), ((char *)(d) + (o)), (s)) |
137 | | | 137 | |
138 | struct dwc_otg_pipe; | | 138 | struct dwc_otg_pipe; |
139 | | | 139 | |
140 | Static usbd_status dwc_otg_open(usbd_pipe_handle); | | 140 | Static usbd_status dwc_otg_open(usbd_pipe_handle); |
141 | Static void dwc_otg_poll(struct usbd_bus *); | | 141 | Static void dwc_otg_poll(struct usbd_bus *); |
142 | Static void dwc_otg_softintr(void *); | | 142 | Static void dwc_otg_softintr(void *); |
143 | Static void dwc_otg_waitintr(struct dwc_otg_softc *, usbd_xfer_handle); | | 143 | Static void dwc_otg_waitintr(struct dwc_otg_softc *, usbd_xfer_handle); |
144 | | | 144 | |
145 | Static usbd_status dwc_otg_allocm(struct usbd_bus *, usb_dma_t *, uint32_t); | | 145 | Static usbd_status dwc_otg_allocm(struct usbd_bus *, usb_dma_t *, uint32_t); |
146 | Static void dwc_otg_freem(struct usbd_bus *, usb_dma_t *); | | 146 | Static void dwc_otg_freem(struct usbd_bus *, usb_dma_t *); |
147 | | | 147 | |
148 | Static usbd_xfer_handle dwc_otg_allocx(struct usbd_bus *); | | 148 | Static usbd_xfer_handle dwc_otg_allocx(struct usbd_bus *); |
149 | Static void dwc_otg_freex(struct usbd_bus *, usbd_xfer_handle); | | 149 | Static void dwc_otg_freex(struct usbd_bus *, usbd_xfer_handle); |
150 | Static void dwc_otg_get_lock(struct usbd_bus *, kmutex_t **); | | 150 | Static void dwc_otg_get_lock(struct usbd_bus *, kmutex_t **); |
151 | | | 151 | |
152 | #if 0 | | 152 | #if 0 |
153 | Static usbd_status dwc_otg_setup_isoc(usbd_pipe_handle pipe); | | 153 | Static usbd_status dwc_otg_setup_isoc(usbd_pipe_handle pipe); |
154 | Static void dwc_otg_device_isoc_enter(usbd_xfer_handle); | | 154 | Static void dwc_otg_device_isoc_enter(usbd_xfer_handle); |
155 | #endif | | 155 | #endif |
156 | | | 156 | |
157 | Static usbd_status dwc_otg_root_ctrl_transfer(usbd_xfer_handle); | | 157 | Static usbd_status dwc_otg_root_ctrl_transfer(usbd_xfer_handle); |
158 | Static usbd_status dwc_otg_root_ctrl_start(usbd_xfer_handle); | | 158 | Static usbd_status dwc_otg_root_ctrl_start(usbd_xfer_handle); |
159 | Static void dwc_otg_root_ctrl_abort(usbd_xfer_handle); | | 159 | Static void dwc_otg_root_ctrl_abort(usbd_xfer_handle); |
160 | Static void dwc_otg_root_ctrl_close(usbd_pipe_handle); | | 160 | Static void dwc_otg_root_ctrl_close(usbd_pipe_handle); |
161 | Static void dwc_otg_root_ctrl_done(usbd_xfer_handle); | | 161 | Static void dwc_otg_root_ctrl_done(usbd_xfer_handle); |
162 | | | 162 | |
163 | Static usbd_status dwc_otg_root_intr_transfer(usbd_xfer_handle); | | 163 | Static usbd_status dwc_otg_root_intr_transfer(usbd_xfer_handle); |
164 | Static usbd_status dwc_otg_root_intr_start(usbd_xfer_handle); | | 164 | Static usbd_status dwc_otg_root_intr_start(usbd_xfer_handle); |
165 | Static void dwc_otg_root_intr_abort(usbd_xfer_handle); | | 165 | Static void dwc_otg_root_intr_abort(usbd_xfer_handle); |
166 | Static void dwc_otg_root_intr_close(usbd_pipe_handle); | | 166 | Static void dwc_otg_root_intr_close(usbd_pipe_handle); |
167 | Static void dwc_otg_root_intr_done(usbd_xfer_handle); | | 167 | Static void dwc_otg_root_intr_done(usbd_xfer_handle); |
168 | | | 168 | |
169 | Static usbd_status dwc_otg_device_ctrl_transfer(usbd_xfer_handle); | | 169 | Static usbd_status dwc_otg_device_ctrl_transfer(usbd_xfer_handle); |
170 | Static usbd_status dwc_otg_device_ctrl_start(usbd_xfer_handle); | | 170 | Static usbd_status dwc_otg_device_ctrl_start(usbd_xfer_handle); |
171 | Static void dwc_otg_device_ctrl_abort(usbd_xfer_handle); | | 171 | Static void dwc_otg_device_ctrl_abort(usbd_xfer_handle); |
172 | Static void dwc_otg_device_ctrl_close(usbd_pipe_handle); | | 172 | Static void dwc_otg_device_ctrl_close(usbd_pipe_handle); |
173 | Static void dwc_otg_device_ctrl_done(usbd_xfer_handle); | | 173 | Static void dwc_otg_device_ctrl_done(usbd_xfer_handle); |
174 | | | 174 | |
175 | Static usbd_status dwc_otg_device_bulk_transfer(usbd_xfer_handle); | | 175 | Static usbd_status dwc_otg_device_bulk_transfer(usbd_xfer_handle); |
176 | Static usbd_status dwc_otg_device_bulk_start(usbd_xfer_handle); | | 176 | Static usbd_status dwc_otg_device_bulk_start(usbd_xfer_handle); |
177 | Static void dwc_otg_device_bulk_abort(usbd_xfer_handle); | | 177 | Static void dwc_otg_device_bulk_abort(usbd_xfer_handle); |
178 | Static void dwc_otg_device_bulk_close(usbd_pipe_handle); | | 178 | Static void dwc_otg_device_bulk_close(usbd_pipe_handle); |
179 | Static void dwc_otg_device_bulk_done(usbd_xfer_handle); | | 179 | Static void dwc_otg_device_bulk_done(usbd_xfer_handle); |
180 | | | 180 | |
181 | Static usbd_status dwc_otg_device_intr_transfer(usbd_xfer_handle); | | 181 | Static usbd_status dwc_otg_device_intr_transfer(usbd_xfer_handle); |
182 | Static usbd_status dwc_otg_device_intr_start(usbd_xfer_handle); | | 182 | Static usbd_status dwc_otg_device_intr_start(usbd_xfer_handle); |
183 | Static void dwc_otg_device_intr_abort(usbd_xfer_handle); | | 183 | Static void dwc_otg_device_intr_abort(usbd_xfer_handle); |
184 | Static void dwc_otg_device_intr_close(usbd_pipe_handle); | | 184 | Static void dwc_otg_device_intr_close(usbd_pipe_handle); |
185 | Static void dwc_otg_device_intr_done(usbd_xfer_handle); | | 185 | Static void dwc_otg_device_intr_done(usbd_xfer_handle); |
186 | | | 186 | |
187 | Static usbd_status dwc_otg_device_isoc_transfer(usbd_xfer_handle); | | 187 | Static usbd_status dwc_otg_device_isoc_transfer(usbd_xfer_handle); |
188 | Static usbd_status dwc_otg_device_isoc_start(usbd_xfer_handle); | | 188 | Static usbd_status dwc_otg_device_isoc_start(usbd_xfer_handle); |
189 | Static void dwc_otg_device_isoc_abort(usbd_xfer_handle); | | 189 | Static void dwc_otg_device_isoc_abort(usbd_xfer_handle); |
190 | Static void dwc_otg_device_isoc_close(usbd_pipe_handle); | | 190 | Static void dwc_otg_device_isoc_close(usbd_pipe_handle); |
191 | Static void dwc_otg_device_isoc_done(usbd_xfer_handle); | | 191 | Static void dwc_otg_device_isoc_done(usbd_xfer_handle); |
192 | | | 192 | |
193 | #if 0 | | 193 | #if 0 |
194 | Static void dwc_otg_close_pipe(usbd_pipe_handle, dwc_otg_soft_ed_t *); | | 194 | Static void dwc_otg_close_pipe(usbd_pipe_handle, dwc_otg_soft_ed_t *); |
195 | #endif | | 195 | #endif |
196 | Static void dwc_otg_abort_xfer(usbd_xfer_handle, usbd_status); | | 196 | Static void dwc_otg_abort_xfer(usbd_xfer_handle, usbd_status); |
197 | | | 197 | |
198 | Static void dwc_otg_device_clear_toggle(usbd_pipe_handle pipe); | | 198 | Static void dwc_otg_device_clear_toggle(usbd_pipe_handle pipe); |
199 | Static void dwc_otg_noop(usbd_pipe_handle pipe); | | 199 | Static void dwc_otg_noop(usbd_pipe_handle pipe); |
200 | | | 200 | |
201 | #ifdef DWC_OTG_DEBUG | | 201 | #ifdef DWC_OTG_DEBUG |
202 | Static void dwc_otg_dump_global_regs(struct dwc_otg_softc *); | | 202 | Static void dwc_otg_dump_global_regs(struct dwc_otg_softc *); |
203 | Static void dwc_otg_dump_host_regs(struct dwc_otg_softc *); | | 203 | Static void dwc_otg_dump_host_regs(struct dwc_otg_softc *); |
204 | #endif | | 204 | #endif |
205 | | | 205 | |
206 | Static void dwc_otg_setup_data_chain(usbd_xfer_handle); | | 206 | Static void dwc_otg_setup_data_chain(usbd_xfer_handle); |
207 | Static void dwc_otg_setup_ctrl_chain(usbd_xfer_handle); | | 207 | Static void dwc_otg_setup_ctrl_chain(usbd_xfer_handle); |
208 | Static void dwc_otg_setup_intr_chain(usbd_xfer_handle); | | 208 | Static void dwc_otg_setup_intr_chain(usbd_xfer_handle); |
209 | Static void dwc_otg_setup_bulk_chain(usbd_xfer_handle); | | 209 | Static void dwc_otg_setup_bulk_chain(usbd_xfer_handle); |
210 | //Static void dwc_otg_setup_isoc_chain(usbd_xfer_handle); | | 210 | //Static void dwc_otg_setup_isoc_chain(usbd_xfer_handle); |
211 | | | 211 | |
212 | Static void dwc_otg_timeout(void *); | | 212 | Static void dwc_otg_timeout(void *); |
213 | Static void dwc_otg_timeout_task(void *); | | 213 | Static void dwc_otg_timeout_task(void *); |
214 | | | 214 | |
215 | Static void dwc_otg_xfer_setup(usbd_xfer_handle); | | 215 | Static void dwc_otg_xfer_setup(usbd_xfer_handle); |
216 | Static void dwc_otg_xfer_start(usbd_xfer_handle); | | 216 | Static void dwc_otg_xfer_start(usbd_xfer_handle); |
217 | Static void dwc_otg_xfer_end(usbd_xfer_handle); | | 217 | Static void dwc_otg_xfer_end(usbd_xfer_handle); |
218 | | | 218 | |
219 | // static dwc_otg_cmd_t dwc_otg_setup_rx; | | 219 | // static dwc_otg_cmd_t dwc_otg_setup_rx; |
220 | // static dwc_otg_cmd_t dwc_otg_data_rx; | | 220 | // static dwc_otg_cmd_t dwc_otg_data_rx; |
221 | // static dwc_otg_cmd_t dwc_otg_data_tx; | | 221 | // static dwc_otg_cmd_t dwc_otg_data_tx; |
222 | // static dwc_otg_cmd_t dwc_otg_data_tx_sync; | | 222 | // static dwc_otg_cmd_t dwc_otg_data_tx_sync; |
223 | | | 223 | |
224 | static dwc_otg_cmd_t dwc_otg_host_setup_tx; | | 224 | static dwc_otg_cmd_t dwc_otg_host_setup_tx; |
225 | static dwc_otg_cmd_t dwc_otg_host_data_tx; | | 225 | static dwc_otg_cmd_t dwc_otg_host_data_tx; |
226 | static dwc_otg_cmd_t dwc_otg_host_data_rx; | | 226 | static dwc_otg_cmd_t dwc_otg_host_data_rx; |
227 | | | 227 | |
228 | static int dwc_otg_init_fifo(struct dwc_otg_softc *, uint8_t); | | 228 | static int dwc_otg_init_fifo(struct dwc_otg_softc *, uint8_t); |
229 | Static void dwc_otg_clocks_on(struct dwc_otg_softc*); | | 229 | Static void dwc_otg_clocks_on(struct dwc_otg_softc*); |
230 | Static void dwc_otg_clocks_off(struct dwc_otg_softc*); | | 230 | Static void dwc_otg_clocks_off(struct dwc_otg_softc*); |
231 | Static void dwc_otg_pull_up(struct dwc_otg_softc *); | | 231 | Static void dwc_otg_pull_up(struct dwc_otg_softc *); |
232 | Static void dwc_otg_pull_down(struct dwc_otg_softc *); | | 232 | Static void dwc_otg_pull_down(struct dwc_otg_softc *); |
233 | Static void dwc_otg_enable_sof_irq(struct dwc_otg_softc *); | | 233 | Static void dwc_otg_enable_sof_irq(struct dwc_otg_softc *); |
234 | Static void dwc_otg_resume_irq(struct dwc_otg_softc *); | | 234 | Static void dwc_otg_resume_irq(struct dwc_otg_softc *); |
235 | Static void dwc_otg_suspend_irq(struct dwc_otg_softc *); | | 235 | Static void dwc_otg_suspend_irq(struct dwc_otg_softc *); |
236 | Static void dwc_otg_wakeup_peer(struct dwc_otg_softc *); | | 236 | Static void dwc_otg_wakeup_peer(struct dwc_otg_softc *); |
237 | Static int dwc_otg_interrupt(struct dwc_otg_softc *); | | 237 | Static int dwc_otg_interrupt(struct dwc_otg_softc *); |
238 | Static void dwc_otg_timer(struct dwc_otg_softc *); | | 238 | Static void dwc_otg_timer(struct dwc_otg_softc *); |
239 | Static void dwc_otg_timer_tick(void *); | | 239 | Static void dwc_otg_timer_tick(void *); |
240 | Static void dwc_otg_timer_start(struct dwc_otg_softc *); | | 240 | Static void dwc_otg_timer_start(struct dwc_otg_softc *); |
241 | Static void dwc_otg_timer_stop(struct dwc_otg_softc *); | | 241 | Static void dwc_otg_timer_stop(struct dwc_otg_softc *); |
242 | Static void dwc_otg_interrupt_poll(struct dwc_otg_softc *); | | 242 | Static void dwc_otg_interrupt_poll(struct dwc_otg_softc *); |
243 | Static void dwc_otg_do_poll(struct usbd_bus *); | | 243 | Static void dwc_otg_do_poll(struct usbd_bus *); |
244 | Static void dwc_otg_worker(struct work *, void *); | | 244 | Static void dwc_otg_worker(struct work *, void *); |
245 | Static void dwc_otg_rhc(void *); | | 245 | Static void dwc_otg_rhc(void *); |
246 | Static void dwc_otg_vbus_interrupt(struct dwc_otg_softc *); | | 246 | Static void dwc_otg_vbus_interrupt(struct dwc_otg_softc *); |
247 | Static void dwc_otg_standard_done(usbd_xfer_handle); | | 247 | Static void dwc_otg_standard_done(usbd_xfer_handle); |
248 | Static usbd_status dwc_otg_standard_done_sub(usbd_xfer_handle); | | 248 | Static usbd_status dwc_otg_standard_done_sub(usbd_xfer_handle); |
249 | Static void dwc_otg_device_done(usbd_xfer_handle, usbd_status); | | 249 | Static void dwc_otg_device_done(usbd_xfer_handle, usbd_status); |
250 | Static void dwc_otg_setup_standard_chain(usbd_xfer_handle); | | 250 | Static void dwc_otg_setup_standard_chain(usbd_xfer_handle); |
251 | Static void dwc_otg_start_standard_chain(usbd_xfer_handle); | | 251 | Static void dwc_otg_start_standard_chain(usbd_xfer_handle); |
252 | | | 252 | |
253 | Static void dwc_otg_core_reset(struct dwc_otg_softc *sc); | | 253 | Static void dwc_otg_core_reset(struct dwc_otg_softc *sc); |
254 | | | 254 | |
255 | static inline void | | 255 | static inline void |
256 | dwc_otg_root_intr(struct dwc_otg_softc *sc) | | 256 | dwc_otg_root_intr(struct dwc_otg_softc *sc) |
257 | { | | 257 | { |
258 | | | 258 | |
259 | softint_schedule(sc->sc_rhc_si); | | 259 | softint_schedule(sc->sc_rhc_si); |
260 | } | | 260 | } |
261 | | | 261 | |
262 | #define DWC_OTG_READ_4(sc, reg) \ | | 262 | #define DWC_OTG_READ_4(sc, reg) \ |
263 | bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) | | 263 | bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) |
264 | #define DWC_OTG_WRITE_4(sc, reg, data) \ | | 264 | #define DWC_OTG_WRITE_4(sc, reg, data) \ |
265 | bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (data)); | | 265 | bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (data)); |
266 | | | 266 | |
267 | #define DWC_OTG_MODIFY_4(sc, reg, off, on) \ | | 267 | #define DWC_OTG_MODIFY_4(sc, reg, off, on) \ |
268 | DWC_OTG_WRITE_4((sc),(reg),(DWC_OTG_READ_4((sc),(reg)) & ~(off)) | (on)) | | 268 | DWC_OTG_WRITE_4((sc),(reg),(DWC_OTG_READ_4((sc),(reg)) & ~(off)) | (on)) |
269 | | | 269 | |
270 | | | 270 | |
271 | struct dwc_otg_pipe { | | 271 | struct dwc_otg_pipe { |
272 | struct usbd_pipe pipe; /* Must be first */ | | 272 | struct usbd_pipe pipe; /* Must be first */ |
273 | }; | | 273 | }; |
274 | | | 274 | |
275 | #define DWC_OTG_INTR_ENDPT 1 | | 275 | #define DWC_OTG_INTR_ENDPT 1 |
276 | | | 276 | |
277 | Static const struct usbd_bus_methods dwc_otg_bus_methods = { | | 277 | Static const struct usbd_bus_methods dwc_otg_bus_methods = { |
278 | .open_pipe = dwc_otg_open, | | 278 | .open_pipe = dwc_otg_open, |
279 | .soft_intr = dwc_otg_softintr, | | 279 | .soft_intr = dwc_otg_softintr, |
280 | .do_poll = dwc_otg_poll, | | 280 | .do_poll = dwc_otg_poll, |
281 | .allocm = dwc_otg_allocm, | | 281 | .allocm = dwc_otg_allocm, |
282 | .freem = dwc_otg_freem, | | 282 | .freem = dwc_otg_freem, |
283 | .allocx = dwc_otg_allocx, | | 283 | .allocx = dwc_otg_allocx, |
284 | .freex = dwc_otg_freex, | | 284 | .freex = dwc_otg_freex, |
285 | .get_lock = dwc_otg_get_lock, | | 285 | .get_lock = dwc_otg_get_lock, |
286 | }; | | 286 | }; |
287 | | | 287 | |
288 | Static const struct usbd_pipe_methods dwc_otg_root_ctrl_methods = { | | 288 | Static const struct usbd_pipe_methods dwc_otg_root_ctrl_methods = { |
289 | .transfer = dwc_otg_root_ctrl_transfer, | | 289 | .transfer = dwc_otg_root_ctrl_transfer, |
290 | .start = dwc_otg_root_ctrl_start, | | 290 | .start = dwc_otg_root_ctrl_start, |
291 | .abort = dwc_otg_root_ctrl_abort, | | 291 | .abort = dwc_otg_root_ctrl_abort, |
292 | .close = dwc_otg_root_ctrl_close, | | 292 | .close = dwc_otg_root_ctrl_close, |
293 | .cleartoggle = dwc_otg_noop, | | 293 | .cleartoggle = dwc_otg_noop, |
294 | .done = dwc_otg_root_ctrl_done, | | 294 | .done = dwc_otg_root_ctrl_done, |
295 | }; | | 295 | }; |
296 | | | 296 | |
297 | Static const struct usbd_pipe_methods dwc_otg_root_intr_methods = { | | 297 | Static const struct usbd_pipe_methods dwc_otg_root_intr_methods = { |
298 | .transfer = dwc_otg_root_intr_transfer, | | 298 | .transfer = dwc_otg_root_intr_transfer, |
299 | .start = dwc_otg_root_intr_start, | | 299 | .start = dwc_otg_root_intr_start, |
300 | .abort = dwc_otg_root_intr_abort, | | 300 | .abort = dwc_otg_root_intr_abort, |
301 | .close = dwc_otg_root_intr_close, | | 301 | .close = dwc_otg_root_intr_close, |
302 | .cleartoggle = dwc_otg_noop, | | 302 | .cleartoggle = dwc_otg_noop, |
303 | .done = dwc_otg_root_intr_done, | | 303 | .done = dwc_otg_root_intr_done, |
304 | }; | | 304 | }; |
305 | | | 305 | |
306 | Static const struct usbd_pipe_methods dwc_otg_device_ctrl_methods = { | | 306 | Static const struct usbd_pipe_methods dwc_otg_device_ctrl_methods = { |
307 | .transfer = dwc_otg_device_ctrl_transfer, | | 307 | .transfer = dwc_otg_device_ctrl_transfer, |
308 | .start = dwc_otg_device_ctrl_start, | | 308 | .start = dwc_otg_device_ctrl_start, |
309 | .abort = dwc_otg_device_ctrl_abort, | | 309 | .abort = dwc_otg_device_ctrl_abort, |
310 | .close = dwc_otg_device_ctrl_close, | | 310 | .close = dwc_otg_device_ctrl_close, |
311 | .cleartoggle = dwc_otg_noop, | | 311 | .cleartoggle = dwc_otg_noop, |
312 | .done = dwc_otg_device_ctrl_done, | | 312 | .done = dwc_otg_device_ctrl_done, |
313 | }; | | 313 | }; |
314 | | | 314 | |
315 | Static const struct usbd_pipe_methods dwc_otg_device_intr_methods = { | | 315 | Static const struct usbd_pipe_methods dwc_otg_device_intr_methods = { |
316 | .transfer = dwc_otg_device_intr_transfer, | | 316 | .transfer = dwc_otg_device_intr_transfer, |
317 | .start = dwc_otg_device_intr_start, | | 317 | .start = dwc_otg_device_intr_start, |
318 | .abort = dwc_otg_device_intr_abort, | | 318 | .abort = dwc_otg_device_intr_abort, |
319 | .close = dwc_otg_device_intr_close, | | 319 | .close = dwc_otg_device_intr_close, |
320 | .cleartoggle = dwc_otg_device_clear_toggle, | | 320 | .cleartoggle = dwc_otg_device_clear_toggle, |
321 | .done = dwc_otg_device_intr_done, | | 321 | .done = dwc_otg_device_intr_done, |
322 | }; | | 322 | }; |
323 | | | 323 | |
324 | Static const struct usbd_pipe_methods dwc_otg_device_bulk_methods = { | | 324 | Static const struct usbd_pipe_methods dwc_otg_device_bulk_methods = { |
325 | .transfer = dwc_otg_device_bulk_transfer, | | 325 | .transfer = dwc_otg_device_bulk_transfer, |
326 | .start = dwc_otg_device_bulk_start, | | 326 | .start = dwc_otg_device_bulk_start, |
327 | .abort = dwc_otg_device_bulk_abort, | | 327 | .abort = dwc_otg_device_bulk_abort, |
328 | .close = dwc_otg_device_bulk_close, | | 328 | .close = dwc_otg_device_bulk_close, |
329 | .cleartoggle = dwc_otg_device_clear_toggle, | | 329 | .cleartoggle = dwc_otg_device_clear_toggle, |
330 | .done = dwc_otg_device_bulk_done, | | 330 | .done = dwc_otg_device_bulk_done, |
331 | }; | | 331 | }; |
332 | | | 332 | |
333 | Static const struct usbd_pipe_methods dwc_otg_device_isoc_methods = { | | 333 | Static const struct usbd_pipe_methods dwc_otg_device_isoc_methods = { |
334 | .transfer = dwc_otg_device_isoc_transfer, | | 334 | .transfer = dwc_otg_device_isoc_transfer, |
335 | .start = dwc_otg_device_isoc_start, | | 335 | .start = dwc_otg_device_isoc_start, |
336 | .abort = dwc_otg_device_isoc_abort, | | 336 | .abort = dwc_otg_device_isoc_abort, |
337 | .close = dwc_otg_device_isoc_close, | | 337 | .close = dwc_otg_device_isoc_close, |
338 | .cleartoggle = dwc_otg_noop, | | 338 | .cleartoggle = dwc_otg_noop, |
339 | .done = dwc_otg_device_isoc_done, | | 339 | .done = dwc_otg_device_isoc_done, |
340 | }; | | 340 | }; |
341 | | | 341 | |
342 | Static usbd_status | | 342 | Static usbd_status |
343 | dwc_otg_allocm(struct usbd_bus *bus, usb_dma_t *dma, uint32_t size) | | 343 | dwc_otg_allocm(struct usbd_bus *bus, usb_dma_t *dma, uint32_t size) |
344 | { | | 344 | { |
345 | struct dwc_otg_softc *sc = bus->hci_private; | | 345 | struct dwc_otg_softc *sc = bus->hci_private; |
346 | usbd_status status; | | 346 | usbd_status status; |
347 | | | 347 | |
348 | status = usb_allocmem(&sc->sc_bus, size, 0, dma); | | 348 | status = usb_allocmem(&sc->sc_bus, size, 0, dma); |
349 | if (status == USBD_NOMEM) | | 349 | if (status == USBD_NOMEM) |
350 | status = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size); | | 350 | status = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size); |
351 | return status; | | 351 | return status; |
352 | } | | 352 | } |
353 | | | 353 | |
354 | Static void | | 354 | Static void |
355 | dwc_otg_freem(struct usbd_bus *bus, usb_dma_t *dma) | | 355 | dwc_otg_freem(struct usbd_bus *bus, usb_dma_t *dma) |
356 | { | | 356 | { |
357 | struct dwc_otg_softc *sc = bus->hci_private; | | 357 | struct dwc_otg_softc *sc = bus->hci_private; |
358 | | | 358 | |
359 | DPRINTF("\n"); | | 359 | DPRINTF("\n"); |
360 | | | 360 | |
361 | if (dma->block->flags & USB_DMA_RESERVE) { | | 361 | if (dma->block->flags & USB_DMA_RESERVE) { |
362 | usb_reserve_freem(&sc->sc_dma_reserve, dma); | | 362 | usb_reserve_freem(&sc->sc_dma_reserve, dma); |
363 | return; | | 363 | return; |
364 | } | | 364 | } |
365 | usb_freemem(&sc->sc_bus, dma); | | 365 | usb_freemem(&sc->sc_bus, dma); |
366 | } | | 366 | } |
367 | | | 367 | |
368 | usbd_xfer_handle | | 368 | usbd_xfer_handle |
369 | dwc_otg_allocx(struct usbd_bus *bus) | | 369 | dwc_otg_allocx(struct usbd_bus *bus) |
370 | { | | 370 | { |
371 | struct dwc_otg_softc *sc = bus->hci_private; | | 371 | struct dwc_otg_softc *sc = bus->hci_private; |
372 | usbd_xfer_handle xfer; | | 372 | usbd_xfer_handle xfer; |
373 | | | 373 | |
374 | DPRINTF("\n"); | | 374 | DPRINTF("\n"); |
375 | | | 375 | |
376 | DOTG_EVCNT_INCR(sc->sc_ev_xferpoolget); | | 376 | DOTG_EVCNT_INCR(sc->sc_ev_xferpoolget); |
377 | xfer = pool_cache_get(sc->sc_xferpool, PR_NOWAIT); | | 377 | xfer = pool_cache_get(sc->sc_xferpool, PR_NOWAIT); |
378 | if (xfer != NULL) { | | 378 | if (xfer != NULL) { |
379 | memset(xfer, 0, sizeof(struct dwc_otg_xfer)); | | 379 | memset(xfer, 0, sizeof(struct dwc_otg_xfer)); |
380 | #ifdef DIAGNOSTIC | | 380 | #ifdef DIAGNOSTIC |
381 | xfer->busy_free = XFER_BUSY; | | 381 | xfer->busy_free = XFER_BUSY; |
382 | #endif | | 382 | #endif |
383 | } | | 383 | } |
384 | return xfer; | | 384 | return xfer; |
385 | } | | 385 | } |
386 | | | 386 | |
387 | void | | 387 | void |
388 | dwc_otg_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) | | 388 | dwc_otg_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) |
389 | { | | 389 | { |
390 | struct dwc_otg_softc *sc = bus->hci_private; | | 390 | struct dwc_otg_softc *sc = bus->hci_private; |
391 | | | 391 | |
392 | DPRINTF("\n"); | | 392 | DPRINTF("\n"); |
393 | | | 393 | |
394 | #ifdef DIAGNOSTIC | | 394 | #ifdef DIAGNOSTIC |
395 | if (xfer->busy_free != XFER_BUSY) { | | 395 | if (xfer->busy_free != XFER_BUSY) { |
396 | DPRINTF("xfer=%p not busy, 0x%08x\n", xfer, xfer->busy_free); | | 396 | DPRINTF("xfer=%p not busy, 0x%08x\n", xfer, xfer->busy_free); |
397 | } | | 397 | } |
398 | xfer->busy_free = XFER_FREE; | | 398 | xfer->busy_free = XFER_FREE; |
399 | #endif | | 399 | #endif |
400 | DOTG_EVCNT_INCR(sc->sc_ev_xferpoolput); | | 400 | DOTG_EVCNT_INCR(sc->sc_ev_xferpoolput); |
401 | pool_cache_put(sc->sc_xferpool, xfer); | | 401 | pool_cache_put(sc->sc_xferpool, xfer); |
402 | } | | 402 | } |
403 | | | 403 | |
404 | | | 404 | |
405 | Static void | | 405 | Static void |
406 | dwc_otg_get_lock(struct usbd_bus *bus, kmutex_t **lock) | | 406 | dwc_otg_get_lock(struct usbd_bus *bus, kmutex_t **lock) |
407 | { | | 407 | { |
408 | struct dwc_otg_softc *sc = bus->hci_private; | | 408 | struct dwc_otg_softc *sc = bus->hci_private; |
409 | | | 409 | |
410 | *lock = &sc->sc_lock; | | 410 | *lock = &sc->sc_lock; |
411 | } | | 411 | } |
412 | | | 412 | |
413 | Static void | | 413 | Static void |
414 | dwc_otg_softintr(void *v) | | 414 | dwc_otg_softintr(void *v) |
415 | { | | 415 | { |
416 | struct usbd_bus *bus = v; | | 416 | struct usbd_bus *bus = v; |
417 | struct dwc_otg_softc *sc = bus->hci_private; | | 417 | struct dwc_otg_softc *sc = bus->hci_private; |
418 | struct dwc_otg_xfer *dxfer, *tmp; | | 418 | struct dwc_otg_xfer *dxfer, *tmp; |
419 | | | 419 | |
420 | KASSERT(sc->sc_bus.use_polling || mutex_owned(&sc->sc_lock)); | | 420 | KASSERT(sc->sc_bus.use_polling || mutex_owned(&sc->sc_lock)); |
421 | | | 421 | |
422 | DOTG_EVCNT_INCR(sc->sc_ev_soft_intr); | | 422 | DOTG_EVCNT_INCR(sc->sc_ev_soft_intr); |
423 | | | 423 | |
424 | DPRINTF("\n"); | | 424 | DPRINTF("\n"); |
425 | TAILQ_FOREACH_SAFE(dxfer, &sc->sc_complete, xnext, tmp) { | | 425 | TAILQ_FOREACH_SAFE(dxfer, &sc->sc_complete, xnext, tmp) { |
426 | TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext); | | 426 | TAILQ_REMOVE(&sc->sc_complete, dxfer, xnext); |
427 | | | 427 | |
428 | usb_transfer_complete(&dxfer->xfer); | | 428 | usb_transfer_complete(&dxfer->xfer); |
429 | } | | 429 | } |
430 | } | | 430 | } |
431 | | | 431 | |
432 | Static void | | 432 | Static void |
433 | dwc_otg_waitintr(struct dwc_otg_softc *sc, usbd_xfer_handle xfer) | | 433 | dwc_otg_waitintr(struct dwc_otg_softc *sc, usbd_xfer_handle xfer) |
434 | { | | 434 | { |
435 | int timo; | | 435 | int timo; |
436 | uint32_t intrs; | | 436 | uint32_t intrs; |
437 | | | 437 | |
438 | xfer->status = USBD_IN_PROGRESS; | | 438 | xfer->status = USBD_IN_PROGRESS; |
439 | for (timo = xfer->timeout; timo >= 0; timo--) { | | 439 | for (timo = xfer->timeout; timo >= 0; timo--) { |
440 | usb_delay_ms(&sc->sc_bus, 1); | | 440 | usb_delay_ms(&sc->sc_bus, 1); |
441 | if (sc->sc_dying) | | 441 | if (sc->sc_dying) |
442 | break; | | 442 | break; |
443 | intrs = DWC_OTG_READ_4(sc, DOTG_GINTSTS); | | 443 | intrs = DWC_OTG_READ_4(sc, DOTG_GINTSTS); |
444 | | | 444 | |
445 | DPRINTFN(15, "0x%08x\n", intrs); | | 445 | DPRINTFN(15, "0x%08x\n", intrs); |
446 | | | 446 | |
447 | if (intrs) { | | 447 | if (intrs) { |
448 | KASSERT(mutex_owned(&sc->sc_lock)); | | 448 | KASSERT(mutex_owned(&sc->sc_lock)); |
449 | mutex_spin_enter(&sc->sc_intr_lock); | | 449 | mutex_spin_enter(&sc->sc_intr_lock); |
450 | dwc_otg_interrupt(sc); | | 450 | dwc_otg_interrupt(sc); |
451 | mutex_spin_exit(&sc->sc_intr_lock); | | 451 | mutex_spin_exit(&sc->sc_intr_lock); |
452 | if (xfer->status != USBD_IN_PROGRESS) | | 452 | if (xfer->status != USBD_IN_PROGRESS) |
453 | return; | | 453 | return; |
454 | } | | 454 | } |
455 | } | | 455 | } |
456 | | | 456 | |
457 | /* Timeout */ | | 457 | /* Timeout */ |
458 | DPRINTF("timeout\n"); | | 458 | DPRINTF("timeout\n"); |
459 | | | 459 | |
460 | mutex_enter(&sc->sc_lock); | | 460 | mutex_enter(&sc->sc_lock); |
461 | xfer->status = USBD_TIMEOUT; | | 461 | xfer->status = USBD_TIMEOUT; |
462 | usb_transfer_complete(xfer); | | 462 | usb_transfer_complete(xfer); |
463 | mutex_exit(&sc->sc_lock); | | 463 | mutex_exit(&sc->sc_lock); |
464 | } | | 464 | } |
465 | | | 465 | |
466 | Static void | | 466 | Static void |
467 | dwc_otg_timeout(void *addr) | | 467 | dwc_otg_timeout(void *addr) |
468 | { | | 468 | { |
469 | struct dwc_otg_xfer *dxfer = addr; | | 469 | struct dwc_otg_xfer *dxfer = addr; |
470 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)dxfer->xfer.pipe; | | 470 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)dxfer->xfer.pipe; |
471 | struct dwc_otg_softc *sc = dpipe->pipe.device->bus->hci_private; | | 471 | struct dwc_otg_softc *sc = dpipe->pipe.device->bus->hci_private; |
472 | | | 472 | |
473 | DPRINTF("dxfer=%p\n", dxfer); | | 473 | DPRINTF("dxfer=%p\n", dxfer); |
474 | | | 474 | |
475 | if (sc->sc_dying) { | | 475 | if (sc->sc_dying) { |
476 | mutex_enter(&sc->sc_lock); | | 476 | mutex_enter(&sc->sc_lock); |
477 | dwc_otg_abort_xfer(&dxfer->xfer, USBD_TIMEOUT); | | 477 | dwc_otg_abort_xfer(&dxfer->xfer, USBD_TIMEOUT); |
478 | mutex_exit(&sc->sc_lock); | | 478 | mutex_exit(&sc->sc_lock); |
479 | return; | | 479 | return; |
480 | } | | 480 | } |
481 | | | 481 | |
482 | /* Execute the abort in a process context. */ | | 482 | /* Execute the abort in a process context. */ |
483 | usb_init_task(&dxfer->abort_task, dwc_otg_timeout_task, addr); | | 483 | usb_init_task(&dxfer->abort_task, dwc_otg_timeout_task, addr); |
484 | usb_add_task(dxfer->xfer.pipe->device, &dxfer->abort_task, | | 484 | usb_add_task(dxfer->xfer.pipe->device, &dxfer->abort_task, |
485 | USB_TASKQ_HC); | | 485 | USB_TASKQ_HC); |
486 | } | | 486 | } |
487 | | | 487 | |
488 | Static void | | 488 | Static void |
489 | dwc_otg_timeout_task(void *addr) | | 489 | dwc_otg_timeout_task(void *addr) |
490 | { | | 490 | { |
491 | usbd_xfer_handle xfer = addr; | | 491 | usbd_xfer_handle xfer = addr; |
492 | struct dwc_otg_softc *sc = xfer->pipe->device->bus->hci_private; | | 492 | struct dwc_otg_softc *sc = xfer->pipe->device->bus->hci_private; |
493 | | | 493 | |
494 | DPRINTF("xfer=%p\n", xfer); | | 494 | DPRINTF("xfer=%p\n", xfer); |
495 | | | 495 | |
496 | mutex_enter(&sc->sc_lock); | | 496 | mutex_enter(&sc->sc_lock); |
497 | dwc_otg_abort_xfer(xfer, USBD_TIMEOUT); | | 497 | dwc_otg_abort_xfer(xfer, USBD_TIMEOUT); |
498 | mutex_exit(&sc->sc_lock); | | 498 | mutex_exit(&sc->sc_lock); |
499 | } | | 499 | } |
500 | | | 500 | |
501 | usbd_status | | 501 | usbd_status |
502 | dwc_otg_open(usbd_pipe_handle pipe) | | 502 | dwc_otg_open(usbd_pipe_handle pipe) |
503 | { | | 503 | { |
504 | usbd_device_handle dev = pipe->device; | | 504 | usbd_device_handle dev = pipe->device; |
505 | struct dwc_otg_softc *sc = dev->bus->hci_private; | | 505 | struct dwc_otg_softc *sc = dev->bus->hci_private; |
506 | usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc; | | 506 | usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc; |
507 | uint8_t addr = dev->address; | | 507 | uint8_t addr = dev->address; |
508 | uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes); | | 508 | uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes); |
509 | usbd_status err; | | 509 | usbd_status err; |
510 | | | 510 | |
511 | DPRINTF("pipe %p addr %d xfertype %d dir %s\n", pipe, | | 511 | DPRINTF("pipe %p addr %d xfertype %d dir %s\n", pipe, |
512 | addr, xfertype, | | 512 | addr, xfertype, |
513 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? "in" : "out"); | | 513 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? "in" : "out"); |
514 | | | 514 | |
515 | if (sc->sc_dying) { | | 515 | if (sc->sc_dying) { |
516 | err = USBD_IOERROR; | | 516 | err = USBD_IOERROR; |
517 | goto fail; | | 517 | goto fail; |
518 | } | | 518 | } |
519 | | | 519 | |
520 | if (addr == sc->sc_addr) { | | 520 | if (addr == sc->sc_addr) { |
521 | switch (ed->bEndpointAddress) { | | 521 | switch (ed->bEndpointAddress) { |
522 | case USB_CONTROL_ENDPOINT: | | 522 | case USB_CONTROL_ENDPOINT: |
523 | pipe->methods = &dwc_otg_root_ctrl_methods; | | 523 | pipe->methods = &dwc_otg_root_ctrl_methods; |
524 | break; | | 524 | break; |
525 | case UE_DIR_IN | DWC_OTG_INTR_ENDPT: | | 525 | case UE_DIR_IN | DWC_OTG_INTR_ENDPT: |
526 | pipe->methods = &dwc_otg_root_intr_methods; | | 526 | pipe->methods = &dwc_otg_root_intr_methods; |
527 | break; | | 527 | break; |
528 | default: | | 528 | default: |
529 | DPRINTF("bad bEndpointAddress 0x%02x\n", | | 529 | DPRINTF("bad bEndpointAddress 0x%02x\n", |
530 | ed->bEndpointAddress); | | 530 | ed->bEndpointAddress); |
531 | return USBD_INVAL; | | 531 | return USBD_INVAL; |
532 | } | | 532 | } |
533 | DPRINTF("root hub pipe open\n"); | | 533 | DPRINTF("root hub pipe open\n"); |
534 | return USBD_NORMAL_COMPLETION; | | 534 | return USBD_NORMAL_COMPLETION; |
535 | } | | 535 | } |
536 | | | 536 | |
537 | switch (xfertype) { | | 537 | switch (xfertype) { |
538 | case UE_CONTROL: | | 538 | case UE_CONTROL: |
539 | pipe->methods = &dwc_otg_device_ctrl_methods; | | 539 | pipe->methods = &dwc_otg_device_ctrl_methods; |
540 | DPRINTF("UE_CONTROL methods\n"); | | 540 | DPRINTF("UE_CONTROL methods\n"); |
541 | break; | | 541 | break; |
542 | case UE_INTERRUPT: | | 542 | case UE_INTERRUPT: |
543 | DPRINTF("UE_INTERRUPT methods\n"); | | 543 | DPRINTF("UE_INTERRUPT methods\n"); |
544 | pipe->methods = &dwc_otg_device_intr_methods; | | 544 | pipe->methods = &dwc_otg_device_intr_methods; |
545 | break; | | 545 | break; |
546 | case UE_ISOCHRONOUS: | | 546 | case UE_ISOCHRONOUS: |
547 | DPRINTF("US_ISOCHRONOUS methods\n"); | | 547 | DPRINTF("US_ISOCHRONOUS methods\n"); |
548 | pipe->methods = &dwc_otg_device_isoc_methods; | | 548 | pipe->methods = &dwc_otg_device_isoc_methods; |
549 | break; | | 549 | break; |
550 | case UE_BULK: | | 550 | case UE_BULK: |
551 | DPRINTF("UE_BULK methods\n"); | | 551 | DPRINTF("UE_BULK methods\n"); |
552 | pipe->methods = &dwc_otg_device_bulk_methods; | | 552 | pipe->methods = &dwc_otg_device_bulk_methods; |
553 | break; | | 553 | break; |
554 | default: | | 554 | default: |
555 | DPRINTF("bad xfer type %d\n", xfertype); | | 555 | DPRINTF("bad xfer type %d\n", xfertype); |
556 | return USBD_INVAL; | | 556 | return USBD_INVAL; |
557 | } | | 557 | } |
558 | | | 558 | |
559 | return USBD_NORMAL_COMPLETION; | | 559 | return USBD_NORMAL_COMPLETION; |
560 | | | 560 | |
561 | fail: | | 561 | fail: |
562 | return err; | | 562 | return err; |
563 | } | | 563 | } |
564 | | | 564 | |
565 | Static void | | 565 | Static void |
566 | dwc_otg_poll(struct usbd_bus *bus) | | 566 | dwc_otg_poll(struct usbd_bus *bus) |
567 | { | | 567 | { |
568 | struct dwc_otg_softc *sc = bus->hci_private; | | 568 | struct dwc_otg_softc *sc = bus->hci_private; |
569 | | | 569 | |
570 | KASSERT(sc->sc_bus.use_polling || mutex_owned(&sc->sc_lock)); | | 570 | KASSERT(sc->sc_bus.use_polling || mutex_owned(&sc->sc_lock)); |
571 | mutex_spin_enter(&sc->sc_intr_lock); | | 571 | mutex_spin_enter(&sc->sc_intr_lock); |
572 | dwc_otg_interrupt(sc); | | 572 | dwc_otg_interrupt(sc); |
573 | mutex_spin_exit(&sc->sc_intr_lock); | | 573 | mutex_spin_exit(&sc->sc_intr_lock); |
574 | } | | 574 | } |
575 | | | 575 | |
576 | #if 0 | | 576 | #if 0 |
577 | /* | | 577 | /* |
578 | * Close a reqular pipe. | | 578 | * Close a reqular pipe. |
579 | * Assumes that there are no pending transactions. | | 579 | * Assumes that there are no pending transactions. |
580 | */ | | 580 | */ |
581 | Static void | | 581 | Static void |
582 | dwc_otg_close_pipe(usbd_pipe_handle pipe, dwc_otg_soft_ed_t *head) | | 582 | dwc_otg_close_pipe(usbd_pipe_handle pipe, dwc_otg_soft_ed_t *head) |
583 | { | | 583 | { |
584 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)pipe; | | 584 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)pipe; |
585 | struct dwc_otg_softc *sc = pipe->device->bus->hci_private; | | 585 | struct dwc_otg_softc *sc = pipe->device->bus->hci_private; |
586 | | | 586 | |
587 | dpipe = dpipe; | | 587 | dpipe = dpipe; |
588 | usb_delay_ms(&sc->sc_bus, 1); | | 588 | usb_delay_ms(&sc->sc_bus, 1); |
589 | } | | 589 | } |
590 | #endif | | 590 | #endif |
591 | | | 591 | |
592 | /* | | 592 | /* |
593 | * Abort a device request. | | 593 | * Abort a device request. |
594 | */ | | 594 | */ |
595 | Static void | | 595 | Static void |
596 | dwc_otg_abort_xfer(usbd_xfer_handle xfer, usbd_status status) | | 596 | dwc_otg_abort_xfer(usbd_xfer_handle xfer, usbd_status status) |
597 | { | | 597 | { |
598 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 598 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
599 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; | | 599 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; |
600 | struct dwc_otg_softc *sc = dpipe->pipe.device->bus->hci_private; | | 600 | struct dwc_otg_softc *sc = dpipe->pipe.device->bus->hci_private; |
601 | bool wake; | | 601 | bool wake; |
602 | | | 602 | |
603 | DPRINTF("xfer=%p\n", xfer); | | 603 | DPRINTF("xfer=%p\n", xfer); |
604 | | | 604 | |
605 | KASSERT(mutex_owned(&sc->sc_lock)); | | 605 | KASSERT(mutex_owned(&sc->sc_lock)); |
606 | KASSERT(!cpu_intr_p() && !cpu_softintr_p()); | | 606 | KASSERT(!cpu_intr_p() && !cpu_softintr_p()); |
607 | | | 607 | |
608 | if (sc->sc_dying) { | | 608 | if (sc->sc_dying) { |
609 | xfer->status = status; | | 609 | xfer->status = status; |
610 | callout_stop(&xfer->timeout_handle); | | 610 | callout_stop(&xfer->timeout_handle); |
611 | usb_transfer_complete(xfer); | | 611 | usb_transfer_complete(xfer); |
612 | return; | | 612 | return; |
613 | } | | 613 | } |
614 | | | 614 | |
615 | if (xfer->hcflags & UXFER_ABORTING) { | | 615 | if (xfer->hcflags & UXFER_ABORTING) { |
616 | xfer->status = status; | | 616 | xfer->status = status; |
617 | xfer->hcflags |= UXFER_ABORTWAIT; | | 617 | xfer->hcflags |= UXFER_ABORTWAIT; |
618 | while (xfer->hcflags & UXFER_ABORTING) | | 618 | while (xfer->hcflags & UXFER_ABORTING) |
619 | cv_wait(&xfer->hccv, &sc->sc_lock); | | 619 | cv_wait(&xfer->hccv, &sc->sc_lock); |
620 | return; | | 620 | return; |
621 | } | | 621 | } |
622 | xfer->hcflags |= UXFER_ABORTING; | | 622 | xfer->hcflags |= UXFER_ABORTING; |
623 | | | 623 | |
624 | /* | | 624 | /* |
625 | * Step 1: Make interrupt routine and hardware ignore xfer. | | 625 | * Step 1: Make interrupt routine and hardware ignore xfer. |
626 | */ | | 626 | */ |
627 | xfer->status = status; /* make software ignore it */ | | 627 | xfer->status = status; /* make software ignore it */ |
628 | callout_stop(&xfer->timeout_handle); | | 628 | callout_stop(&xfer->timeout_handle); |
629 | | | 629 | |
630 | if (dxfer->td_transfer_cache) { | | 630 | if (dxfer->td_transfer_cache) { |
631 | int ch = dxfer->td_transfer_cache->channel; | | 631 | int ch = dxfer->td_transfer_cache->channel; |
632 | if (ch < DWC_OTG_MAX_CHANNELS) { | | 632 | if (ch < DWC_OTG_MAX_CHANNELS) { |
633 | | | 633 | |
634 | DPRINTF("Disabling channel %d\n", ch); | | 634 | DPRINTF("Disabling channel %d\n", ch); |
635 | DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(ch), | | 635 | DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(ch), |
636 | HCINTMSK_CHHLTDMSK); | | 636 | HCINTMSK_CHHLTDMSK); |
637 | DWC_OTG_WRITE_4(sc, DOTG_HCINT(ch), | | 637 | DWC_OTG_WRITE_4(sc, DOTG_HCINT(ch), |
638 | ~HCINTMSK_CHHLTDMSK); | | 638 | ~HCINTMSK_CHHLTDMSK); |
639 | | | 639 | |
640 | if ((DWC_OTG_READ_4(sc, DOTG_HCCHAR(ch)) & | | 640 | if ((DWC_OTG_READ_4(sc, DOTG_HCCHAR(ch)) & |
641 | HCCHAR_CHENA) != 0) { | | 641 | HCCHAR_CHENA) != 0) { |
642 | DWC_OTG_MODIFY_4(sc, DOTG_HCCHAR(ch), | | 642 | DWC_OTG_MODIFY_4(sc, DOTG_HCCHAR(ch), |
643 | HCCHAR_CHENA, HCCHAR_CHDIS); | | 643 | HCCHAR_CHENA, HCCHAR_CHDIS); |
644 | } | | 644 | } |
645 | } | | 645 | } |
646 | } | | 646 | } |
647 | | | 647 | |
648 | mutex_spin_enter(&sc->sc_intr_lock); | | 648 | mutex_spin_enter(&sc->sc_intr_lock); |
649 | dxfer->queued = false; | | 649 | dxfer->queued = false; |
650 | TAILQ_REMOVE(&sc->sc_active, dxfer, xnext); | | 650 | TAILQ_REMOVE(&sc->sc_active, dxfer, xnext); |
651 | mutex_spin_exit(&sc->sc_intr_lock); | | 651 | mutex_spin_exit(&sc->sc_intr_lock); |
652 | | | 652 | |
653 | /* | | 653 | /* |
654 | * Step 4: Execute callback. | | 654 | * Step 4: Execute callback. |
655 | */ | | 655 | */ |
656 | wake = xfer->hcflags & UXFER_ABORTWAIT; | | 656 | wake = xfer->hcflags & UXFER_ABORTWAIT; |
657 | xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); | | 657 | xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); |
658 | usb_transfer_complete(xfer); | | 658 | usb_transfer_complete(xfer); |
659 | if (wake) { | | 659 | if (wake) { |
660 | cv_broadcast(&xfer->hccv); | | 660 | cv_broadcast(&xfer->hccv); |
661 | } | | 661 | } |
662 | | | 662 | |
663 | KASSERT(mutex_owned(&sc->sc_lock)); | | 663 | KASSERT(mutex_owned(&sc->sc_lock)); |
664 | } | | 664 | } |
665 | | | 665 | |
666 | Static void | | 666 | Static void |
667 | dwc_otg_noop(usbd_pipe_handle pipe) | | 667 | dwc_otg_noop(usbd_pipe_handle pipe) |
668 | { | | 668 | { |
669 | | | 669 | |
670 | DPRINTF("\n"); | | 670 | DPRINTF("\n"); |
671 | } | | 671 | } |
672 | | | 672 | |
673 | Static void | | 673 | Static void |
674 | dwc_otg_device_clear_toggle(usbd_pipe_handle pipe) | | 674 | dwc_otg_device_clear_toggle(usbd_pipe_handle pipe) |
675 | { | | 675 | { |
676 | | | 676 | |
677 | DPRINTF("toggle %d -> 0", pipe->endpoint->datatoggle); | | 677 | DPRINTF("toggle %d -> 0", pipe->endpoint->datatoggle); |
678 | | | 678 | |
679 | pipe->endpoint->datatoggle = 0; | | 679 | pipe->endpoint->datatoggle = 0; |
680 | } | | 680 | } |
681 | | | 681 | |
682 | /***********************************************************************/ | | 682 | /***********************************************************************/ |
683 | | | 683 | |
684 | /* | | 684 | /* |
685 | * Data structures and routines to emulate the root hub. | | 685 | * Data structures and routines to emulate the root hub. |
686 | */ | | 686 | */ |
687 | | | 687 | |
688 | Static const usb_device_descriptor_t dwc_otg_devd = { | | 688 | Static const usb_device_descriptor_t dwc_otg_devd = { |
689 | .bLength = sizeof(usb_device_descriptor_t), | | 689 | .bLength = sizeof(usb_device_descriptor_t), |
690 | .bDescriptorType = UDESC_DEVICE, | | 690 | .bDescriptorType = UDESC_DEVICE, |
691 | .bcdUSB = {0x00, 0x02}, | | 691 | .bcdUSB = {0x00, 0x02}, |
692 | .bDeviceClass = UDCLASS_HUB, | | 692 | .bDeviceClass = UDCLASS_HUB, |
693 | .bDeviceSubClass = UDSUBCLASS_HUB, | | 693 | .bDeviceSubClass = UDSUBCLASS_HUB, |
694 | .bDeviceProtocol = UDPROTO_HSHUBSTT, | | 694 | .bDeviceProtocol = UDPROTO_HSHUBSTT, |
695 | .bMaxPacketSize = 64, | | 695 | .bMaxPacketSize = 64, |
696 | .bcdDevice = {0x00, 0x01}, | | 696 | .bcdDevice = {0x00, 0x01}, |
697 | .iManufacturer = 1, | | 697 | .iManufacturer = 1, |
698 | .iProduct = 2, | | 698 | .iProduct = 2, |
699 | .bNumConfigurations = 1, | | 699 | .bNumConfigurations = 1, |
700 | }; | | 700 | }; |
701 | | | 701 | |
702 | struct dwc_otg_config_desc { | | 702 | struct dwc_otg_config_desc { |
703 | usb_config_descriptor_t confd; | | 703 | usb_config_descriptor_t confd; |
704 | usb_interface_descriptor_t ifcd; | | 704 | usb_interface_descriptor_t ifcd; |
705 | usb_endpoint_descriptor_t endpd; | | 705 | usb_endpoint_descriptor_t endpd; |
706 | } __packed; | | 706 | } __packed; |
707 | | | 707 | |
708 | Static const struct dwc_otg_config_desc dwc_otg_confd = { | | 708 | Static const struct dwc_otg_config_desc dwc_otg_confd = { |
709 | .confd = { | | 709 | .confd = { |
710 | .bLength = USB_CONFIG_DESCRIPTOR_SIZE, | | 710 | .bLength = USB_CONFIG_DESCRIPTOR_SIZE, |
711 | .bDescriptorType = UDESC_CONFIG, | | 711 | .bDescriptorType = UDESC_CONFIG, |
712 | .wTotalLength[0] = sizeof(dwc_otg_confd), | | 712 | .wTotalLength[0] = sizeof(dwc_otg_confd), |
713 | .bNumInterface = 1, | | 713 | .bNumInterface = 1, |
714 | .bConfigurationValue = 1, | | 714 | .bConfigurationValue = 1, |
715 | .iConfiguration = 0, | | 715 | .iConfiguration = 0, |
716 | .bmAttributes = UC_SELF_POWERED, | | 716 | .bmAttributes = UC_SELF_POWERED, |
717 | .bMaxPower = 0, | | 717 | .bMaxPower = 0, |
718 | }, | | 718 | }, |
719 | .ifcd = { | | 719 | .ifcd = { |
720 | .bLength = USB_INTERFACE_DESCRIPTOR_SIZE, | | 720 | .bLength = USB_INTERFACE_DESCRIPTOR_SIZE, |
721 | .bDescriptorType = UDESC_INTERFACE, | | 721 | .bDescriptorType = UDESC_INTERFACE, |
722 | .bInterfaceNumber = 0, | | 722 | .bInterfaceNumber = 0, |
723 | .bAlternateSetting = 0, | | 723 | .bAlternateSetting = 0, |
724 | .bNumEndpoints = 1, | | 724 | .bNumEndpoints = 1, |
725 | .bInterfaceClass = UICLASS_HUB, | | 725 | .bInterfaceClass = UICLASS_HUB, |
726 | .bInterfaceSubClass = UISUBCLASS_HUB, | | 726 | .bInterfaceSubClass = UISUBCLASS_HUB, |
727 | .bInterfaceProtocol = UIPROTO_HSHUBSTT, | | 727 | .bInterfaceProtocol = UIPROTO_HSHUBSTT, |
728 | .iInterface = 0 | | 728 | .iInterface = 0 |
729 | }, | | 729 | }, |
730 | .endpd = { | | 730 | .endpd = { |
731 | .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, | | 731 | .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, |
732 | .bDescriptorType = UDESC_ENDPOINT, | | 732 | .bDescriptorType = UDESC_ENDPOINT, |
733 | .bEndpointAddress = UE_DIR_IN | DWC_OTG_INTR_ENDPT, | | 733 | .bEndpointAddress = UE_DIR_IN | DWC_OTG_INTR_ENDPT, |
734 | .bmAttributes = UE_INTERRUPT, | | 734 | .bmAttributes = UE_INTERRUPT, |
735 | .wMaxPacketSize = {8, 0}, /* max packet */ | | 735 | .wMaxPacketSize = {8, 0}, /* max packet */ |
736 | .bInterval = 255, | | 736 | .bInterval = 255, |
737 | }, | | 737 | }, |
738 | }; | | 738 | }; |
739 | | | 739 | |
740 | #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } | | 740 | #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } |
741 | Static const usb_hub_descriptor_t dwc_otg_hubd = { | | 741 | Static const usb_hub_descriptor_t dwc_otg_hubd = { |
742 | .bDescLength = USB_HUB_DESCRIPTOR_SIZE, | | 742 | .bDescLength = USB_HUB_DESCRIPTOR_SIZE, |
743 | .bDescriptorType = UDESC_HUB, | | 743 | .bDescriptorType = UDESC_HUB, |
744 | .bNbrPorts = 1, | | 744 | .bNbrPorts = 1, |
745 | HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)), | | 745 | HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)), |
746 | .bPwrOn2PwrGood = 50, | | 746 | .bPwrOn2PwrGood = 50, |
747 | .bHubContrCurrent = 0, | | 747 | .bHubContrCurrent = 0, |
748 | .DeviceRemovable = {0}, /* port is removable */ | | 748 | .DeviceRemovable = {0}, /* port is removable */ |
749 | }; | | 749 | }; |
750 | | | 750 | |
751 | Static usbd_status | | 751 | Static usbd_status |
752 | dwc_otg_root_ctrl_transfer(usbd_xfer_handle xfer) | | 752 | dwc_otg_root_ctrl_transfer(usbd_xfer_handle xfer) |
753 | { | | 753 | { |
754 | struct dwc_otg_softc *sc = xfer->pipe->device->bus->hci_private; | | 754 | struct dwc_otg_softc *sc = xfer->pipe->device->bus->hci_private; |
755 | usbd_status err; | | 755 | usbd_status err; |
756 | | | 756 | |
757 | mutex_enter(&sc->sc_lock); | | 757 | mutex_enter(&sc->sc_lock); |
758 | err = usb_insert_transfer(xfer); | | 758 | err = usb_insert_transfer(xfer); |
759 | mutex_exit(&sc->sc_lock); | | 759 | mutex_exit(&sc->sc_lock); |
760 | if (err) | | 760 | if (err) |
761 | return err; | | 761 | return err; |
762 | | | 762 | |
763 | return dwc_otg_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)); | | 763 | return dwc_otg_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)); |
764 | } | | 764 | } |
765 | | | 765 | |
766 | Static usbd_status | | 766 | Static usbd_status |
767 | dwc_otg_root_ctrl_start(usbd_xfer_handle xfer) | | 767 | dwc_otg_root_ctrl_start(usbd_xfer_handle xfer) |
768 | { | | 768 | { |
769 | struct dwc_otg_softc *sc = xfer->pipe->device->bus->hci_private; | | 769 | struct dwc_otg_softc *sc = xfer->pipe->device->bus->hci_private; |
770 | usb_device_request_t *req; | | 770 | usb_device_request_t *req; |
771 | uint8_t *buf; | | 771 | uint8_t *buf; |
772 | int len, value, index, l, totlen; | | 772 | int len, value, index, l, totlen; |
773 | usb_port_status_t ps; | | 773 | usb_port_status_t ps; |
774 | usb_hub_descriptor_t hubd; | | 774 | usb_hub_descriptor_t hubd; |
775 | usbd_status err = USBD_IOERROR; | | 775 | usbd_status err = USBD_IOERROR; |
776 | | | 776 | |
777 | if (sc->sc_dying) | | 777 | if (sc->sc_dying) |
778 | return USBD_IOERROR; | | 778 | return USBD_IOERROR; |
779 | | | 779 | |
780 | req = &xfer->request; | | 780 | req = &xfer->request; |
781 | | | 781 | |
782 | len = UGETW(req->wLength); | | 782 | len = UGETW(req->wLength); |
783 | value = UGETW(req->wValue); | | 783 | value = UGETW(req->wValue); |
784 | index = UGETW(req->wIndex); | | 784 | index = UGETW(req->wIndex); |
785 | | | 785 | |
786 | DPRINTFN(4, "type=0x%02x request=%02x value=%04x len=%04x index=%04x\n", | | 786 | DPRINTFN(4, "type=0x%02x request=%02x value=%04x len=%04x index=%04x\n", |
787 | req->bmRequestType, req->bRequest, value, len, index); | | 787 | req->bmRequestType, req->bRequest, value, len, index); |
788 | | | 788 | |
789 | buf = len ? KERNADDR(&xfer->dmabuf, 0) : NULL; | | 789 | buf = len ? KERNADDR(&xfer->dmabuf, 0) : NULL; |
790 | | | 790 | |
791 | totlen = 0; | | 791 | totlen = 0; |
792 | | | 792 | |
793 | #define C(x,y) ((x) | ((y) << 8)) | | 793 | #define C(x,y) ((x) | ((y) << 8)) |
794 | switch (C(req->bRequest, req->bmRequestType)) { | | 794 | switch (C(req->bRequest, req->bmRequestType)) { |
795 | case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): | | 795 | case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): |
796 | case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): | | 796 | case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): |
797 | case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): | | 797 | case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): |
798 | /* | | 798 | /* |
799 | * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops | | 799 | * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops |
800 | * for the integrated root hub. | | 800 | * for the integrated root hub. |
801 | */ | | 801 | */ |
802 | break; | | 802 | break; |
803 | case C(UR_GET_CONFIG, UT_READ_DEVICE): | | 803 | case C(UR_GET_CONFIG, UT_READ_DEVICE): |
804 | if (len > 0) { | | 804 | if (len > 0) { |
805 | *buf = sc->sc_conf; | | 805 | *buf = sc->sc_conf; |
806 | totlen = 1; | | 806 | totlen = 1; |
807 | } | | 807 | } |
808 | break; | | 808 | break; |
809 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): | | 809 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): |
810 | DPRINTFN(8, "wValue=0x%04x\n", value); | | 810 | DPRINTFN(8, "wValue=0x%04x\n", value); |
811 | | | 811 | |
812 | if (len == 0) | | 812 | if (len == 0) |
813 | break; | | 813 | break; |
814 | switch (value) { | | 814 | switch (value) { |
815 | case C(0, UDESC_DEVICE): | | 815 | case C(0, UDESC_DEVICE): |
816 | l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); | | 816 | l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); |
817 | memcpy(buf, &dwc_otg_devd, l); | | 817 | memcpy(buf, &dwc_otg_devd, l); |
818 | buf += l; | | 818 | buf += l; |
819 | len -= l; | | 819 | len -= l; |
820 | totlen += l; | | 820 | totlen += l; |
821 | | | 821 | |
822 | break; | | 822 | break; |
823 | case C(0, UDESC_CONFIG): | | 823 | case C(0, UDESC_CONFIG): |
824 | l = min(len, sizeof(dwc_otg_confd)); | | 824 | l = min(len, sizeof(dwc_otg_confd)); |
825 | memcpy(buf, &dwc_otg_confd, l); | | 825 | memcpy(buf, &dwc_otg_confd, l); |
826 | buf += l; | | 826 | buf += l; |
827 | len -= l; | | 827 | len -= l; |
828 | totlen += l; | | 828 | totlen += l; |
829 | | | 829 | |
830 | break; | | 830 | break; |
831 | #define sd ((usb_string_descriptor_t *)buf) | | 831 | #define sd ((usb_string_descriptor_t *)buf) |
832 | case C(0, UDESC_STRING): | | 832 | case C(0, UDESC_STRING): |
833 | totlen = usb_makelangtbl(sd, len); | | 833 | totlen = usb_makelangtbl(sd, len); |
834 | break; | | 834 | break; |
835 | case C(1, UDESC_STRING): | | 835 | case C(1, UDESC_STRING): |
836 | totlen = usb_makestrdesc(sd, len, sc->sc_vendor); | | 836 | totlen = usb_makestrdesc(sd, len, sc->sc_vendor); |
837 | break; | | 837 | break; |
838 | case C(2, UDESC_STRING): | | 838 | case C(2, UDESC_STRING): |
839 | totlen = usb_makestrdesc(sd, len, "DWC OTG root hub"); | | 839 | totlen = usb_makestrdesc(sd, len, "DWC OTG root hub"); |
840 | break; | | 840 | break; |
841 | #undef sd | | 841 | #undef sd |
842 | default: | | 842 | default: |
843 | goto fail; | | 843 | goto fail; |
844 | } | | 844 | } |
845 | break; | | 845 | break; |
846 | case C(UR_GET_INTERFACE, UT_READ_INTERFACE): | | 846 | case C(UR_GET_INTERFACE, UT_READ_INTERFACE): |
847 | if (len > 0) { | | 847 | if (len > 0) { |
848 | *buf = 0; | | 848 | *buf = 0; |
849 | totlen = 1; | | 849 | totlen = 1; |
850 | } | | 850 | } |
851 | break; | | 851 | break; |
852 | case C(UR_GET_STATUS, UT_READ_DEVICE): | | 852 | case C(UR_GET_STATUS, UT_READ_DEVICE): |
853 | if (len > 1) { | | 853 | if (len > 1) { |
854 | USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED); | | 854 | USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED); |
855 | totlen = 2; | | 855 | totlen = 2; |
856 | } | | 856 | } |
857 | break; | | 857 | break; |
858 | case C(UR_GET_STATUS, UT_READ_INTERFACE): | | 858 | case C(UR_GET_STATUS, UT_READ_INTERFACE): |
859 | case C(UR_GET_STATUS, UT_READ_ENDPOINT): | | 859 | case C(UR_GET_STATUS, UT_READ_ENDPOINT): |
860 | if (len > 1) { | | 860 | if (len > 1) { |
861 | USETW(((usb_status_t *)buf)->wStatus, 0); | | 861 | USETW(((usb_status_t *)buf)->wStatus, 0); |
862 | totlen = 2; | | 862 | totlen = 2; |
863 | } | | 863 | } |
864 | break; | | 864 | break; |
865 | case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): | | 865 | case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): |
866 | DPRINTF("UR_SET_ADDRESS, UT_WRITE_DEVICE: addr %d\n", | | 866 | DPRINTF("UR_SET_ADDRESS, UT_WRITE_DEVICE: addr %d\n", |
867 | value); | | 867 | value); |
868 | if (value >= USB_MAX_DEVICES) | | 868 | if (value >= USB_MAX_DEVICES) |
869 | goto fail; | | 869 | goto fail; |
870 | | | 870 | |
871 | sc->sc_addr = value; | | 871 | sc->sc_addr = value; |
872 | break; | | 872 | break; |
873 | case C(UR_SET_CONFIG, UT_WRITE_DEVICE): | | 873 | case C(UR_SET_CONFIG, UT_WRITE_DEVICE): |
874 | if (value != 0 && value != 1) | | 874 | if (value != 0 && value != 1) |
875 | goto fail; | | 875 | goto fail; |
876 | | | 876 | |
877 | sc->sc_conf = value; | | 877 | sc->sc_conf = value; |
878 | break; | | 878 | break; |
879 | case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): | | 879 | case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): |
880 | break; | | 880 | break; |
881 | case C(UR_SET_FEATURE, UT_WRITE_DEVICE): | | 881 | case C(UR_SET_FEATURE, UT_WRITE_DEVICE): |
882 | case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): | | 882 | case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): |
883 | err = USBD_IOERROR; | | 883 | err = USBD_IOERROR; |
884 | goto fail; | | 884 | goto fail; |
885 | case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): | | 885 | case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): |
886 | // switch (UGETW(req->wValue)) { | | 886 | // switch (UGETW(req->wValue)) { |
887 | // case UF_ENDPOINT_HALT: | | 887 | // case UF_ENDPOINT_HALT: |
888 | // goto tr_handle_clear_halt; | | 888 | // goto tr_handle_clear_halt; |
889 | // case UF_DEVICE_REMOTE_WAKEUP: | | 889 | // case UF_DEVICE_REMOTE_WAKEUP: |
890 | // goto tr_handle_clear_wakeup; | | 890 | // goto tr_handle_clear_wakeup; |
891 | // default: | | 891 | // default: |
892 | // goto tr_stalled; | | 892 | // goto tr_stalled; |
893 | // } | | 893 | // } |
894 | // break; | | 894 | // break; |
895 | // err = USBD_IOERROR; | | 895 | // err = USBD_IOERROR; |
896 | // goto fail; | | 896 | // goto fail; |
897 | err = USBD_NORMAL_COMPLETION; | | 897 | err = USBD_NORMAL_COMPLETION; |
898 | goto fail; | | 898 | goto fail; |
899 | case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): | | 899 | case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): |
900 | break; | | 900 | break; |
901 | case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): | | 901 | case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): |
902 | break; | | 902 | break; |
903 | | | 903 | |
904 | /* Hub requests */ | | 904 | /* Hub requests */ |
905 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): | | 905 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): |
906 | break; | | 906 | break; |
907 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): | | 907 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): |
908 | DPRINTFN(9, "UR_CLEAR_FEATURE port=%d feature=%d\n", | | 908 | DPRINTFN(9, "UR_CLEAR_FEATURE port=%d feature=%d\n", |
909 | index, value); | | 909 | index, value); |
910 | if (index < 1 || index > sc->sc_noport) | | 910 | if (index < 1 || index > sc->sc_noport) |
911 | goto fail; | | 911 | goto fail; |
912 | | | 912 | |
913 | switch (value) { | | 913 | switch (value) { |
914 | case UHF_PORT_ENABLE: | | 914 | case UHF_PORT_ENABLE: |
915 | if (sc->sc_flags.status_device_mode == 0) { | | 915 | if (sc->sc_flags.status_device_mode == 0) { |
916 | DWC_OTG_WRITE_4(sc, DOTG_HPRT, | | 916 | DWC_OTG_WRITE_4(sc, DOTG_HPRT, |
917 | sc->sc_hprt_val | HPRT_PRTENA); | | 917 | sc->sc_hprt_val | HPRT_PRTENA); |
918 | } | | 918 | } |
919 | sc->sc_flags.port_enabled = 0; | | 919 | sc->sc_flags.port_enabled = 0; |
920 | break; | | 920 | break; |
921 | | | 921 | |
922 | case UHF_PORT_SUSPEND: | | 922 | case UHF_PORT_SUSPEND: |
923 | dwc_otg_wakeup_peer(sc); | | 923 | dwc_otg_wakeup_peer(sc); |
924 | break; | | 924 | break; |
925 | | | 925 | |
926 | case UHF_PORT_POWER: | | 926 | case UHF_PORT_POWER: |
927 | sc->sc_flags.port_powered = 0; | | 927 | sc->sc_flags.port_powered = 0; |
928 | if (sc->sc_mode == DWC_MODE_HOST || | | 928 | if (sc->sc_mode == DWC_MODE_HOST || |
929 | sc->sc_mode == DWC_MODE_OTG) { | | 929 | sc->sc_mode == DWC_MODE_OTG) { |
930 | sc->sc_hprt_val = 0; | | 930 | sc->sc_hprt_val = 0; |
931 | DWC_OTG_WRITE_4(sc, DOTG_HPRT, HPRT_PRTENA); | | 931 | DWC_OTG_WRITE_4(sc, DOTG_HPRT, HPRT_PRTENA); |
932 | } | | 932 | } |
933 | dwc_otg_pull_down(sc); | | 933 | dwc_otg_pull_down(sc); |
934 | dwc_otg_clocks_off(sc); | | 934 | dwc_otg_clocks_off(sc); |
935 | break; | | 935 | break; |
936 | | | 936 | |
937 | case UHF_C_PORT_CONNECTION: | | 937 | case UHF_C_PORT_CONNECTION: |
938 | /* clear connect change flag */ | | 938 | /* clear connect change flag */ |
939 | sc->sc_flags.change_connect = 0; | | 939 | sc->sc_flags.change_connect = 0; |
940 | break; | | 940 | break; |
941 | case UHF_C_PORT_ENABLE: | | 941 | case UHF_C_PORT_ENABLE: |
942 | sc->sc_flags.change_enabled = 0; | | 942 | sc->sc_flags.change_enabled = 0; |
943 | break; | | 943 | break; |
944 | case UHF_C_PORT_SUSPEND: | | 944 | case UHF_C_PORT_SUSPEND: |
945 | sc->sc_flags.change_suspend = 0; | | 945 | sc->sc_flags.change_suspend = 0; |
946 | break; | | 946 | break; |
947 | case UHF_C_PORT_OVER_CURRENT: | | 947 | case UHF_C_PORT_OVER_CURRENT: |
948 | sc->sc_flags.change_over_current = 0; | | 948 | sc->sc_flags.change_over_current = 0; |
949 | break; | | 949 | break; |
950 | case UHF_C_PORT_RESET: | | 950 | case UHF_C_PORT_RESET: |
951 | /* ??? *//* enable rhsc interrupt if condition is cleared */ | | 951 | /* ??? *//* enable rhsc interrupt if condition is cleared */ |
952 | sc->sc_flags.change_reset = 0; | | 952 | sc->sc_flags.change_reset = 0; |
953 | break; | | 953 | break; |
954 | // case UHF_PORT_TEST: | | 954 | // case UHF_PORT_TEST: |
955 | // case UHF_PORT_INDICATOR: | | 955 | // case UHF_PORT_INDICATOR: |
956 | // /* nops */ | | 956 | // /* nops */ |
957 | // break; | | 957 | // break; |
958 | default: | | 958 | default: |
959 | goto fail; | | 959 | goto fail; |
960 | } | | 960 | } |
961 | break; | | 961 | break; |
962 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): | | 962 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): |
963 | if (len == 0) | | 963 | if (len == 0) |
964 | break; | | 964 | break; |
965 | if ((value & 0xff) != 0) | | 965 | if ((value & 0xff) != 0) |
966 | goto fail; | | 966 | goto fail; |
967 | | | 967 | |
968 | hubd = dwc_otg_hubd; | | 968 | hubd = dwc_otg_hubd; |
969 | hubd.bNbrPorts = sc->sc_noport; | | 969 | hubd.bNbrPorts = sc->sc_noport; |
970 | | | 970 | |
971 | l = min(len, hubd.bDescLength); | | 971 | l = min(len, hubd.bDescLength); |
972 | memcpy(buf, &hubd, l); | | 972 | memcpy(buf, &hubd, l); |
973 | buf += l; | | 973 | buf += l; |
974 | len -= l; | | 974 | len -= l; |
975 | totlen += l; | | 975 | totlen += l; |
976 | | | 976 | |
977 | break; | | 977 | break; |
978 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): | | 978 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): |
979 | if (len != 4) | | 979 | if (len != 4) |
980 | goto fail; | | 980 | goto fail; |
981 | memset(buf, 0, len); /* ? XXX */ | | 981 | memset(buf, 0, len); /* ? XXX */ |
982 | totlen = len; | | 982 | totlen = len; |
983 | break; | | 983 | break; |
984 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): | | 984 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): |
985 | DPRINTFN(8, "get port status i=%d\n", index); | | 985 | DPRINTFN(8, "get port status i=%d\n", index); |
986 | | | 986 | |
987 | if (index < 1 || index > sc->sc_noport) | | 987 | if (index < 1 || index > sc->sc_noport) |
988 | goto fail; | | 988 | goto fail; |
989 | if (len != 4) | | 989 | if (len != 4) |
990 | goto fail; | | 990 | goto fail; |
991 | | | 991 | |
992 | if (sc->sc_flags.status_vbus) | | 992 | if (sc->sc_flags.status_vbus) |
993 | dwc_otg_clocks_on(sc); | | 993 | dwc_otg_clocks_on(sc); |
994 | else | | 994 | else |
995 | dwc_otg_clocks_off(sc); | | 995 | dwc_otg_clocks_off(sc); |
996 | | | 996 | |
997 | /* Select Device Side Mode */ | | 997 | /* Select Device Side Mode */ |
998 | value = 0; | | 998 | value = 0; |
999 | if (sc->sc_flags.status_device_mode) { | | 999 | if (sc->sc_flags.status_device_mode) { |
1000 | /* | | 1000 | /* |
1001 | * XXX FreeBSD specific, which value ? | | 1001 | * XXX FreeBSD specific, which value ? |
1002 | * value = UPS_PORT_MODE_DEVICE; | | 1002 | * value = UPS_PORT_MODE_DEVICE; |
1003 | */ | | 1003 | */ |
1004 | dwc_otg_timer_stop(sc); | | 1004 | dwc_otg_timer_stop(sc); |
1005 | } else { | | 1005 | } else { |
1006 | dwc_otg_timer_start(sc); | | 1006 | dwc_otg_timer_start(sc); |
1007 | } | | 1007 | } |
1008 | | | 1008 | |
1009 | if (sc->sc_flags.status_high_speed) | | 1009 | if (sc->sc_flags.status_high_speed) |
1010 | value |= UPS_HIGH_SPEED; | | 1010 | value |= UPS_HIGH_SPEED; |
1011 | else if (sc->sc_flags.status_low_speed) | | 1011 | else if (sc->sc_flags.status_low_speed) |
1012 | value |= UPS_LOW_SPEED; | | 1012 | value |= UPS_LOW_SPEED; |
1013 | | | 1013 | |
1014 | if (sc->sc_flags.port_powered) | | 1014 | if (sc->sc_flags.port_powered) |
1015 | value |= UPS_PORT_POWER; | | 1015 | value |= UPS_PORT_POWER; |
1016 | | | 1016 | |
1017 | if (sc->sc_flags.port_enabled) | | 1017 | if (sc->sc_flags.port_enabled) |
1018 | value |= UPS_PORT_ENABLED; | | 1018 | value |= UPS_PORT_ENABLED; |
1019 | | | 1019 | |
1020 | if (sc->sc_flags.port_over_current) | | 1020 | if (sc->sc_flags.port_over_current) |
1021 | value |= UPS_OVERCURRENT_INDICATOR; | | 1021 | value |= UPS_OVERCURRENT_INDICATOR; |
1022 | | | 1022 | |
1023 | if (sc->sc_flags.status_vbus && | | 1023 | if (sc->sc_flags.status_vbus && |
1024 | sc->sc_flags.status_bus_reset) | | 1024 | sc->sc_flags.status_bus_reset) |
1025 | value |= UPS_CURRENT_CONNECT_STATUS; | | 1025 | value |= UPS_CURRENT_CONNECT_STATUS; |
1026 | | | 1026 | |
1027 | if (sc->sc_flags.status_suspend) | | 1027 | if (sc->sc_flags.status_suspend) |
1028 | value |= UPS_SUSPEND; | | 1028 | value |= UPS_SUSPEND; |
1029 | | | 1029 | |
1030 | USETW(ps.wPortStatus, value); | | 1030 | USETW(ps.wPortStatus, value); |
1031 | | | 1031 | |
1032 | value = 0; | | 1032 | value = 0; |
1033 | | | 1033 | |
1034 | if (sc->sc_flags.change_connect) | | 1034 | if (sc->sc_flags.change_connect) |
1035 | value |= UPS_C_CONNECT_STATUS; | | 1035 | value |= UPS_C_CONNECT_STATUS; |
1036 | if (sc->sc_flags.change_suspend) | | 1036 | if (sc->sc_flags.change_suspend) |
1037 | value |= UPS_C_SUSPEND; | | 1037 | value |= UPS_C_SUSPEND; |
1038 | if (sc->sc_flags.change_reset) | | 1038 | if (sc->sc_flags.change_reset) |
1039 | value |= UPS_C_PORT_RESET; | | 1039 | value |= UPS_C_PORT_RESET; |
1040 | if (sc->sc_flags.change_over_current) | | 1040 | if (sc->sc_flags.change_over_current) |
1041 | value |= UPS_C_OVERCURRENT_INDICATOR; | | 1041 | value |= UPS_C_OVERCURRENT_INDICATOR; |
1042 | | | 1042 | |
1043 | USETW(ps.wPortChange, value); | | 1043 | USETW(ps.wPortChange, value); |
1044 | | | 1044 | |
1045 | l = min(len, sizeof(ps)); | | 1045 | l = min(len, sizeof(ps)); |
1046 | memcpy(buf, &ps, l); | | 1046 | memcpy(buf, &ps, l); |
1047 | buf += l; | | 1047 | buf += l; |
1048 | len -= l; | | 1048 | len -= l; |
1049 | totlen += l; | | 1049 | totlen += l; |
1050 | | | 1050 | |
1051 | break; | | 1051 | break; |
1052 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): | | 1052 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): |
1053 | goto fail; | | 1053 | goto fail; |
1054 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): | | 1054 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): |
1055 | break; | | 1055 | break; |
1056 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): | | 1056 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): |
1057 | DPRINTFN(9, "UR_SET_FEATURE port=%d feature=%d\n", | | 1057 | DPRINTFN(9, "UR_SET_FEATURE port=%d feature=%d\n", |
1058 | index, value); | | 1058 | index, value); |
1059 | | | 1059 | |
1060 | if (index < 1 || index > sc->sc_noport) | | 1060 | if (index < 1 || index > sc->sc_noport) |
1061 | goto fail; | | 1061 | goto fail; |
1062 | | | 1062 | |
| @@ -2700,1784 +2700,1784 @@ check_state: | | | @@ -2700,1784 +2700,1784 @@ check_state: |
2700 | td->did_nak = 1; | | 2700 | td->did_nak = 1; |
2701 | if (td->hcsplt != 0) | | 2701 | if (td->hcsplt != 0) |
2702 | goto receive_spkt; | | 2702 | goto receive_spkt; |
2703 | else | | 2703 | else |
2704 | goto receive_pkt; | | 2704 | goto receive_pkt; |
2705 | } | | 2705 | } |
2706 | if (!(hcint & HCINT_SOFTWARE_ONLY)) { | | 2706 | if (!(hcint & HCINT_SOFTWARE_ONLY)) { |
2707 | if (hcint & HCINT_NYET) { | | 2707 | if (hcint & HCINT_NYET) { |
2708 | if (td->hcsplt != 0) { | | 2708 | if (td->hcsplt != 0) { |
2709 | if (!dwc_otg_host_channel_wait(td)) | | 2709 | if (!dwc_otg_host_channel_wait(td)) |
2710 | break; | | 2710 | break; |
2711 | goto receive_pkt; | | 2711 | goto receive_pkt; |
2712 | } | | 2712 | } |
2713 | } | | 2713 | } |
2714 | break; | | 2714 | break; |
2715 | } | | 2715 | } |
2716 | if (hcint & (HCINT_ACK | HCINT_NYET)) { | | 2716 | if (hcint & (HCINT_ACK | HCINT_NYET)) { |
2717 | if (!dwc_otg_host_channel_wait(td)) | | 2717 | if (!dwc_otg_host_channel_wait(td)) |
2718 | break; | | 2718 | break; |
2719 | | | 2719 | |
2720 | /* check if we are complete */ | | 2720 | /* check if we are complete */ |
2721 | if ((td->remainder == 0) || (td->got_short != 0)) { | | 2721 | if ((td->remainder == 0) || (td->got_short != 0)) { |
2722 | if (td->short_pkt) | | 2722 | if (td->short_pkt) |
2723 | return 0; /* complete */ | | 2723 | return 0; /* complete */ |
2724 | | | 2724 | |
2725 | /* | | 2725 | /* |
2726 | * Else need to receive a zero length | | 2726 | * Else need to receive a zero length |
2727 | * packet. | | 2727 | * packet. |
2728 | */ | | 2728 | */ |
2729 | } | | 2729 | } |
2730 | if (td->hcsplt != 0) | | 2730 | if (td->hcsplt != 0) |
2731 | goto receive_spkt; | | 2731 | goto receive_spkt; |
2732 | else | | 2732 | else |
2733 | goto receive_pkt; | | 2733 | goto receive_pkt; |
2734 | } | | 2734 | } |
2735 | break; | | 2735 | break; |
2736 | | | 2736 | |
2737 | case DWC_CHAN_ST_WAIT_S_ANE: | | 2737 | case DWC_CHAN_ST_WAIT_S_ANE: |
2738 | if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { | | 2738 | if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { |
2739 | if (!dwc_otg_host_channel_wait(td)) | | 2739 | if (!dwc_otg_host_channel_wait(td)) |
2740 | break; | | 2740 | break; |
2741 | | | 2741 | |
2742 | td->did_nak = 1; | | 2742 | td->did_nak = 1; |
2743 | goto receive_spkt; | | 2743 | goto receive_spkt; |
2744 | } | | 2744 | } |
2745 | if (hcint & (HCINT_ACK | HCINT_NYET)) { | | 2745 | if (hcint & (HCINT_ACK | HCINT_NYET)) { |
2746 | if (!dwc_otg_host_channel_wait(td)) | | 2746 | if (!dwc_otg_host_channel_wait(td)) |
2747 | break; | | 2747 | break; |
2748 | goto receive_pkt; | | 2748 | goto receive_pkt; |
2749 | } | | 2749 | } |
2750 | break; | | 2750 | break; |
2751 | | | 2751 | |
2752 | case DWC_CHAN_ST_RX_PKT: | | 2752 | case DWC_CHAN_ST_RX_PKT: |
2753 | goto receive_pkt; | | 2753 | goto receive_pkt; |
2754 | | | 2754 | |
2755 | case DWC_CHAN_ST_RX_SPKT: | | 2755 | case DWC_CHAN_ST_RX_SPKT: |
2756 | goto receive_spkt; | | 2756 | goto receive_spkt; |
2757 | | | 2757 | |
2758 | case DWC_CHAN_ST_RX_SPKT_SYNC: | | 2758 | case DWC_CHAN_ST_RX_SPKT_SYNC: |
2759 | goto receive_spkt_sync; | | 2759 | goto receive_spkt_sync; |
2760 | | | 2760 | |
2761 | default: | | 2761 | default: |
2762 | break; | | 2762 | break; |
2763 | } | | 2763 | } |
2764 | goto busy; | | 2764 | goto busy; |
2765 | | | 2765 | |
2766 | receive_pkt: | | 2766 | receive_pkt: |
2767 | DPRINTF("receive_pkt\n"); | | 2767 | DPRINTF("receive_pkt\n"); |
2768 | | | 2768 | |
2769 | if (td->hcsplt != 0) { | | 2769 | if (td->hcsplt != 0) { |
2770 | count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; | | 2770 | count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; |
2771 | | | 2771 | |
2772 | /* check for even microframes */ | | 2772 | /* check for even microframes */ |
2773 | if (count == td->curr_frame) { | | 2773 | if (count == td->curr_frame) { |
2774 | td->state = DWC_CHAN_ST_RX_PKT; | | 2774 | td->state = DWC_CHAN_ST_RX_PKT; |
2775 | dwc_otg_host_channel_free(td); | | 2775 | dwc_otg_host_channel_free(td); |
2776 | /* enable SOF interrupt */ | | 2776 | /* enable SOF interrupt */ |
2777 | dwc_otg_enable_sof_irq(sc); | | 2777 | dwc_otg_enable_sof_irq(sc); |
2778 | goto busy; | | 2778 | goto busy; |
2779 | } else if (count == 0) { | | 2779 | } else if (count == 0) { |
2780 | /* check for start split timeout */ | | 2780 | /* check for start split timeout */ |
2781 | goto receive_spkt; | | 2781 | goto receive_spkt; |
2782 | } | | 2782 | } |
2783 | | | 2783 | |
2784 | td->curr_frame = count; | | 2784 | td->curr_frame = count; |
2785 | td->hcsplt |= HCSPLT_COMPSPLT; | | 2785 | td->hcsplt |= HCSPLT_COMPSPLT; |
2786 | } else if (dwc_otg_host_rate_check(td)) { | | 2786 | } else if (dwc_otg_host_rate_check(td)) { |
2787 | td->state = DWC_CHAN_ST_RX_PKT; | | 2787 | td->state = DWC_CHAN_ST_RX_PKT; |
2788 | dwc_otg_host_channel_free(td); | | 2788 | dwc_otg_host_channel_free(td); |
2789 | goto busy; | | 2789 | goto busy; |
2790 | } | | 2790 | } |
2791 | | | 2791 | |
2792 | td->state = DWC_CHAN_ST_WAIT_ANE; | | 2792 | td->state = DWC_CHAN_ST_WAIT_ANE; |
2793 | | | 2793 | |
2794 | /* receive one packet */ | | 2794 | /* receive one packet */ |
2795 | uint32_t hctsiz = | | 2795 | uint32_t hctsiz = |
2796 | (td->max_packet_size << HCTSIZ_XFERSIZE_SHIFT) | | | 2796 | (td->max_packet_size << HCTSIZ_XFERSIZE_SHIFT) | |
2797 | (1 << HCTSIZ_PKTCNT_SHIFT) | | | 2797 | (1 << HCTSIZ_PKTCNT_SHIFT) | |
2798 | (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : | | 2798 | (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : |
2799 | (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT)); | | 2799 | (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT)); |
2800 | | | 2800 | |
2801 | DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), hctsiz); | | 2801 | DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), hctsiz); |
2802 | | | 2802 | |
2803 | DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); | | 2803 | DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); |
2804 | | | 2804 | |
2805 | hcchar = td->hcchar; | | 2805 | hcchar = td->hcchar; |
2806 | hcchar |= HCCHAR_EPDIR_IN; | | 2806 | hcchar |= HCCHAR_EPDIR_IN; |
2807 | | | 2807 | |
2808 | /* must enable channel before data can be received */ | | 2808 | /* must enable channel before data can be received */ |
2809 | DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); | | 2809 | DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); |
2810 | | | 2810 | |
2811 | goto busy; | | 2811 | goto busy; |
2812 | | | 2812 | |
2813 | receive_spkt: | | 2813 | receive_spkt: |
2814 | if (dwc_otg_host_rate_check(td)) { | | 2814 | if (dwc_otg_host_rate_check(td)) { |
2815 | td->state = DWC_CHAN_ST_RX_SPKT; | | 2815 | td->state = DWC_CHAN_ST_RX_SPKT; |
2816 | dwc_otg_host_channel_free(td); | | 2816 | dwc_otg_host_channel_free(td); |
2817 | goto busy; | | 2817 | goto busy; |
2818 | } | | 2818 | } |
2819 | | | 2819 | |
2820 | receive_spkt_sync: | | 2820 | receive_spkt_sync: |
2821 | if (ep_type == UE_INTERRUPT || | | 2821 | if (ep_type == UE_INTERRUPT || |
2822 | ep_type == UE_ISOCHRONOUS) { | | 2822 | ep_type == UE_ISOCHRONOUS) { |
2823 | count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; | | 2823 | count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; |
2824 | td->curr_frame = count; | | 2824 | td->curr_frame = count; |
2825 | | | 2825 | |
2826 | /* check for non-zero microframe */ | | 2826 | /* check for non-zero microframe */ |
2827 | if (count != 0) { | | 2827 | if (count != 0) { |
2828 | /* enable SOF interrupt */ | | 2828 | /* enable SOF interrupt */ |
2829 | dwc_otg_enable_sof_irq(sc); | | 2829 | dwc_otg_enable_sof_irq(sc); |
2830 | /* set state */ | | 2830 | /* set state */ |
2831 | td->state = DWC_CHAN_ST_RX_SPKT_SYNC; | | 2831 | td->state = DWC_CHAN_ST_RX_SPKT_SYNC; |
2832 | dwc_otg_host_channel_free(td); | | 2832 | dwc_otg_host_channel_free(td); |
2833 | goto busy; | | 2833 | goto busy; |
2834 | } | | 2834 | } |
2835 | } else { | | 2835 | } else { |
2836 | count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; | | 2836 | count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; |
2837 | td->curr_frame = count; | | 2837 | td->curr_frame = count; |
2838 | | | 2838 | |
2839 | /* check for two last frames */ | | 2839 | /* check for two last frames */ |
2840 | if (count >= 6) { | | 2840 | if (count >= 6) { |
2841 | /* enable SOF interrupt */ | | 2841 | /* enable SOF interrupt */ |
2842 | dwc_otg_enable_sof_irq(sc); | | 2842 | dwc_otg_enable_sof_irq(sc); |
2843 | /* set state */ | | 2843 | /* set state */ |
2844 | td->state = DWC_CHAN_ST_RX_SPKT_SYNC; | | 2844 | td->state = DWC_CHAN_ST_RX_SPKT_SYNC; |
2845 | dwc_otg_host_channel_free(td); | | 2845 | dwc_otg_host_channel_free(td); |
2846 | goto busy; | | 2846 | goto busy; |
2847 | } | | 2847 | } |
2848 | } | | 2848 | } |
2849 | | | 2849 | |
2850 | td->hcsplt &= ~HCSPLT_COMPSPLT; | | 2850 | td->hcsplt &= ~HCSPLT_COMPSPLT; |
2851 | td->state = DWC_CHAN_ST_WAIT_S_ANE; | | 2851 | td->state = DWC_CHAN_ST_WAIT_S_ANE; |
2852 | | | 2852 | |
2853 | /* receive one packet */ | | 2853 | /* receive one packet */ |
2854 | DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), | | 2854 | DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), |
2855 | (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : | | 2855 | (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : |
2856 | (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); | | 2856 | (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); |
2857 | | | 2857 | |
2858 | DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); | | 2858 | DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); |
2859 | | | 2859 | |
2860 | hcchar = td->hcchar; | | 2860 | hcchar = td->hcchar; |
2861 | hcchar |= HCCHAR_EPDIR_IN; | | 2861 | hcchar |= HCCHAR_EPDIR_IN; |
2862 | | | 2862 | |
2863 | /* must enable channel before data can be received */ | | 2863 | /* must enable channel before data can be received */ |
2864 | DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); | | 2864 | DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); |
2865 | | | 2865 | |
2866 | busy: | | 2866 | busy: |
2867 | return 1; /* busy */ | | 2867 | return 1; /* busy */ |
2868 | } | | 2868 | } |
2869 | | | 2869 | |
2870 | | | 2870 | |
2871 | static uint8_t | | 2871 | static uint8_t |
2872 | dwc_otg_host_data_tx(struct dwc_otg_td *td) | | 2872 | dwc_otg_host_data_tx(struct dwc_otg_td *td) |
2873 | { | | 2873 | { |
2874 | struct dwc_otg_softc *sc; | | 2874 | struct dwc_otg_softc *sc; |
2875 | uint32_t count; | | 2875 | uint32_t count; |
2876 | uint32_t hcint; | | 2876 | uint32_t hcint; |
2877 | uint32_t hcchar; | | 2877 | uint32_t hcchar; |
2878 | uint8_t ep_type; | | 2878 | uint8_t ep_type; |
2879 | | | 2879 | |
2880 | if (dwc_otg_host_channel_alloc(td)) | | 2880 | if (dwc_otg_host_channel_alloc(td)) |
2881 | return 1; /* busy */ | | 2881 | return 1; /* busy */ |
2882 | | | 2882 | |
2883 | /* get pointer to softc */ | | 2883 | /* get pointer to softc */ |
2884 | sc = DWC_OTG_TD2SC(td); | | 2884 | sc = DWC_OTG_TD2SC(td); |
2885 | | | 2885 | |
2886 | ep_type = ((td->hcchar & | | 2886 | ep_type = ((td->hcchar & |
2887 | HCCHAR_EPTYPE_MASK) >> HCCHAR_EPTYPE_SHIFT); | | 2887 | HCCHAR_EPTYPE_MASK) >> HCCHAR_EPTYPE_SHIFT); |
2888 | | | 2888 | |
2889 | hcint = sc->sc_chan_state[td->channel].hcint; | | 2889 | hcint = sc->sc_chan_state[td->channel].hcint; |
2890 | | | 2890 | |
2891 | DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n", | | 2891 | DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n", |
2892 | td->channel, td->state, hcint, | | 2892 | td->channel, td->state, hcint, |
2893 | DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)), | | 2893 | DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)), |
2894 | DWC_OTG_READ_4(sc, DOTG_HCTSIZ(td->channel))); | | 2894 | DWC_OTG_READ_4(sc, DOTG_HCTSIZ(td->channel))); |
2895 | | | 2895 | |
2896 | if (hcint & (HCINT_RETRY | HCINT_ACK | HCINT_NYET)) { | | 2896 | if (hcint & (HCINT_RETRY | HCINT_ACK | HCINT_NYET)) { |
2897 | /* give success bits priority over failure bits */ | | 2897 | /* give success bits priority over failure bits */ |
2898 | } else if (hcint & HCINT_STALL) { | | 2898 | } else if (hcint & HCINT_STALL) { |
2899 | DPRINTF("CH=%d STALL\n", td->channel); | | 2899 | DPRINTF("CH=%d STALL\n", td->channel); |
2900 | td->error_stall = 1; | | 2900 | td->error_stall = 1; |
2901 | td->error_any = 1; | | 2901 | td->error_any = 1; |
2902 | return 0; /* complete */ | | 2902 | return 0; /* complete */ |
2903 | } else if (hcint & HCINT_ERRORS) { | | 2903 | } else if (hcint & HCINT_ERRORS) { |
2904 | DPRINTF("CH=%d ERROR\n", td->channel); | | 2904 | DPRINTF("CH=%d ERROR\n", td->channel); |
2905 | td->errcnt++; | | 2905 | td->errcnt++; |
2906 | if (td->hcsplt != 0 || td->errcnt >= 3) { | | 2906 | if (td->hcsplt != 0 || td->errcnt >= 3) { |
2907 | td->error_any = 1; | | 2907 | td->error_any = 1; |
2908 | return 0; /* complete */ | | 2908 | return 0; /* complete */ |
2909 | } | | 2909 | } |
2910 | } | | 2910 | } |
2911 | | | 2911 | |
2912 | /* channel must be disabled before we can complete the transfer */ | | 2912 | /* channel must be disabled before we can complete the transfer */ |
2913 | | | 2913 | |
2914 | if (hcint & (HCINT_ERRORS | HCINT_RETRY | HCINT_ACK | HCINT_NYET)) { | | 2914 | if (hcint & (HCINT_ERRORS | HCINT_RETRY | HCINT_ACK | HCINT_NYET)) { |
2915 | | | 2915 | |
2916 | dwc_otg_host_channel_disable(sc, td->channel); | | 2916 | dwc_otg_host_channel_disable(sc, td->channel); |
2917 | | | 2917 | |
2918 | if (!(hcint & HCINT_ERRORS)) | | 2918 | if (!(hcint & HCINT_ERRORS)) |
2919 | td->errcnt = 0; | | 2919 | td->errcnt = 0; |
2920 | } | | 2920 | } |
2921 | | | 2921 | |
2922 | switch (td->state) { | | 2922 | switch (td->state) { |
2923 | case DWC_CHAN_ST_START: | | 2923 | case DWC_CHAN_ST_START: |
2924 | goto send_pkt; | | 2924 | goto send_pkt; |
2925 | | | 2925 | |
2926 | case DWC_CHAN_ST_WAIT_ANE: | | 2926 | case DWC_CHAN_ST_WAIT_ANE: |
2927 | if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { | | 2927 | if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { |
2928 | if (!dwc_otg_host_channel_wait(td)) | | 2928 | if (!dwc_otg_host_channel_wait(td)) |
2929 | break; | | 2929 | break; |
2930 | td->did_nak = 1; | | 2930 | td->did_nak = 1; |
2931 | goto send_pkt; | | 2931 | goto send_pkt; |
2932 | } | | 2932 | } |
2933 | if (hcint & (HCINT_ACK | HCINT_NYET)) { | | 2933 | if (hcint & (HCINT_ACK | HCINT_NYET)) { |
2934 | if (!dwc_otg_host_channel_wait(td)) | | 2934 | if (!dwc_otg_host_channel_wait(td)) |
2935 | break; | | 2935 | break; |
2936 | | | 2936 | |
2937 | td->actlen += td->tx_bytes; | | 2937 | td->actlen += td->tx_bytes; |
2938 | td->offset += td->tx_bytes; | | 2938 | td->offset += td->tx_bytes; |
2939 | td->remainder -= td->tx_bytes; | | 2939 | td->remainder -= td->tx_bytes; |
2940 | td->toggle ^= 1; | | 2940 | td->toggle ^= 1; |
2941 | | | 2941 | |
2942 | /* check remainder */ | | 2942 | /* check remainder */ |
2943 | if (td->remainder == 0) { | | 2943 | if (td->remainder == 0) { |
2944 | if (td->short_pkt) | | 2944 | if (td->short_pkt) |
2945 | return 0; /* complete */ | | 2945 | return 0; /* complete */ |
2946 | | | 2946 | |
2947 | /* | | 2947 | /* |
2948 | * Else we need to transmit a short | | 2948 | * Else we need to transmit a short |
2949 | * packet: | | 2949 | * packet: |
2950 | */ | | 2950 | */ |
2951 | } | | 2951 | } |
2952 | goto send_pkt; | | 2952 | goto send_pkt; |
2953 | } | | 2953 | } |
2954 | break; | | 2954 | break; |
2955 | case DWC_CHAN_ST_WAIT_S_ANE: | | 2955 | case DWC_CHAN_ST_WAIT_S_ANE: |
2956 | if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { | | 2956 | if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { |
2957 | if (!dwc_otg_host_channel_wait(td)) | | 2957 | if (!dwc_otg_host_channel_wait(td)) |
2958 | break; | | 2958 | break; |
2959 | td->did_nak = 1; | | 2959 | td->did_nak = 1; |
2960 | goto send_pkt; | | 2960 | goto send_pkt; |
2961 | } | | 2961 | } |
2962 | if (hcint & (HCINT_ACK | HCINT_NYET)) { | | 2962 | if (hcint & (HCINT_ACK | HCINT_NYET)) { |
2963 | if (!dwc_otg_host_channel_wait(td)) | | 2963 | if (!dwc_otg_host_channel_wait(td)) |
2964 | break; | | 2964 | break; |
2965 | goto send_cpkt; | | 2965 | goto send_cpkt; |
2966 | } | | 2966 | } |
2967 | break; | | 2967 | break; |
2968 | case DWC_CHAN_ST_WAIT_C_ANE: | | 2968 | case DWC_CHAN_ST_WAIT_C_ANE: |
2969 | if (hcint & HCINT_NYET) { | | 2969 | if (hcint & HCINT_NYET) { |
2970 | if (!dwc_otg_host_channel_wait(td)) | | 2970 | if (!dwc_otg_host_channel_wait(td)) |
2971 | break; | | 2971 | break; |
2972 | goto send_cpkt; | | 2972 | goto send_cpkt; |
2973 | } | | 2973 | } |
2974 | if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { | | 2974 | if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { |
2975 | if (!dwc_otg_host_channel_wait(td)) | | 2975 | if (!dwc_otg_host_channel_wait(td)) |
2976 | break; | | 2976 | break; |
2977 | td->did_nak = 1; | | 2977 | td->did_nak = 1; |
2978 | goto send_pkt; | | 2978 | goto send_pkt; |
2979 | } | | 2979 | } |
2980 | if (hcint & HCINT_ACK) { | | 2980 | if (hcint & HCINT_ACK) { |
2981 | if (!dwc_otg_host_channel_wait(td)) | | 2981 | if (!dwc_otg_host_channel_wait(td)) |
2982 | break; | | 2982 | break; |
2983 | td->actlen += td->tx_bytes; | | 2983 | td->actlen += td->tx_bytes; |
2984 | td->offset += td->tx_bytes; | | 2984 | td->offset += td->tx_bytes; |
2985 | td->remainder -= td->tx_bytes; | | 2985 | td->remainder -= td->tx_bytes; |
2986 | td->toggle ^= 1; | | 2986 | td->toggle ^= 1; |
2987 | | | 2987 | |
2988 | /* check remainder */ | | 2988 | /* check remainder */ |
2989 | if (td->remainder == 0) { | | 2989 | if (td->remainder == 0) { |
2990 | if (td->short_pkt) | | 2990 | if (td->short_pkt) |
2991 | return 0; /* complete */ | | 2991 | return 0; /* complete */ |
2992 | | | 2992 | |
2993 | /* else we need to transmit a short packet */ | | 2993 | /* else we need to transmit a short packet */ |
2994 | } | | 2994 | } |
2995 | goto send_pkt; | | 2995 | goto send_pkt; |
2996 | } | | 2996 | } |
2997 | break; | | 2997 | break; |
2998 | | | 2998 | |
2999 | case DWC_CHAN_ST_TX_PKT: | | 2999 | case DWC_CHAN_ST_TX_PKT: |
3000 | goto send_pkt; | | 3000 | goto send_pkt; |
3001 | | | 3001 | |
3002 | case DWC_CHAN_ST_TX_PKT_SYNC: | | 3002 | case DWC_CHAN_ST_TX_PKT_SYNC: |
3003 | goto send_pkt_sync; | | 3003 | goto send_pkt_sync; |
3004 | | | 3004 | |
3005 | case DWC_CHAN_ST_TX_CPKT: | | 3005 | case DWC_CHAN_ST_TX_CPKT: |
3006 | goto send_cpkt; | | 3006 | goto send_cpkt; |
3007 | | | 3007 | |
3008 | default: | | 3008 | default: |
3009 | break; | | 3009 | break; |
3010 | } | | 3010 | } |
3011 | goto busy; | | 3011 | goto busy; |
3012 | | | 3012 | |
3013 | send_pkt: | | 3013 | send_pkt: |
3014 | if (dwc_otg_host_rate_check(td)) { | | 3014 | if (dwc_otg_host_rate_check(td)) { |
3015 | td->state = DWC_CHAN_ST_TX_PKT; | | 3015 | td->state = DWC_CHAN_ST_TX_PKT; |
3016 | dwc_otg_host_channel_free(td); | | 3016 | dwc_otg_host_channel_free(td); |
3017 | goto busy; | | 3017 | goto busy; |
3018 | } | | 3018 | } |
3019 | | | 3019 | |
3020 | send_pkt_sync: | | 3020 | send_pkt_sync: |
3021 | if (td->hcsplt != 0) { | | 3021 | if (td->hcsplt != 0) { |
3022 | count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; | | 3022 | count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; |
3023 | /* check for first or last microframe */ | | 3023 | /* check for first or last microframe */ |
3024 | if (count == 7 || count == 0) { | | 3024 | if (count == 7 || count == 0) { |
3025 | /* enable SOF interrupt */ | | 3025 | /* enable SOF interrupt */ |
3026 | dwc_otg_enable_sof_irq(sc); | | 3026 | dwc_otg_enable_sof_irq(sc); |
3027 | /* set state */ | | 3027 | /* set state */ |
3028 | td->state = DWC_CHAN_ST_TX_PKT_SYNC; | | 3028 | td->state = DWC_CHAN_ST_TX_PKT_SYNC; |
3029 | dwc_otg_host_channel_free(td); | | 3029 | dwc_otg_host_channel_free(td); |
3030 | goto busy; | | 3030 | goto busy; |
3031 | } | | 3031 | } |
3032 | | | 3032 | |
3033 | td->hcsplt &= ~HCSPLT_COMPSPLT; | | 3033 | td->hcsplt &= ~HCSPLT_COMPSPLT; |
3034 | td->state = DWC_CHAN_ST_WAIT_S_ANE; | | 3034 | td->state = DWC_CHAN_ST_WAIT_S_ANE; |
3035 | } else { | | 3035 | } else { |
3036 | td->state = DWC_CHAN_ST_WAIT_ANE; | | 3036 | td->state = DWC_CHAN_ST_WAIT_ANE; |
3037 | } | | 3037 | } |
3038 | | | 3038 | |
3039 | /* send one packet at a time */ | | 3039 | /* send one packet at a time */ |
3040 | count = td->max_packet_size; | | 3040 | count = td->max_packet_size; |
3041 | if (td->remainder < count) { | | 3041 | if (td->remainder < count) { |
3042 | /* we have a short packet */ | | 3042 | /* we have a short packet */ |
3043 | td->short_pkt = 1; | | 3043 | td->short_pkt = 1; |
3044 | count = td->remainder; | | 3044 | count = td->remainder; |
3045 | } | | 3045 | } |
3046 | | | 3046 | |
3047 | /* TODO: HCTSIZ_DOPNG */ | | 3047 | /* TODO: HCTSIZ_DOPNG */ |
3048 | | | 3048 | |
3049 | DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), | | 3049 | DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), |
3050 | (count << HCTSIZ_XFERSIZE_SHIFT) | | | 3050 | (count << HCTSIZ_XFERSIZE_SHIFT) | |
3051 | (1 << HCTSIZ_PKTCNT_SHIFT) | | | 3051 | (1 << HCTSIZ_PKTCNT_SHIFT) | |
3052 | (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : | | 3052 | (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : |
3053 | (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); | | 3053 | (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); |
3054 | | | 3054 | |
3055 | DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); | | 3055 | DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); |
3056 | | | 3056 | |
3057 | hcchar = td->hcchar; | | 3057 | hcchar = td->hcchar; |
3058 | hcchar &= ~HCCHAR_EPDIR_IN; | | 3058 | hcchar &= ~HCCHAR_EPDIR_IN; |
3059 | | | 3059 | |
3060 | /* must enable before writing data to FIFO */ | | 3060 | /* must enable before writing data to FIFO */ |
3061 | DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); | | 3061 | DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); |
3062 | | | 3062 | |
3063 | if (count != 0) { | | 3063 | if (count != 0) { |
3064 | | | 3064 | |
3065 | /* clear topmost word before copy */ | | 3065 | /* clear topmost word before copy */ |
3066 | sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0; | | 3066 | sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0; |
3067 | | | 3067 | |
3068 | DPRINTF("send_pkt_sync td->buf %p len %d\n", td->buf, count); | | 3068 | DPRINTF("send_pkt_sync td->buf %p len %d\n", td->buf, count); |
3069 | | | 3069 | |
3070 | /* copy out data */ | | 3070 | /* copy out data */ |
3071 | usbd_copy_out(td->buf, td->offset, | | 3071 | usbd_copy_out(td->buf, td->offset, |
3072 | sc->sc_tx_bounce_buffer, count); | | 3072 | sc->sc_tx_bounce_buffer, count); |
3073 | | | 3073 | |
3074 | /* transfer data into FIFO */ | | 3074 | /* transfer data into FIFO */ |
3075 | bus_space_write_region_4(sc->sc_iot, sc->sc_ioh, | | 3075 | bus_space_write_region_4(sc->sc_iot, sc->sc_ioh, |
3076 | DOTG_DFIFO(td->channel), | | 3076 | DOTG_DFIFO(td->channel), |
3077 | sc->sc_tx_bounce_buffer, (count + 3) / 4); | | 3077 | sc->sc_tx_bounce_buffer, (count + 3) / 4); |
3078 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, | | 3078 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, |
3079 | DOTG_DFIFO(td->channel), ((count + 3) / 4) * 4, | | 3079 | DOTG_DFIFO(td->channel), ((count + 3) / 4) * 4, |
3080 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); | | 3080 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); |
3081 | } | | 3081 | } |
3082 | | | 3082 | |
3083 | /* store number of bytes transmitted */ | | 3083 | /* store number of bytes transmitted */ |
3084 | td->tx_bytes = count; | | 3084 | td->tx_bytes = count; |
3085 | goto busy; | | 3085 | goto busy; |
3086 | | | 3086 | |
3087 | send_cpkt: | | 3087 | send_cpkt: |
3088 | count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; | | 3088 | count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; |
3089 | /* check for first microframe */ | | 3089 | /* check for first microframe */ |
3090 | if (count == 0) { | | 3090 | if (count == 0) { |
3091 | /* send packet again */ | | 3091 | /* send packet again */ |
3092 | goto send_pkt; | | 3092 | goto send_pkt; |
3093 | } | | 3093 | } |
3094 | | | 3094 | |
3095 | td->hcsplt |= HCSPLT_COMPSPLT; | | 3095 | td->hcsplt |= HCSPLT_COMPSPLT; |
3096 | td->state = DWC_CHAN_ST_WAIT_C_ANE; | | 3096 | td->state = DWC_CHAN_ST_WAIT_C_ANE; |
3097 | | | 3097 | |
3098 | DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), | | 3098 | DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), |
3099 | (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : | | 3099 | (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : |
3100 | (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); | | 3100 | (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); |
3101 | | | 3101 | |
3102 | DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); | | 3102 | DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); |
3103 | | | 3103 | |
3104 | hcchar = td->hcchar; | | 3104 | hcchar = td->hcchar; |
3105 | hcchar &= ~HCCHAR_EPDIR_IN; | | 3105 | hcchar &= ~HCCHAR_EPDIR_IN; |
3106 | | | 3106 | |
3107 | /* must enable channel before writing data to FIFO */ | | 3107 | /* must enable channel before writing data to FIFO */ |
3108 | DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); | | 3108 | DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); |
3109 | | | 3109 | |
3110 | busy: | | 3110 | busy: |
3111 | return 1; /* busy */ | | 3111 | return 1; /* busy */ |
3112 | } | | 3112 | } |
3113 | | | 3113 | |
3114 | uint32_t fifoenters; | | 3114 | uint32_t fifoenters; |
3115 | | | 3115 | |
3116 | static uint8_t | | 3116 | static uint8_t |
3117 | dwc_otg_xfer_do_fifo(usbd_xfer_handle xfer) | | 3117 | dwc_otg_xfer_do_fifo(usbd_xfer_handle xfer) |
3118 | { | | 3118 | { |
3119 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 3119 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
3120 | struct dwc_otg_td *td; | | 3120 | struct dwc_otg_td *td; |
3121 | uint8_t toggle; | | 3121 | uint8_t toggle; |
3122 | uint8_t channel; | | 3122 | uint8_t channel; |
3123 | uint8_t tmr_val; | | 3123 | uint8_t tmr_val; |
3124 | uint8_t tmr_res; | | 3124 | uint8_t tmr_res; |
3125 | | | 3125 | |
3126 | DPRINTFN(9, "xfer %p td %p\n", xfer, dxfer->td_transfer_cache); | | 3126 | DPRINTFN(9, "xfer %p td %p\n", xfer, dxfer->td_transfer_cache); |
3127 | | | 3127 | |
3128 | td = dxfer->td_transfer_cache; | | 3128 | td = dxfer->td_transfer_cache; |
3129 | | | 3129 | |
3130 | while (1) { | | 3130 | while (1) { |
3131 | if (td->func(td)) { | | 3131 | if (td->func(td)) { |
3132 | /* operation in progress */ | | 3132 | /* operation in progress */ |
3133 | break; | | 3133 | break; |
3134 | } | | 3134 | } |
3135 | if (td == dxfer->td_transfer_last) { | | 3135 | if (td == dxfer->td_transfer_last) { |
3136 | goto done; | | 3136 | goto done; |
3137 | } | | 3137 | } |
3138 | if (td->error_any) { | | 3138 | if (td->error_any) { |
3139 | goto done; | | 3139 | goto done; |
3140 | } else if (td->remainder > 0) { | | 3140 | } else if (td->remainder > 0) { |
3141 | /* | | 3141 | /* |
3142 | * We had a short transfer. If there is no alternate | | 3142 | * We had a short transfer. If there is no alternate |
3143 | * next, stop processing ! | | 3143 | * next, stop processing ! |
3144 | */ | | 3144 | */ |
3145 | if (!td->alt_next) | | 3145 | if (!td->alt_next) |
3146 | goto done; | | 3146 | goto done; |
3147 | } | | 3147 | } |
3148 | | | 3148 | |
3149 | /* | | 3149 | /* |
3150 | * Fetch the next transfer descriptor and transfer | | 3150 | * Fetch the next transfer descriptor and transfer |
3151 | * some flags to the next transfer descriptor | | 3151 | * some flags to the next transfer descriptor |
3152 | */ | | 3152 | */ |
3153 | tmr_res = td->tmr_res; | | 3153 | tmr_res = td->tmr_res; |
3154 | tmr_val = td->tmr_val; | | 3154 | tmr_val = td->tmr_val; |
3155 | toggle = td->toggle; | | 3155 | toggle = td->toggle; |
3156 | channel = td->channel; | | 3156 | channel = td->channel; |
3157 | td = td->obj_next; | | 3157 | td = td->obj_next; |
3158 | | | 3158 | |
3159 | dxfer->td_transfer_cache = td; | | 3159 | dxfer->td_transfer_cache = td; |
3160 | td->toggle = toggle; /* transfer toggle */ | | 3160 | td->toggle = toggle; /* transfer toggle */ |
3161 | td->channel = channel; /* transfer channel */ | | 3161 | td->channel = channel; /* transfer channel */ |
3162 | td->tmr_res = tmr_res; | | 3162 | td->tmr_res = tmr_res; |
3163 | td->tmr_val = tmr_val; | | 3163 | td->tmr_val = tmr_val; |
3164 | } | | 3164 | } |
3165 | return 1; /* not complete */ | | 3165 | return 1; /* not complete */ |
3166 | | | 3166 | |
3167 | done: | | 3167 | done: |
3168 | /* compute all actual lengths */ | | 3168 | /* compute all actual lengths */ |
3169 | dwc_otg_standard_done(xfer); | | 3169 | dwc_otg_standard_done(xfer); |
3170 | return 0; /* complete */ | | 3170 | return 0; /* complete */ |
3171 | } | | 3171 | } |
3172 | | | 3172 | |
3173 | Static void | | 3173 | Static void |
3174 | dwc_otg_timer_tick(void *_sc) | | 3174 | dwc_otg_timer_tick(void *_sc) |
3175 | { | | 3175 | { |
3176 | struct dwc_otg_softc *sc = _sc; | | 3176 | struct dwc_otg_softc *sc = _sc; |
3177 | | | 3177 | |
3178 | workqueue_enqueue(sc->sc_wq, (struct work *)&sc->sc_timer_work, NULL); | | 3178 | workqueue_enqueue(sc->sc_wq, (struct work *)&sc->sc_timer_work, NULL); |
3179 | } | | 3179 | } |
3180 | | | 3180 | |
3181 | Static void | | 3181 | Static void |
3182 | dwc_otg_timer(struct dwc_otg_softc *sc) | | 3182 | dwc_otg_timer(struct dwc_otg_softc *sc) |
3183 | { | | 3183 | { |
3184 | struct dwc_otg_xfer *xfer; | | 3184 | struct dwc_otg_xfer *xfer; |
3185 | struct dwc_otg_td *td; | | 3185 | struct dwc_otg_td *td; |
3186 | | | 3186 | |
3187 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3187 | KASSERT(mutex_owned(&sc->sc_lock)); |
3188 | | | 3188 | |
3189 | /* increment timer value */ | | 3189 | /* increment timer value */ |
3190 | sc->sc_tmr_val++; | | 3190 | sc->sc_tmr_val++; |
3191 | | | 3191 | |
3192 | TAILQ_FOREACH(xfer, &sc->sc_active, xnext) { | | 3192 | TAILQ_FOREACH(xfer, &sc->sc_active, xnext) { |
3193 | td = xfer->td_transfer_cache; | | 3193 | td = xfer->td_transfer_cache; |
3194 | if (td != NULL) | | 3194 | if (td != NULL) |
3195 | td->did_nak = 0; | | 3195 | td->did_nak = 0; |
3196 | } | | 3196 | } |
3197 | | | 3197 | |
3198 | /* poll jobs */ | | 3198 | /* poll jobs */ |
3199 | mutex_spin_enter(&sc->sc_intr_lock); | | 3199 | mutex_spin_enter(&sc->sc_intr_lock); |
3200 | dwc_otg_interrupt_poll(sc); | | 3200 | dwc_otg_interrupt_poll(sc); |
3201 | mutex_spin_exit(&sc->sc_intr_lock); | | 3201 | mutex_spin_exit(&sc->sc_intr_lock); |
3202 | | | 3202 | |
3203 | if (sc->sc_timer_active) { | | 3203 | if (sc->sc_timer_active) { |
3204 | /* restart timer */ | | 3204 | /* restart timer */ |
3205 | callout_reset(&sc->sc_timer, mstohz(DWC_OTG_HOST_TIMER_RATE), | | 3205 | callout_reset(&sc->sc_timer, mstohz(DWC_OTG_HOST_TIMER_RATE), |
3206 | dwc_otg_timer_tick, sc); | | 3206 | dwc_otg_timer_tick, sc); |
3207 | } | | 3207 | } |
3208 | } | | 3208 | } |
3209 | | | 3209 | |
3210 | Static void | | 3210 | Static void |
3211 | dwc_otg_timer_start(struct dwc_otg_softc *sc) | | 3211 | dwc_otg_timer_start(struct dwc_otg_softc *sc) |
3212 | { | | 3212 | { |
3213 | if (sc->sc_timer_active != 0) | | 3213 | if (sc->sc_timer_active != 0) |
3214 | return; | | 3214 | return; |
3215 | | | 3215 | |
3216 | sc->sc_timer_active = 1; | | 3216 | sc->sc_timer_active = 1; |
3217 | | | 3217 | |
3218 | /* restart timer */ | | 3218 | /* restart timer */ |
3219 | callout_reset(&sc->sc_timer, mstohz(DWC_OTG_HOST_TIMER_RATE), | | 3219 | callout_reset(&sc->sc_timer, mstohz(DWC_OTG_HOST_TIMER_RATE), |
3220 | dwc_otg_timer_tick, sc); | | 3220 | dwc_otg_timer_tick, sc); |
3221 | } | | 3221 | } |
3222 | | | 3222 | |
3223 | Static void | | 3223 | Static void |
3224 | dwc_otg_timer_stop(struct dwc_otg_softc *sc) | | 3224 | dwc_otg_timer_stop(struct dwc_otg_softc *sc) |
3225 | { | | 3225 | { |
3226 | if (sc->sc_timer_active == 0) | | 3226 | if (sc->sc_timer_active == 0) |
3227 | return; | | 3227 | return; |
3228 | | | 3228 | |
3229 | sc->sc_timer_active = 0; | | 3229 | sc->sc_timer_active = 0; |
3230 | | | 3230 | |
3231 | /* stop timer */ | | 3231 | /* stop timer */ |
3232 | callout_stop(&sc->sc_timer); | | 3232 | callout_stop(&sc->sc_timer); |
3233 | } | | 3233 | } |
3234 | | | 3234 | |
3235 | void | | 3235 | void |
3236 | dwc_otg_interrupt_poll(struct dwc_otg_softc *sc) | | 3236 | dwc_otg_interrupt_poll(struct dwc_otg_softc *sc) |
3237 | { | | 3237 | { |
3238 | uint8_t ch; | | 3238 | uint8_t ch; |
3239 | uint32_t temp; | | 3239 | uint32_t temp; |
3240 | uint32_t intrs; | | 3240 | uint32_t intrs; |
3241 | struct dwc_otg_xfer *dxfer; | | 3241 | struct dwc_otg_xfer *dxfer; |
3242 | uint8_t got_rx_status; | | 3242 | uint8_t got_rx_status; |
3243 | | | 3243 | |
3244 | // DPRINTF("\n"); | | 3244 | // DPRINTF("\n"); |
3245 | | | 3245 | |
3246 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | | 3246 | KASSERT(mutex_owned(&sc->sc_intr_lock)); |
3247 | | | 3247 | |
3248 | repeat: | | 3248 | repeat: |
3249 | /* get all channel interrupts */ | | 3249 | /* get all channel interrupts */ |
3250 | for (ch = 0; ch < sc->sc_host_ch_max; ++ch) { | | 3250 | for (ch = 0; ch < sc->sc_host_ch_max; ++ch) { |
3251 | intrs = DWC_OTG_READ_4(sc, DOTG_HCINT(ch)); | | 3251 | intrs = DWC_OTG_READ_4(sc, DOTG_HCINT(ch)); |
3252 | if (intrs != 0) { | | 3252 | if (intrs != 0) { |
3253 | // DPRINTF("ch %d intrs %08x\n", ch, intrs); | | 3253 | // DPRINTF("ch %d intrs %08x\n", ch, intrs); |
3254 | | | 3254 | |
3255 | DWC_OTG_WRITE_4(sc, DOTG_HCINT(ch), intrs); | | 3255 | DWC_OTG_WRITE_4(sc, DOTG_HCINT(ch), intrs); |
3256 | intrs &= ~HCINT_SOFTWARE_ONLY; | | 3256 | intrs &= ~HCINT_SOFTWARE_ONLY; |
3257 | sc->sc_chan_state[ch].hcint |= intrs; | | 3257 | sc->sc_chan_state[ch].hcint |= intrs; |
3258 | } | | 3258 | } |
3259 | } | | 3259 | } |
3260 | | | 3260 | |
3261 | if (sc->sc_last_rx_status == 0) { | | 3261 | if (sc->sc_last_rx_status == 0) { |
3262 | temp = DWC_OTG_READ_4(sc, DOTG_GINTSTS); | | 3262 | temp = DWC_OTG_READ_4(sc, DOTG_GINTSTS); |
3263 | if (temp & GINTSTS_RXFLVL) { | | 3263 | if (temp & GINTSTS_RXFLVL) { |
3264 | /* pop current status */ | | 3264 | /* pop current status */ |
3265 | sc->sc_last_rx_status = | | 3265 | sc->sc_last_rx_status = |
3266 | DWC_OTG_READ_4(sc, DOTG_GRXSTSP); | | 3266 | DWC_OTG_READ_4(sc, DOTG_GRXSTSP); |
3267 | } | | 3267 | } |
3268 | | | 3268 | |
3269 | if (sc->sc_last_rx_status != 0) { | | 3269 | if (sc->sc_last_rx_status != 0) { |
3270 | uint32_t bcnt; | | 3270 | uint32_t bcnt; |
3271 | uint8_t ep_no; | | 3271 | uint8_t ep_no; |
3272 | | | 3272 | |
3273 | temp = sc->sc_last_rx_status & | | 3273 | temp = sc->sc_last_rx_status & |
3274 | GRXSTSRD_PKTSTS_MASK; | | 3274 | GRXSTSRD_PKTSTS_MASK; |
3275 | | | 3275 | |
3276 | /* non-data messages we simply skip */ | | 3276 | /* non-data messages we simply skip */ |
3277 | if (temp != GRXSTSRD_STP_DATA && | | 3277 | if (temp != GRXSTSRD_STP_DATA && |
3278 | temp != GRXSTSRD_OUT_DATA) { | | 3278 | temp != GRXSTSRD_OUT_DATA) { |
3279 | dwc_otg_common_rx_ack(sc); | | 3279 | dwc_otg_common_rx_ack(sc); |
3280 | goto repeat; | | 3280 | goto repeat; |
3281 | } | | 3281 | } |
3282 | | | 3282 | |
3283 | bcnt = GRXSTSRD_BCNT_GET(sc->sc_last_rx_status); | | 3283 | bcnt = GRXSTSRD_BCNT_GET(sc->sc_last_rx_status); |
3284 | ep_no = GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status); | | 3284 | ep_no = GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status); |
3285 | | | 3285 | |
3286 | /* receive data, if any */ | | 3286 | /* receive data, if any */ |
3287 | if (bcnt != 0) { | | 3287 | if (bcnt != 0) { |
3288 | DPRINTF("Reading %d bytes from ep %d\n", bcnt, | | 3288 | DPRINTF("Reading %d bytes from ep %d\n", bcnt, |
3289 | ep_no); | | 3289 | ep_no); |
3290 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, | | 3290 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, |
3291 | DOTG_DFIFO(ep_no), ((bcnt + 3) / 4) * 4, | | 3291 | DOTG_DFIFO(ep_no), ((bcnt + 3) / 4) * 4, |
3292 | BUS_SPACE_BARRIER_READ); | | 3292 | BUS_SPACE_BARRIER_READ); |
3293 | bus_space_read_region_4(sc->sc_iot, sc->sc_ioh, | | 3293 | bus_space_read_region_4(sc->sc_iot, sc->sc_ioh, |
3294 | DOTG_DFIFO(ep_no), sc->sc_rx_bounce_buffer, | | 3294 | DOTG_DFIFO(ep_no), sc->sc_rx_bounce_buffer, |
3295 | (bcnt + 3) / 4); | | 3295 | (bcnt + 3) / 4); |
3296 | } | | 3296 | } |
3297 | | | 3297 | |
3298 | /* check if we should dump the data */ | | 3298 | /* check if we should dump the data */ |
3299 | if (!(sc->sc_active_rx_ep & (1U << ep_no))) { | | 3299 | if (!(sc->sc_active_rx_ep & (1U << ep_no))) { |
3300 | dwc_otg_common_rx_ack(sc); | | 3300 | dwc_otg_common_rx_ack(sc); |
3301 | goto repeat; | | 3301 | goto repeat; |
3302 | } | | 3302 | } |
3303 | | | 3303 | |
3304 | got_rx_status = 1; | | 3304 | got_rx_status = 1; |
3305 | | | 3305 | |
3306 | DPRINTFN(5, "RX status = 0x%08x: " | | 3306 | DPRINTFN(5, "RX status = 0x%08x: " |
3307 | "ch=%d pid=%d bytes=%d sts=%d\n", | | 3307 | "ch=%d pid=%d bytes=%d sts=%d\n", |
3308 | sc->sc_last_rx_status, ep_no, | | 3308 | sc->sc_last_rx_status, ep_no, |
3309 | (sc->sc_last_rx_status >> 15) & 3, | | 3309 | (sc->sc_last_rx_status >> 15) & 3, |
3310 | GRXSTSRD_BCNT_GET(sc->sc_last_rx_status), | | 3310 | GRXSTSRD_BCNT_GET(sc->sc_last_rx_status), |
3311 | (sc->sc_last_rx_status >> 17) & 15); | | 3311 | (sc->sc_last_rx_status >> 17) & 15); |
3312 | } else { | | 3312 | } else { |
3313 | got_rx_status = 0; | | 3313 | got_rx_status = 0; |
3314 | } | | 3314 | } |
3315 | } else { | | 3315 | } else { |
3316 | uint8_t ep_no; | | 3316 | uint8_t ep_no; |
3317 | | | 3317 | |
3318 | ep_no = GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status); | | 3318 | ep_no = GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status); |
3319 | DPRINTF("%s: ep_no %d\n", __func__, ep_no); | | 3319 | DPRINTF("%s: ep_no %d\n", __func__, ep_no); |
3320 | | | 3320 | |
3321 | /* check if we should dump the data */ | | 3321 | /* check if we should dump the data */ |
3322 | if (!(sc->sc_active_rx_ep & (1U << ep_no))) { | | 3322 | if (!(sc->sc_active_rx_ep & (1U << ep_no))) { |
3323 | dwc_otg_common_rx_ack(sc); | | 3323 | dwc_otg_common_rx_ack(sc); |
3324 | goto repeat; | | 3324 | goto repeat; |
3325 | } | | 3325 | } |
3326 | | | 3326 | |
3327 | got_rx_status = 1; | | 3327 | got_rx_status = 1; |
3328 | } | | 3328 | } |
3329 | | | 3329 | |
3330 | TAILQ_FOREACH(dxfer, &sc->sc_active, xnext) { | | 3330 | TAILQ_FOREACH(dxfer, &sc->sc_active, xnext) { |
3331 | if (!dwc_otg_xfer_do_fifo(&dxfer->xfer)) { | | 3331 | if (!dwc_otg_xfer_do_fifo(&dxfer->xfer)) { |
3332 | /* queue has been modified */ | | 3332 | /* queue has been modified */ |
3333 | goto repeat; | | 3333 | goto repeat; |
3334 | } | | 3334 | } |
3335 | } | | 3335 | } |
3336 | | | 3336 | |
3337 | if (got_rx_status) { | | 3337 | if (got_rx_status) { |
3338 | /* check if data was consumed */ | | 3338 | /* check if data was consumed */ |
3339 | if (sc->sc_last_rx_status == 0) | | 3339 | if (sc->sc_last_rx_status == 0) |
3340 | goto repeat; | | 3340 | goto repeat; |
3341 | | | 3341 | |
3342 | /* disable RX FIFO level interrupt */ | | 3342 | /* disable RX FIFO level interrupt */ |
3343 | sc->sc_irq_mask &= ~GINTMSK_RXFLVLMSK; | | 3343 | sc->sc_irq_mask &= ~GINTMSK_RXFLVLMSK; |
3344 | DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); | | 3344 | DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); |
3345 | } | | 3345 | } |
3346 | } | | 3346 | } |
3347 | | | 3347 | |
3348 | Static void | | 3348 | Static void |
3349 | dwc_otg_vbus_interrupt(struct dwc_otg_softc *sc) | | 3349 | dwc_otg_vbus_interrupt(struct dwc_otg_softc *sc) |
3350 | { | | 3350 | { |
3351 | uint32_t temp; | | 3351 | uint32_t temp; |
3352 | | | 3352 | |
3353 | temp = DWC_OTG_READ_4(sc, DOTG_GOTGCTL); | | 3353 | temp = DWC_OTG_READ_4(sc, DOTG_GOTGCTL); |
3354 | | | 3354 | |
3355 | DPRINTFN(15, "GOTGCTL %08x\n", temp); | | 3355 | DPRINTFN(15, "GOTGCTL %08x\n", temp); |
3356 | | | 3356 | |
3357 | if (temp & (GOTGCTL_ASESVLD | GOTGCTL_BSESVLD)) { | | 3357 | if (temp & (GOTGCTL_ASESVLD | GOTGCTL_BSESVLD)) { |
3358 | if (!sc->sc_flags.status_vbus) { | | 3358 | if (!sc->sc_flags.status_vbus) { |
3359 | sc->sc_flags.status_vbus = 1; | | 3359 | sc->sc_flags.status_vbus = 1; |
3360 | | | 3360 | |
3361 | /* complete root HUB interrupt endpoint */ | | 3361 | /* complete root HUB interrupt endpoint */ |
3362 | dwc_otg_root_intr(sc); | | 3362 | dwc_otg_root_intr(sc); |
3363 | } | | 3363 | } |
3364 | } else { | | 3364 | } else { |
3365 | if (sc->sc_flags.status_vbus) { | | 3365 | if (sc->sc_flags.status_vbus) { |
3366 | sc->sc_flags.status_vbus = 0; | | 3366 | sc->sc_flags.status_vbus = 0; |
3367 | sc->sc_flags.status_bus_reset = 0; | | 3367 | sc->sc_flags.status_bus_reset = 0; |
3368 | sc->sc_flags.status_suspend = 0; | | 3368 | sc->sc_flags.status_suspend = 0; |
3369 | sc->sc_flags.change_suspend = 0; | | 3369 | sc->sc_flags.change_suspend = 0; |
3370 | sc->sc_flags.change_connect = 1; | | 3370 | sc->sc_flags.change_connect = 1; |
3371 | | | 3371 | |
3372 | /* complete root HUB interrupt endpoint */ | | 3372 | /* complete root HUB interrupt endpoint */ |
3373 | dwc_otg_root_intr(sc); | | 3373 | dwc_otg_root_intr(sc); |
3374 | } | | 3374 | } |
3375 | } | | 3375 | } |
3376 | } | | 3376 | } |
3377 | | | 3377 | |
3378 | int | | 3378 | int |
3379 | dwc_otg_interrupt(struct dwc_otg_softc *sc) | | 3379 | dwc_otg_interrupt(struct dwc_otg_softc *sc) |
3380 | { | | 3380 | { |
3381 | uint32_t status; | | 3381 | uint32_t status; |
3382 | | | 3382 | |
3383 | DOTG_EVCNT_INCR(sc->sc_ev_intr); | | 3383 | DOTG_EVCNT_INCR(sc->sc_ev_intr); |
3384 | | | 3384 | |
3385 | /* read and clear interrupt status */ | | 3385 | /* read and clear interrupt status */ |
3386 | status = DWC_OTG_READ_4(sc, DOTG_GINTSTS); | | 3386 | status = DWC_OTG_READ_4(sc, DOTG_GINTSTS); |
3387 | DWC_OTG_WRITE_4(sc, DOTG_GINTSTS, status); | | 3387 | DWC_OTG_WRITE_4(sc, DOTG_GINTSTS, status); |
3388 | | | 3388 | |
3389 | #ifdef DOTG_COUNTERS | | 3389 | #ifdef DOTG_COUNTERS |
3390 | for (size_t i = DWC_OTG_INTRBITF; i < DWC_OTG_NINTRBITS; i++) { | | 3390 | for (size_t i = DWC_OTG_INTRBITF; i < DWC_OTG_NINTRBITS; i++) { |
3391 | if (status & (1 << i)) { | | 3391 | if (status & (1 << i)) { |
3392 | DOTG_EVCNT_INCR(sc->sc_ev_intr_bit[i]); | | 3392 | DOTG_EVCNT_INCR(sc->sc_ev_intr_bit[i]); |
3393 | } | | 3393 | } |
3394 | } | | 3394 | } |
3395 | #endif | | 3395 | #endif |
3396 | | | 3396 | |
3397 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | | 3397 | KASSERT(mutex_owned(&sc->sc_intr_lock)); |
3398 | if (status & GINTSTS_USBRST) { | | 3398 | if (status & GINTSTS_USBRST) { |
3399 | DPRINTF("GINTSTS_USBRST\n"); | | 3399 | DPRINTF("GINTSTS_USBRST\n"); |
3400 | | | 3400 | |
3401 | /* set correct state */ | | 3401 | /* set correct state */ |
3402 | sc->sc_flags.status_device_mode = 1; | | 3402 | sc->sc_flags.status_device_mode = 1; |
3403 | sc->sc_flags.status_bus_reset = 0; | | 3403 | sc->sc_flags.status_bus_reset = 0; |
3404 | sc->sc_flags.status_suspend = 0; | | 3404 | sc->sc_flags.status_suspend = 0; |
3405 | sc->sc_flags.change_suspend = 0; | | 3405 | sc->sc_flags.change_suspend = 0; |
3406 | sc->sc_flags.change_connect = 1; | | 3406 | sc->sc_flags.change_connect = 1; |
3407 | | | 3407 | |
3408 | /* complete root HUB interrupt endpoint */ | | 3408 | /* complete root HUB interrupt endpoint */ |
3409 | dwc_otg_root_intr(sc); | | 3409 | dwc_otg_root_intr(sc); |
3410 | } | | 3410 | } |
3411 | | | 3411 | |
3412 | /* check for any bus state change interrupts */ | | 3412 | /* check for any bus state change interrupts */ |
3413 | if (status & GINTSTS_ENUMDONE) { | | 3413 | if (status & GINTSTS_ENUMDONE) { |
3414 | uint32_t temp; | | 3414 | uint32_t temp; |
3415 | | | 3415 | |
3416 | DPRINTFN(5, "end of reset\n"); | | 3416 | DPRINTFN(5, "end of reset\n"); |
3417 | | | 3417 | |
3418 | /* set correct state */ | | 3418 | /* set correct state */ |
3419 | sc->sc_flags.status_device_mode = 1; | | 3419 | sc->sc_flags.status_device_mode = 1; |
3420 | sc->sc_flags.status_bus_reset = 1; | | 3420 | sc->sc_flags.status_bus_reset = 1; |
3421 | sc->sc_flags.status_suspend = 0; | | 3421 | sc->sc_flags.status_suspend = 0; |
3422 | sc->sc_flags.change_suspend = 0; | | 3422 | sc->sc_flags.change_suspend = 0; |
3423 | sc->sc_flags.change_connect = 1; | | 3423 | sc->sc_flags.change_connect = 1; |
3424 | sc->sc_flags.status_low_speed = 0; | | 3424 | sc->sc_flags.status_low_speed = 0; |
3425 | sc->sc_flags.port_enabled = 1; | | 3425 | sc->sc_flags.port_enabled = 1; |
3426 | | | 3426 | |
3427 | /* reset FIFOs */ | | 3427 | /* reset FIFOs */ |
3428 | dwc_otg_init_fifo(sc, DWC_MODE_DEVICE); | | 3428 | dwc_otg_init_fifo(sc, DWC_MODE_DEVICE); |
3429 | | | 3429 | |
3430 | /* reset function address */ | | 3430 | /* reset function address */ |
3431 | dwc_otg_set_address(sc, 0); | | 3431 | dwc_otg_set_address(sc, 0); |
3432 | | | 3432 | |
3433 | /* figure out enumeration speed */ | | 3433 | /* figure out enumeration speed */ |
3434 | temp = DWC_OTG_READ_4(sc, DOTG_DSTS); | | 3434 | temp = DWC_OTG_READ_4(sc, DOTG_DSTS); |
3435 | if (DSTS_ENUMSPD_GET(temp) == DSTS_ENUMSPD_HI) | | 3435 | if (DSTS_ENUMSPD_GET(temp) == DSTS_ENUMSPD_HI) |
3436 | sc->sc_flags.status_high_speed = 1; | | 3436 | sc->sc_flags.status_high_speed = 1; |
3437 | else | | 3437 | else |
3438 | sc->sc_flags.status_high_speed = 0; | | 3438 | sc->sc_flags.status_high_speed = 0; |
3439 | | | 3439 | |
3440 | /* disable resume interrupt and enable suspend interrupt */ | | 3440 | /* disable resume interrupt and enable suspend interrupt */ |
3441 | | | 3441 | |
3442 | sc->sc_irq_mask &= ~GINTMSK_WKUPINTMSK; | | 3442 | sc->sc_irq_mask &= ~GINTMSK_WKUPINTMSK; |
3443 | sc->sc_irq_mask |= GINTMSK_USBSUSPMSK; | | 3443 | sc->sc_irq_mask |= GINTMSK_USBSUSPMSK; |
3444 | DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); | | 3444 | DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); |
3445 | | | 3445 | |
3446 | /* complete root HUB interrupt endpoint */ | | 3446 | /* complete root HUB interrupt endpoint */ |
3447 | dwc_otg_root_intr(sc); | | 3447 | dwc_otg_root_intr(sc); |
3448 | } | | 3448 | } |
3449 | | | 3449 | |
3450 | if (status & GINTSTS_PRTINT) { | | 3450 | if (status & GINTSTS_PRTINT) { |
3451 | DPRINTF("GINTSTS_PRTINT\n"); | | 3451 | DPRINTF("GINTSTS_PRTINT\n"); |
3452 | uint32_t hprt; | | 3452 | uint32_t hprt; |
3453 | | | 3453 | |
3454 | /* Why is this needed ? */ | | 3454 | /* Why is this needed ? */ |
3455 | delay(62000); | | 3455 | delay(62000); |
3456 | | | 3456 | |
3457 | hprt = DWC_OTG_READ_4(sc, DOTG_HPRT); | | 3457 | hprt = DWC_OTG_READ_4(sc, DOTG_HPRT); |
3458 | | | 3458 | |
3459 | /* clear change bits */ | | 3459 | /* clear change bits */ |
3460 | DWC_OTG_WRITE_4(sc, DOTG_HPRT, (hprt & ( | | 3460 | DWC_OTG_WRITE_4(sc, DOTG_HPRT, (hprt & ( |
3461 | HPRT_PRTPWR | HPRT_PRTENCHNG | | | 3461 | HPRT_PRTPWR | HPRT_PRTENCHNG | |
3462 | HPRT_PRTCONNDET | HPRT_PRTOVRCURRCHNG)) | | | 3462 | HPRT_PRTCONNDET | HPRT_PRTOVRCURRCHNG)) | |
3463 | sc->sc_hprt_val); | | 3463 | sc->sc_hprt_val); |
3464 | | | 3464 | |
3465 | DPRINTFN(12, "GINTSTS=0x%08x, HPRT=0x%08x\n", status, hprt); | | 3465 | DPRINTFN(12, "GINTSTS=0x%08x, HPRT=0x%08x\n", status, hprt); |
3466 | | | 3466 | |
3467 | sc->sc_flags.status_device_mode = 0; | | 3467 | sc->sc_flags.status_device_mode = 0; |
3468 | | | 3468 | |
3469 | if (hprt & HPRT_PRTCONNSTS) | | 3469 | if (hprt & HPRT_PRTCONNSTS) |
3470 | sc->sc_flags.status_bus_reset = 1; | | 3470 | sc->sc_flags.status_bus_reset = 1; |
3471 | else | | 3471 | else |
3472 | sc->sc_flags.status_bus_reset = 0; | | 3472 | sc->sc_flags.status_bus_reset = 0; |
3473 | | | 3473 | |
3474 | if (hprt & HPRT_PRTENCHNG) | | 3474 | if (hprt & HPRT_PRTENCHNG) |
3475 | sc->sc_flags.change_enabled = 1; | | 3475 | sc->sc_flags.change_enabled = 1; |
3476 | | | 3476 | |
3477 | if (hprt & HPRT_PRTENA) | | 3477 | if (hprt & HPRT_PRTENA) |
3478 | sc->sc_flags.port_enabled = 1; | | 3478 | sc->sc_flags.port_enabled = 1; |
3479 | else | | 3479 | else |
3480 | sc->sc_flags.port_enabled = 0; | | 3480 | sc->sc_flags.port_enabled = 0; |
3481 | | | 3481 | |
3482 | if (hprt & HPRT_PRTOVRCURRCHNG) | | 3482 | if (hprt & HPRT_PRTOVRCURRCHNG) |
3483 | sc->sc_flags.change_over_current = 1; | | 3483 | sc->sc_flags.change_over_current = 1; |
3484 | | | 3484 | |
3485 | if (hprt & HPRT_PRTOVRCURRACT) | | 3485 | if (hprt & HPRT_PRTOVRCURRACT) |
3486 | sc->sc_flags.port_over_current = 1; | | 3486 | sc->sc_flags.port_over_current = 1; |
3487 | else | | 3487 | else |
3488 | sc->sc_flags.port_over_current = 0; | | 3488 | sc->sc_flags.port_over_current = 0; |
3489 | | | 3489 | |
3490 | if (hprt & HPRT_PRTPWR) | | 3490 | if (hprt & HPRT_PRTPWR) |
3491 | sc->sc_flags.port_powered = 1; | | 3491 | sc->sc_flags.port_powered = 1; |
3492 | else | | 3492 | else |
3493 | sc->sc_flags.port_powered = 0; | | 3493 | sc->sc_flags.port_powered = 0; |
3494 | | | 3494 | |
3495 | if (((hprt & HPRT_PRTSPD_MASK) | | 3495 | if (((hprt & HPRT_PRTSPD_MASK) |
3496 | >> HPRT_PRTSPD_SHIFT) == HPRT_PRTSPD_LOW) | | 3496 | >> HPRT_PRTSPD_SHIFT) == HPRT_PRTSPD_LOW) |
3497 | sc->sc_flags.status_low_speed = 1; | | 3497 | sc->sc_flags.status_low_speed = 1; |
3498 | else | | 3498 | else |
3499 | sc->sc_flags.status_low_speed = 0; | | 3499 | sc->sc_flags.status_low_speed = 0; |
3500 | | | 3500 | |
3501 | if (((hprt & HPRT_PRTSPD_MASK) | | 3501 | if (((hprt & HPRT_PRTSPD_MASK) |
3502 | >> HPRT_PRTSPD_SHIFT) == HPRT_PRTSPD_HIGH) | | 3502 | >> HPRT_PRTSPD_SHIFT) == HPRT_PRTSPD_HIGH) |
3503 | sc->sc_flags.status_high_speed = 1; | | 3503 | sc->sc_flags.status_high_speed = 1; |
3504 | else | | 3504 | else |
3505 | sc->sc_flags.status_high_speed = 0; | | 3505 | sc->sc_flags.status_high_speed = 0; |
3506 | | | 3506 | |
3507 | if (hprt & HPRT_PRTCONNDET) | | 3507 | if (hprt & HPRT_PRTCONNDET) |
3508 | sc->sc_flags.change_connect = 1; | | 3508 | sc->sc_flags.change_connect = 1; |
3509 | | | 3509 | |
3510 | if (hprt & HPRT_PRTSUSP) | | 3510 | if (hprt & HPRT_PRTSUSP) |
3511 | dwc_otg_suspend_irq(sc); | | 3511 | dwc_otg_suspend_irq(sc); |
3512 | else | | 3512 | else |
3513 | dwc_otg_resume_irq(sc); | | 3513 | dwc_otg_resume_irq(sc); |
3514 | | | 3514 | |
3515 | /* complete root HUB interrupt endpoint */ | | 3515 | /* complete root HUB interrupt endpoint */ |
3516 | dwc_otg_root_intr(sc); | | 3516 | dwc_otg_root_intr(sc); |
3517 | } | | 3517 | } |
3518 | | | 3518 | |
3519 | /* | | 3519 | /* |
3520 | * If resume and suspend is set at the same time we interpret | | 3520 | * If resume and suspend is set at the same time we interpret |
3521 | * that like RESUME. Resume is set when there is at least 3 | | 3521 | * that like RESUME. Resume is set when there is at least 3 |
3522 | * milliseconds of inactivity on the USB BUS. | | 3522 | * milliseconds of inactivity on the USB BUS. |
3523 | */ | | 3523 | */ |
3524 | if (status & GINTSTS_WKUPINT) { | | 3524 | if (status & GINTSTS_WKUPINT) { |
3525 | DPRINTFN(5, "resume interrupt\n"); | | 3525 | DPRINTFN(5, "resume interrupt\n"); |
3526 | | | 3526 | |
3527 | dwc_otg_resume_irq(sc); | | 3527 | dwc_otg_resume_irq(sc); |
3528 | } | | 3528 | } |
3529 | | | 3529 | |
3530 | if (status & GINTSTS_USBSUSP) { | | 3530 | if (status & GINTSTS_USBSUSP) { |
3531 | | | 3531 | |
3532 | DPRINTFN(5, "suspend interrupt\n"); | | 3532 | DPRINTFN(5, "suspend interrupt\n"); |
3533 | | | 3533 | |
3534 | dwc_otg_suspend_irq(sc); | | 3534 | dwc_otg_suspend_irq(sc); |
3535 | } | | 3535 | } |
3536 | | | 3536 | |
3537 | /* check VBUS */ | | 3537 | /* check VBUS */ |
3538 | if (status & (GINTSTS_USBSUSP | GINTSTS_USBRST | GINTSTS_OTGINT | | | 3538 | if (status & (GINTSTS_USBSUSP | GINTSTS_USBRST | GINTSTS_OTGINT | |
3539 | GINTSTS_SESSREQINT)) { | | 3539 | GINTSTS_SESSREQINT)) { |
3540 | DPRINTFN(5, "vbus interrupt\n"); | | 3540 | DPRINTFN(5, "vbus interrupt\n"); |
3541 | | | 3541 | |
3542 | dwc_otg_vbus_interrupt(sc); | | 3542 | dwc_otg_vbus_interrupt(sc); |
3543 | } | | 3543 | } |
3544 | | | 3544 | |
3545 | /* clear all IN endpoint interrupts */ | | 3545 | /* clear all IN endpoint interrupts */ |
3546 | if (status & GINTSTS_IEPINT) { | | 3546 | if (status & GINTSTS_IEPINT) { |
3547 | uint32_t temp; | | 3547 | uint32_t temp; |
3548 | uint8_t x; | | 3548 | uint8_t x; |
3549 | | | 3549 | |
3550 | DPRINTFN(5, "endpoint interrupt\n"); | | 3550 | DPRINTFN(5, "endpoint interrupt\n"); |
3551 | | | 3551 | |
3552 | for (x = 0; x != sc->sc_dev_in_ep_max; x++) { | | 3552 | for (x = 0; x != sc->sc_dev_in_ep_max; x++) { |
3553 | temp = DWC_OTG_READ_4(sc, DOTG_DIEPINT(x)); | | 3553 | temp = DWC_OTG_READ_4(sc, DOTG_DIEPINT(x)); |
3554 | if (temp & DIEPMSK_XFERCOMPLMSK) { | | 3554 | if (temp & DIEPMSK_XFERCOMPLMSK) { |
3555 | DWC_OTG_WRITE_4(sc, DOTG_DIEPINT(x), | | 3555 | DWC_OTG_WRITE_4(sc, DOTG_DIEPINT(x), |
3556 | DIEPMSK_XFERCOMPLMSK); | | 3556 | DIEPMSK_XFERCOMPLMSK); |
3557 | } | | 3557 | } |
3558 | } | | 3558 | } |
3559 | } | | 3559 | } |
3560 | | | 3560 | |
3561 | /* check for SOF interrupt */ | | 3561 | /* check for SOF interrupt */ |
3562 | if (status & GINTSTS_SOF) { | | 3562 | if (status & GINTSTS_SOF) { |
3563 | if (sc->sc_irq_mask & GINTMSK_SOFMSK) { | | 3563 | if (sc->sc_irq_mask & GINTMSK_SOFMSK) { |
3564 | uint8_t x; | | 3564 | uint8_t x; |
3565 | uint8_t y; | | 3565 | uint8_t y; |
3566 | | | 3566 | |
3567 | for (x = y = 0; x != sc->sc_host_ch_max; x++) { | | 3567 | for (x = y = 0; x != sc->sc_host_ch_max; x++) { |
3568 | if (sc->sc_chan_state[x].wait_sof != 0) { | | 3568 | if (sc->sc_chan_state[x].wait_sof != 0) { |
3569 | if (--(sc->sc_chan_state[x].wait_sof) != 0) | | 3569 | if (--(sc->sc_chan_state[x].wait_sof) != 0) |
3570 | y = 1; | | 3570 | y = 1; |
3571 | } | | 3571 | } |
3572 | } | | 3572 | } |
3573 | if (y == 0) { | | 3573 | if (y == 0) { |
3574 | sc->sc_irq_mask &= ~GINTMSK_SOFMSK; | | 3574 | sc->sc_irq_mask &= ~GINTMSK_SOFMSK; |
3575 | DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); | | 3575 | DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); |
3576 | } | | 3576 | } |
3577 | } | | 3577 | } |
3578 | } | | 3578 | } |
3579 | | | 3579 | |
3580 | /* poll FIFO(s) */ | | 3580 | /* poll FIFO(s) */ |
3581 | dwc_otg_interrupt_poll(sc); | | 3581 | dwc_otg_interrupt_poll(sc); |
3582 | | | 3582 | |
3583 | return 1; | | 3583 | return 1; |
3584 | } | | 3584 | } |
3585 | | | 3585 | |
3586 | static void | | 3586 | static void |
3587 | dwc_otg_setup_standard_chain_sub(struct dwc_otg_std_temp *temp) | | 3587 | dwc_otg_setup_standard_chain_sub(struct dwc_otg_std_temp *temp) |
3588 | { | | 3588 | { |
3589 | struct dwc_otg_td *td; | | 3589 | struct dwc_otg_td *td; |
3590 | | | 3590 | |
3591 | /* get current Transfer Descriptor */ | | 3591 | /* get current Transfer Descriptor */ |
3592 | td = temp->td_next; | | 3592 | td = temp->td_next; |
3593 | temp->td = td; | | 3593 | temp->td = td; |
3594 | | | 3594 | |
3595 | DPRINTF("td %p buf %p \n", td, temp->buf); | | 3595 | DPRINTF("td %p buf %p \n", td, temp->buf); |
3596 | DPRINTF("td %p func %p offset %08x remainder %08x shrt %d alt %d\n", | | 3596 | DPRINTF("td %p func %p offset %08x remainder %08x shrt %d alt %d\n", |
3597 | td, td->func, temp->offset, temp->len, temp->short_pkt, | | 3597 | td, td->func, temp->offset, temp->len, temp->short_pkt, |
3598 | temp->setup_alt_next); | | 3598 | temp->setup_alt_next); |
3599 | /* prepare for next TD */ | | 3599 | /* prepare for next TD */ |
3600 | temp->td_next = td->obj_next; | | 3600 | temp->td_next = td->obj_next; |
3601 | | | 3601 | |
3602 | /* fill out the Transfer Descriptor */ | | 3602 | /* fill out the Transfer Descriptor */ |
3603 | td->func = temp->func; | | 3603 | td->func = temp->func; |
3604 | td->xfer = temp->xfer; | | 3604 | td->xfer = temp->xfer; |
3605 | td->buf = temp->buf; | | 3605 | td->buf = temp->buf; |
3606 | td->offset = temp->offset; | | 3606 | td->offset = temp->offset; |
3607 | td->remainder = temp->len; | | 3607 | td->remainder = temp->len; |
3608 | td->actlen = 0; | | 3608 | td->actlen = 0; |
3609 | td->tx_bytes = 0; | | 3609 | td->tx_bytes = 0; |
3610 | td->error_any = 0; | | 3610 | td->error_any = 0; |
3611 | td->error_stall = 0; | | 3611 | td->error_stall = 0; |
3612 | td->npkt = 0; | | 3612 | td->npkt = 0; |
3613 | td->did_stall = temp->did_stall; | | 3613 | td->did_stall = temp->did_stall; |
3614 | td->short_pkt = temp->short_pkt; | | 3614 | td->short_pkt = temp->short_pkt; |
3615 | td->alt_next = temp->setup_alt_next; | | 3615 | td->alt_next = temp->setup_alt_next; |
3616 | td->set_toggle = 0; | | 3616 | td->set_toggle = 0; |
3617 | td->got_short = 0; | | 3617 | td->got_short = 0; |
3618 | td->did_nak = 0; | | 3618 | td->did_nak = 0; |
3619 | td->channel = DWC_OTG_MAX_CHANNELS; | | 3619 | td->channel = DWC_OTG_MAX_CHANNELS; |
3620 | td->state = DWC_CHAN_ST_START; | | 3620 | td->state = DWC_CHAN_ST_START; |
3621 | td->errcnt = 0; | | 3621 | td->errcnt = 0; |
3622 | td->retrycnt = 0; | | 3622 | td->retrycnt = 0; |
3623 | td->toggle = 0; | | 3623 | td->toggle = 0; |
3624 | } | | 3624 | } |
3625 | | | 3625 | |
3626 | Static void | | 3626 | Static void |
3627 | dwc_otg_setup_ctrl_chain(usbd_xfer_handle xfer) | | 3627 | dwc_otg_setup_ctrl_chain(usbd_xfer_handle xfer) |
3628 | { | | 3628 | { |
3629 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 3629 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
3630 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; | | 3630 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; |
3631 | usb_endpoint_descriptor_t *ed = dpipe->pipe.endpoint->edesc; | | 3631 | usb_endpoint_descriptor_t *ed = dpipe->pipe.endpoint->edesc; |
3632 | usb_device_request_t *req = &xfer->request; | | 3632 | usb_device_request_t *req = &xfer->request; |
3633 | #ifdef DWC_OTG_DEBUG | | 3633 | #ifdef DWC_OTG_DEBUG |
3634 | usbd_device_handle dev = dpipe->pipe.device; | | 3634 | usbd_device_handle dev = dpipe->pipe.device; |
3635 | #endif | | 3635 | #endif |
3636 | uint8_t dir = req->bmRequestType & UT_READ; | | 3636 | uint8_t dir = req->bmRequestType & UT_READ; |
3637 | uint32_t len = UGETW(req->wLength); | | 3637 | uint32_t len = UGETW(req->wLength); |
3638 | struct dwc_otg_std_temp temp; /* XXX */ | | 3638 | struct dwc_otg_std_temp temp; /* XXX */ |
3639 | struct dwc_otg_td *td; | | 3639 | struct dwc_otg_td *td; |
3640 | int done; | | 3640 | int done; |
3641 | | | 3641 | |
3642 | DPRINTFN(3, "type=0x%02x, request=0x%02x, wValue=0x%04x," | | 3642 | DPRINTFN(3, "type=0x%02x, request=0x%02x, wValue=0x%04x," |
3643 | "wIndex=0x%04x len=%d, addr=%d, endpt=%d, dir=%s, speed=%d\n", | | 3643 | "wIndex=0x%04x len=%d, addr=%d, endpt=%d, dir=%s, speed=%d\n", |
3644 | req->bmRequestType, req->bRequest, UGETW(req->wValue), | | 3644 | req->bmRequestType, req->bRequest, UGETW(req->wValue), |
3645 | UGETW(req->wIndex), UGETW(req->wLength), dev->address, | | 3645 | UGETW(req->wIndex), UGETW(req->wLength), dev->address, |
3646 | UE_GET_ADDR(ed->bEndpointAddress), dir == UT_READ ? "in" :"out", | | 3646 | UE_GET_ADDR(ed->bEndpointAddress), dir == UT_READ ? "in" :"out", |
3647 | dev->speed); | | 3647 | dev->speed); |
3648 | | | 3648 | |
3649 | temp.max_frame_size = UGETW(ed->wMaxPacketSize); | | 3649 | temp.max_frame_size = UGETW(ed->wMaxPacketSize); |
3650 | | | 3650 | |
3651 | td = dxfer->td_start[0]; | | 3651 | td = dxfer->td_start[0]; |
3652 | dxfer->td_transfer_first = td; | | 3652 | dxfer->td_transfer_first = td; |
3653 | dxfer->td_transfer_cache = td; | | 3653 | dxfer->td_transfer_cache = td; |
3654 | | | 3654 | |
3655 | /* Setup stage */ | | 3655 | /* Setup stage */ |
3656 | temp.xfer = xfer; | | 3656 | temp.xfer = xfer; |
3657 | temp.buf = NULL; | | 3657 | temp.buf = NULL; |
3658 | temp.td = NULL; | | 3658 | temp.td = NULL; |
3659 | temp.td_next = td; | | 3659 | temp.td_next = td; |
3660 | temp.offset = 0; | | 3660 | temp.offset = 0; |
3661 | temp.setup_alt_next = 0/*(xfer->flags & USBD_SHORT_XFER_OK)*/; | | 3661 | temp.setup_alt_next = 0/*(xfer->flags & USBD_SHORT_XFER_OK)*/; |
3662 | temp.did_stall = 0; /* !xfer->flags_int.control_stall; */ | | 3662 | temp.did_stall = 0; /* !xfer->flags_int.control_stall; */ |
3663 | | | 3663 | |
3664 | temp.func = &dwc_otg_host_setup_tx; | | 3664 | temp.func = &dwc_otg_host_setup_tx; |
3665 | temp.len = sizeof(*req); | | 3665 | temp.len = sizeof(*req); |
3666 | temp.buf = req; | | 3666 | temp.buf = req; |
3667 | temp.short_pkt = 1; /* We're 8 bytes this is short for HS */ | | 3667 | temp.short_pkt = 1; /* We're 8 bytes this is short for HS */ |
3668 | temp.setup_alt_next = 0; /* XXXNH */ | | 3668 | temp.setup_alt_next = 0; /* XXXNH */ |
3669 | | | 3669 | |
3670 | DPRINTF("SE temp.len %d temp.pc %p\n", temp.len, temp.buf); | | 3670 | DPRINTF("SE temp.len %d temp.pc %p\n", temp.len, temp.buf); |
3671 | | | 3671 | |
3672 | dwc_otg_setup_standard_chain_sub(&temp); | | 3672 | dwc_otg_setup_standard_chain_sub(&temp); |
3673 | | | 3673 | |
3674 | done = 0; | | 3674 | done = 0; |
3675 | KASSERT((temp.buf == NULL) == (temp.len == 0)); | | 3675 | KASSERT((temp.buf == NULL) == (temp.len == 0)); |
3676 | if (dir == UT_READ) { | | 3676 | if (dir == UT_READ) { |
3677 | temp.func = &dwc_otg_host_data_rx; | | 3677 | temp.func = &dwc_otg_host_data_rx; |
3678 | } else { | | 3678 | } else { |
3679 | temp.func = &dwc_otg_host_data_tx; | | 3679 | temp.func = &dwc_otg_host_data_tx; |
3680 | } | | 3680 | } |
3681 | | | 3681 | |
3682 | /* Optional Data stage */ | | 3682 | /* Optional Data stage */ |
3683 | while (done != len) { | | 3683 | while (done != len) { |
3684 | | | 3684 | |
3685 | /* DATA0 / DATA1 message */ | | 3685 | /* DATA0 / DATA1 message */ |
3686 | | | 3686 | |
3687 | temp.buf = len ? KERNADDR(&xfer->dmabuf, done) : NULL; | | 3687 | temp.buf = len ? KERNADDR(&xfer->dmabuf, done) : NULL; |
3688 | temp.len = len - done; | | 3688 | temp.len = len - done; |
3689 | temp.short_pkt = ( (xfer->flags & USBD_FORCE_SHORT_XFER) ? 0 : 1); | | 3689 | temp.short_pkt = ( (xfer->flags & USBD_FORCE_SHORT_XFER) ? 0 : 1); |
3690 | | | 3690 | |
3691 | if (temp.len > UGETW(ed->wMaxPacketSize)) | | 3691 | if (temp.len > UGETW(ed->wMaxPacketSize)) |
3692 | temp.len = UGETW(ed->wMaxPacketSize); | | 3692 | temp.len = UGETW(ed->wMaxPacketSize); |
3693 | | | 3693 | |
3694 | dwc_otg_setup_standard_chain_sub(&temp); | | 3694 | dwc_otg_setup_standard_chain_sub(&temp); |
3695 | | | 3695 | |
3696 | done += temp.len; | | 3696 | done += temp.len; |
3697 | if (temp.len) | | 3697 | if (temp.len) |
3698 | temp.buf = (char *)KERNADDR(&xfer->dmabuf, 0) + done; | | 3698 | temp.buf = (char *)KERNADDR(&xfer->dmabuf, 0) + done; |
3699 | }; | | 3699 | } |
3700 | | | 3700 | |
3701 | /* Status Stage */ | | 3701 | /* Status Stage */ |
3702 | temp.buf = &req; /* XXXNH not needed */ | | 3702 | temp.buf = &req; /* XXXNH not needed */ |
3703 | temp.len = 0; | | 3703 | temp.len = 0; |
3704 | temp.short_pkt = 0; | | 3704 | temp.short_pkt = 0; |
3705 | temp.setup_alt_next = 0; | | 3705 | temp.setup_alt_next = 0; |
3706 | | | 3706 | |
3707 | /* | | 3707 | /* |
3708 | * Send a DATA1 message and invert the current endpoint direction. | | 3708 | * Send a DATA1 message and invert the current endpoint direction. |
3709 | */ | | 3709 | */ |
3710 | if (dir == UT_READ) { | | 3710 | if (dir == UT_READ) { |
3711 | temp.func = &dwc_otg_host_data_tx; | | 3711 | temp.func = &dwc_otg_host_data_tx; |
3712 | } else { | | 3712 | } else { |
3713 | temp.func = &dwc_otg_host_data_rx; | | 3713 | temp.func = &dwc_otg_host_data_rx; |
3714 | } | | 3714 | } |
3715 | | | 3715 | |
3716 | dwc_otg_setup_standard_chain_sub(&temp); | | 3716 | dwc_otg_setup_standard_chain_sub(&temp); |
3717 | | | 3717 | |
3718 | /* data toggle should be DATA1 */ | | 3718 | /* data toggle should be DATA1 */ |
3719 | td = temp.td; | | 3719 | td = temp.td; |
3720 | td->set_toggle = 1; | | 3720 | td->set_toggle = 1; |
3721 | | | 3721 | |
3722 | /* must have at least one frame! */ | | 3722 | /* must have at least one frame! */ |
3723 | td = temp.td; | | 3723 | td = temp.td; |
3724 | dxfer->td_transfer_last = td; | | 3724 | dxfer->td_transfer_last = td; |
3725 | | | 3725 | |
3726 | dwc_otg_setup_standard_chain(xfer); | | 3726 | dwc_otg_setup_standard_chain(xfer); |
3727 | } | | 3727 | } |
3728 | | | 3728 | |
3729 | Static void | | 3729 | Static void |
3730 | dwc_otg_setup_data_chain(usbd_xfer_handle xfer) | | 3730 | dwc_otg_setup_data_chain(usbd_xfer_handle xfer) |
3731 | { | | 3731 | { |
3732 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 3732 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
3733 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; | | 3733 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; |
3734 | usb_endpoint_descriptor_t *ed = dpipe->pipe.endpoint->edesc; | | 3734 | usb_endpoint_descriptor_t *ed = dpipe->pipe.endpoint->edesc; |
3735 | #ifdef DWC_OTG_DEBUG | | 3735 | #ifdef DWC_OTG_DEBUG |
3736 | usbd_device_handle dev = dpipe->pipe.device; | | 3736 | usbd_device_handle dev = dpipe->pipe.device; |
3737 | #endif | | 3737 | #endif |
3738 | uint8_t dir = UE_GET_DIR(ed->bEndpointAddress); | | 3738 | uint8_t dir = UE_GET_DIR(ed->bEndpointAddress); |
3739 | struct dwc_otg_std_temp temp; /* XXX */ | | 3739 | struct dwc_otg_std_temp temp; /* XXX */ |
3740 | struct dwc_otg_td *td; | | 3740 | struct dwc_otg_td *td; |
3741 | int off; | | 3741 | int off; |
3742 | int done; | | 3742 | int done; |
3743 | int len; | | 3743 | int len; |
3744 | | | 3744 | |
3745 | DPRINTFN(3, "xfer=%p, len=%d, flags=%d, addr=%d, endpt=%d, dir %s\n", | | 3745 | DPRINTFN(3, "xfer=%p, len=%d, flags=%d, addr=%d, endpt=%d, dir %s\n", |
3746 | xfer, xfer->length, xfer->flags, dev->address, | | 3746 | xfer, xfer->length, xfer->flags, dev->address, |
3747 | UE_GET_ADDR(ed->bEndpointAddress), dir == UT_READ ? "in" :"out"); | | 3747 | UE_GET_ADDR(ed->bEndpointAddress), dir == UT_READ ? "in" :"out"); |
3748 | | | 3748 | |
3749 | temp.max_frame_size = UGETW(ed->wMaxPacketSize); | | 3749 | temp.max_frame_size = UGETW(ed->wMaxPacketSize); |
3750 | | | 3750 | |
3751 | td = dxfer->td_start[0]; | | 3751 | td = dxfer->td_start[0]; |
3752 | dxfer->td_transfer_first = td; | | 3752 | dxfer->td_transfer_first = td; |
3753 | dxfer->td_transfer_cache = td; | | 3753 | dxfer->td_transfer_cache = td; |
3754 | | | 3754 | |
3755 | temp.xfer = xfer; | | 3755 | temp.xfer = xfer; |
3756 | temp.td = NULL; | | 3756 | temp.td = NULL; |
3757 | temp.td_next = td; | | 3757 | temp.td_next = td; |
3758 | temp.offset = 0; | | 3758 | temp.offset = 0; |
3759 | //temp.setup_alt_next = (xfer->flags & USBD_SHORT_XFER_OK) ? 1 : 0; | | 3759 | //temp.setup_alt_next = (xfer->flags & USBD_SHORT_XFER_OK) ? 1 : 0; |
3760 | temp.setup_alt_next = 0; | | 3760 | temp.setup_alt_next = 0; |
3761 | temp.did_stall = 0; /* !xfer->flags_int.control_stall; */ | | 3761 | temp.did_stall = 0; /* !xfer->flags_int.control_stall; */ |
3762 | temp.func = NULL; | | 3762 | temp.func = NULL; |
3763 | | | 3763 | |
3764 | done = 0; | | 3764 | done = 0; |
3765 | if (dir == UE_DIR_IN) { | | 3765 | if (dir == UE_DIR_IN) { |
3766 | temp.func = &dwc_otg_host_data_rx; | | 3766 | temp.func = &dwc_otg_host_data_rx; |
3767 | } else { | | 3767 | } else { |
3768 | temp.func = &dwc_otg_host_data_tx; | | 3768 | temp.func = &dwc_otg_host_data_tx; |
3769 | } | | 3769 | } |
3770 | | | 3770 | |
3771 | /* Data stage */ | | 3771 | /* Data stage */ |
3772 | off = 0; | | 3772 | off = 0; |
3773 | len = xfer->length; | | 3773 | len = xfer->length; |
3774 | while (len > 0) { | | 3774 | while (len > 0) { |
3775 | /* DATA0 / DATA1 message */ | | 3775 | /* DATA0 / DATA1 message */ |
3776 | temp.buf = KERNADDR(&xfer->dmabuf, off); | | 3776 | temp.buf = KERNADDR(&xfer->dmabuf, off); |
3777 | temp.len = MIN(len, UGETW(ed->wMaxPacketSize)); | | 3777 | temp.len = MIN(len, UGETW(ed->wMaxPacketSize)); |
3778 | temp.short_pkt = (xfer->flags & USBD_FORCE_SHORT_XFER) ? 0 : 1; | | 3778 | temp.short_pkt = (xfer->flags & USBD_FORCE_SHORT_XFER) ? 0 : 1; |
3779 | if (len <= UGETW(ed->wMaxPacketSize)) | | 3779 | if (len <= UGETW(ed->wMaxPacketSize)) |
3780 | temp.setup_alt_next = 0; | | 3780 | temp.setup_alt_next = 0; |
3781 | | | 3781 | |
3782 | dwc_otg_setup_standard_chain_sub(&temp); | | 3782 | dwc_otg_setup_standard_chain_sub(&temp); |
3783 | | | 3783 | |
3784 | len -= temp.len; | | 3784 | len -= temp.len; |
3785 | off += temp.len; | | 3785 | off += temp.len; |
3786 | }; | | 3786 | } |
3787 | | | 3787 | |
3788 | /* must have at least one frame! */ | | 3788 | /* must have at least one frame! */ |
3789 | td = temp.td; | | 3789 | td = temp.td; |
3790 | dxfer->td_transfer_last = td; | | 3790 | dxfer->td_transfer_last = td; |
3791 | | | 3791 | |
3792 | dwc_otg_setup_standard_chain(xfer); | | 3792 | dwc_otg_setup_standard_chain(xfer); |
3793 | } | | 3793 | } |
3794 | | | 3794 | |
3795 | Static void | | 3795 | Static void |
3796 | dwc_otg_setup_intr_chain(usbd_xfer_handle xfer) | | 3796 | dwc_otg_setup_intr_chain(usbd_xfer_handle xfer) |
3797 | { | | 3797 | { |
3798 | dwc_otg_setup_data_chain(xfer); | | 3798 | dwc_otg_setup_data_chain(xfer); |
3799 | } | | 3799 | } |
3800 | | | 3800 | |
3801 | Static void | | 3801 | Static void |
3802 | dwc_otg_setup_bulk_chain(usbd_xfer_handle xfer) | | 3802 | dwc_otg_setup_bulk_chain(usbd_xfer_handle xfer) |
3803 | { | | 3803 | { |
3804 | dwc_otg_setup_data_chain(xfer); | | 3804 | dwc_otg_setup_data_chain(xfer); |
3805 | } | | 3805 | } |
3806 | | | 3806 | |
3807 | #if 0 | | 3807 | #if 0 |
3808 | Static void | | 3808 | Static void |
3809 | dwc_otg_setup_isoc_chain(usbd_xfer_handle xfer) | | 3809 | dwc_otg_setup_isoc_chain(usbd_xfer_handle xfer) |
3810 | { | | 3810 | { |
3811 | } | | 3811 | } |
3812 | #endif | | 3812 | #endif |
3813 | | | 3813 | |
3814 | Static void | | 3814 | Static void |
3815 | dwc_otg_setup_standard_chain(usbd_xfer_handle xfer) | | 3815 | dwc_otg_setup_standard_chain(usbd_xfer_handle xfer) |
3816 | { | | 3816 | { |
3817 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 3817 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
3818 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; | | 3818 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; |
3819 | usb_endpoint_descriptor_t *ed = dpipe->pipe.endpoint->edesc; | | 3819 | usb_endpoint_descriptor_t *ed = dpipe->pipe.endpoint->edesc; |
3820 | usbd_device_handle dev = dpipe->pipe.device; | | 3820 | usbd_device_handle dev = dpipe->pipe.device; |
3821 | usb_device_request_t *req = &xfer->request; | | 3821 | usb_device_request_t *req = &xfer->request; |
3822 | struct dwc_otg_softc *sc = dev->bus->hci_private; | | 3822 | struct dwc_otg_softc *sc = dev->bus->hci_private; |
3823 | uint8_t addr = dev->address; | | 3823 | uint8_t addr = dev->address; |
3824 | uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes); | | 3824 | uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes); |
3825 | uint8_t epnum = UE_GET_ADDR(ed->bEndpointAddress); | | 3825 | uint8_t epnum = UE_GET_ADDR(ed->bEndpointAddress); |
3826 | struct dwc_otg_td *td; | | 3826 | struct dwc_otg_td *td; |
3827 | uint32_t hcchar; | | 3827 | uint32_t hcchar; |
3828 | uint32_t hcsplt; | | 3828 | uint32_t hcsplt; |
3829 | uint32_t ival; | | 3829 | uint32_t ival; |
3830 | | | 3830 | |
3831 | // DPRINTF(("%s: xfer->length %d\n", __func__, xfer->length)); | | 3831 | // DPRINTF(("%s: xfer->length %d\n", __func__, xfer->length)); |
3832 | | | 3832 | |
3833 | /* get first again */ | | 3833 | /* get first again */ |
3834 | td = dxfer->td_transfer_first; | | 3834 | td = dxfer->td_transfer_first; |
3835 | td->toggle = dpipe->pipe.endpoint->datatoggle; | | 3835 | td->toggle = dpipe->pipe.endpoint->datatoggle; |
3836 | | | 3836 | |
3837 | hcsplt = 0; | | 3837 | hcsplt = 0; |
3838 | hcchar = HCCHAR_CHENA | | | 3838 | hcchar = HCCHAR_CHENA | |
3839 | (addr << HCCHAR_DEVADDR_SHIFT) | | | 3839 | (addr << HCCHAR_DEVADDR_SHIFT) | |
3840 | (xfertype << HCCHAR_EPTYPE_SHIFT) | | | 3840 | (xfertype << HCCHAR_EPTYPE_SHIFT) | |
3841 | (epnum << HCCHAR_EPNUM_SHIFT) | | | 3841 | (epnum << HCCHAR_EPNUM_SHIFT) | |
3842 | ((UGETW(ed->wMaxPacketSize)) << HCCHAR_MPS_SHIFT); | | 3842 | ((UGETW(ed->wMaxPacketSize)) << HCCHAR_MPS_SHIFT); |
3843 | | | 3843 | |
3844 | switch (xfertype) { | | 3844 | switch (xfertype) { |
3845 | case UE_CONTROL: | | 3845 | case UE_CONTROL: |
3846 | if ((req->bmRequestType & UT_READ) == UT_READ) { | | 3846 | if ((req->bmRequestType & UT_READ) == UT_READ) { |
3847 | hcchar |= HCCHAR_EPDIR_IN; | | 3847 | hcchar |= HCCHAR_EPDIR_IN; |
3848 | } | | 3848 | } |
3849 | break; | | 3849 | break; |
3850 | | | 3850 | |
3851 | case UE_INTERRUPT: | | 3851 | case UE_INTERRUPT: |
3852 | case UE_BULK: | | 3852 | case UE_BULK: |
3853 | case UE_ISOCHRONOUS: | | 3853 | case UE_ISOCHRONOUS: |
3854 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) { | | 3854 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) { |
3855 | hcchar |= HCCHAR_EPDIR_IN; | | 3855 | hcchar |= HCCHAR_EPDIR_IN; |
3856 | } | | 3856 | } |
3857 | break; | | 3857 | break; |
3858 | default: | | 3858 | default: |
3859 | panic("Unknown transfer type"); | | 3859 | panic("Unknown transfer type"); |
3860 | } | | 3860 | } |
3861 | | | 3861 | |
3862 | switch (dev->speed) { | | 3862 | switch (dev->speed) { |
3863 | case USB_SPEED_LOW: | | 3863 | case USB_SPEED_LOW: |
3864 | DPRINTF("USB_SPEED_LOW\n"); | | 3864 | DPRINTF("USB_SPEED_LOW\n"); |
3865 | hcchar |= HCCHAR_LSPDDEV; | | 3865 | hcchar |= HCCHAR_LSPDDEV; |
3866 | /* FALLTHROUGH */ | | 3866 | /* FALLTHROUGH */ |
3867 | case USB_SPEED_FULL: | | 3867 | case USB_SPEED_FULL: |
3868 | DPRINTF("USB_SPEED_FULL\n"); | | 3868 | DPRINTF("USB_SPEED_FULL\n"); |
3869 | /* check if root HUB port is running High Speed */ | | 3869 | /* check if root HUB port is running High Speed */ |
3870 | if (sc->sc_flags.status_high_speed != 0) { | | 3870 | if (sc->sc_flags.status_high_speed != 0) { |
3871 | hcsplt = HCSPLT_SPLTENA | | | 3871 | hcsplt = HCSPLT_SPLTENA | |
3872 | (dev->myhsport->portno << HCSPLT_PRTADDR_SHIFT) | | | 3872 | (dev->myhsport->portno << HCSPLT_PRTADDR_SHIFT) | |
3873 | (dev->myhsport->parent->address << HCSPLT_HUBADDR_SHIFT); | | 3873 | (dev->myhsport->parent->address << HCSPLT_HUBADDR_SHIFT); |
3874 | if (xfertype == UE_ISOCHRONOUS) /* XXX */ | | 3874 | if (xfertype == UE_ISOCHRONOUS) /* XXX */ |
3875 | hcsplt |= (3 << HCSPLT_XACTPOS_SHIFT); | | 3875 | hcsplt |= (3 << HCSPLT_XACTPOS_SHIFT); |
3876 | } | | 3876 | } |
3877 | break; | | 3877 | break; |
3878 | | | 3878 | |
3879 | case USB_SPEED_HIGH: | | 3879 | case USB_SPEED_HIGH: |
3880 | DPRINTF("USB_SPEED_HIGH\n"); | | 3880 | DPRINTF("USB_SPEED_HIGH\n"); |
3881 | if (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT) { | | 3881 | if (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT) { |
3882 | hcchar |= (/*(xfer->max_packet_count & 3)*/ 1 | | 3882 | hcchar |= (/*(xfer->max_packet_count & 3)*/ 1 |
3883 | << HCCHAR_MC_SHIFT); | | 3883 | << HCCHAR_MC_SHIFT); |
3884 | } | | 3884 | } |
3885 | break; | | 3885 | break; |
3886 | | | 3886 | |
3887 | default: | | 3887 | default: |
3888 | break; | | 3888 | break; |
3889 | } | | 3889 | } |
3890 | | | 3890 | |
3891 | int fps_shift = 1; | | 3891 | int fps_shift = 1; |
3892 | | | 3892 | |
3893 | switch (xfertype) { | | 3893 | switch (xfertype) { |
3894 | case UE_ISOCHRONOUS: | | 3894 | case UE_ISOCHRONOUS: |
3895 | // td->tmr_val = xfer->endpoint->isoc_next & 0xFF; | | 3895 | // td->tmr_val = xfer->endpoint->isoc_next & 0xFF; |
3896 | | | 3896 | |
3897 | ival = 1 << fps_shift; | | 3897 | ival = 1 << fps_shift; |
3898 | break; | | 3898 | break; |
3899 | case UE_INTERRUPT: | | 3899 | case UE_INTERRUPT: |
3900 | ival = dpipe->pipe.interval / DWC_OTG_HOST_TIMER_RATE; | | 3900 | ival = dpipe->pipe.interval / DWC_OTG_HOST_TIMER_RATE; |
3901 | if (ival == 0) | | 3901 | if (ival == 0) |
3902 | ival = 1; | | 3902 | ival = 1; |
3903 | else if (ival > 127) | | 3903 | else if (ival > 127) |
3904 | ival = 127; | | 3904 | ival = 127; |
3905 | td->tmr_val = sc->sc_tmr_val + ival; | | 3905 | td->tmr_val = sc->sc_tmr_val + ival; |
3906 | td->tmr_res = ival; | | 3906 | td->tmr_res = ival; |
3907 | break; | | 3907 | break; |
3908 | default: | | 3908 | default: |
3909 | td->tmr_val = 0; | | 3909 | td->tmr_val = 0; |
3910 | td->tmr_res = 0; | | 3910 | td->tmr_res = 0; |
3911 | ival = 0; | | 3911 | ival = 0; |
3912 | } | | 3912 | } |
3913 | | | 3913 | |
3914 | DPRINTF("hcchar 0x%08x hcchar 0x%08x ival %d\n", hcchar, hcsplt, ival); | | 3914 | DPRINTF("hcchar 0x%08x hcchar 0x%08x ival %d\n", hcchar, hcsplt, ival); |
3915 | | | 3915 | |
3916 | /* store configuration in all TD's */ | | 3916 | /* store configuration in all TD's */ |
3917 | while (1) { | | 3917 | while (1) { |
3918 | td->hcchar = hcchar; | | 3918 | td->hcchar = hcchar; |
3919 | td->hcsplt = hcsplt; | | 3919 | td->hcsplt = hcsplt; |
3920 | | | 3920 | |
3921 | if (td == dxfer->td_transfer_last) | | 3921 | if (td == dxfer->td_transfer_last) |
3922 | break; | | 3922 | break; |
3923 | | | 3923 | |
3924 | td = td->obj_next; | | 3924 | td = td->obj_next; |
3925 | } | | 3925 | } |
3926 | } | | 3926 | } |
3927 | | | 3927 | |
3928 | Static void | | 3928 | Static void |
3929 | dwc_otg_start_standard_chain(usbd_xfer_handle xfer) | | 3929 | dwc_otg_start_standard_chain(usbd_xfer_handle xfer) |
3930 | { | | 3930 | { |
3931 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 3931 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
3932 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; | | 3932 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; |
3933 | usbd_device_handle dev = dpipe->pipe.device; | | 3933 | usbd_device_handle dev = dpipe->pipe.device; |
3934 | struct dwc_otg_softc *sc = dev->bus->hci_private; | | 3934 | struct dwc_otg_softc *sc = dev->bus->hci_private; |
3935 | | | 3935 | |
3936 | DPRINTFN(9, "\n"); | | 3936 | DPRINTFN(9, "\n"); |
3937 | | | 3937 | |
3938 | /* poll one time - will turn on interrupts */ | | 3938 | /* poll one time - will turn on interrupts */ |
3939 | mutex_spin_enter(&sc->sc_intr_lock); | | 3939 | mutex_spin_enter(&sc->sc_intr_lock); |
3940 | if (dwc_otg_xfer_do_fifo(xfer)) { | | 3940 | if (dwc_otg_xfer_do_fifo(xfer)) { |
3941 | | | 3941 | |
3942 | KASSERT(mutex_owned(&sc->sc_lock)); | | 3942 | KASSERT(mutex_owned(&sc->sc_lock)); |
3943 | /* put transfer on interrupt queue */ | | 3943 | /* put transfer on interrupt queue */ |
3944 | | | 3944 | |
3945 | if (!dxfer->queued) { | | 3945 | if (!dxfer->queued) { |
3946 | dxfer->queued = true; | | 3946 | dxfer->queued = true; |
3947 | TAILQ_INSERT_TAIL(&sc->sc_active, dxfer, xnext); | | 3947 | TAILQ_INSERT_TAIL(&sc->sc_active, dxfer, xnext); |
3948 | } else { | | 3948 | } else { |
3949 | printf("%s: xfer %p already queued\n", __func__, | | 3949 | printf("%s: xfer %p already queued\n", __func__, |
3950 | xfer); | | 3950 | xfer); |
3951 | } | | 3951 | } |
3952 | | | 3952 | |
3953 | /* start timeout, if any */ | | 3953 | /* start timeout, if any */ |
3954 | if (xfer->timeout != 0) { | | 3954 | if (xfer->timeout != 0) { |
3955 | callout_reset(&xfer->timeout_handle, | | 3955 | callout_reset(&xfer->timeout_handle, |
3956 | mstohz(xfer->timeout), dwc_otg_timeout, xfer); | | 3956 | mstohz(xfer->timeout), dwc_otg_timeout, xfer); |
3957 | } | | 3957 | } |
3958 | } | | 3958 | } |
3959 | mutex_spin_exit(&sc->sc_intr_lock); | | 3959 | mutex_spin_exit(&sc->sc_intr_lock); |
3960 | | | 3960 | |
3961 | DPRINTFN(9, "done\n"); | | 3961 | DPRINTFN(9, "done\n"); |
3962 | } | | 3962 | } |
3963 | | | 3963 | |
3964 | Static void | | 3964 | Static void |
3965 | dwc_otg_rhc(void *addr) | | 3965 | dwc_otg_rhc(void *addr) |
3966 | { | | 3966 | { |
3967 | struct dwc_otg_softc *sc = addr; | | 3967 | struct dwc_otg_softc *sc = addr; |
3968 | usbd_xfer_handle xfer; | | 3968 | usbd_xfer_handle xfer; |
3969 | usbd_pipe_handle pipe; | | 3969 | usbd_pipe_handle pipe; |
3970 | u_char *p; | | 3970 | u_char *p; |
3971 | | | 3971 | |
3972 | DPRINTF("\n"); | | 3972 | DPRINTF("\n"); |
3973 | mutex_enter(&sc->sc_lock); | | 3973 | mutex_enter(&sc->sc_lock); |
3974 | xfer = sc->sc_intrxfer; | | 3974 | xfer = sc->sc_intrxfer; |
3975 | | | 3975 | |
3976 | if (xfer == NULL) { | | 3976 | if (xfer == NULL) { |
3977 | /* Just ignore the change. */ | | 3977 | /* Just ignore the change. */ |
3978 | mutex_exit(&sc->sc_lock); | | 3978 | mutex_exit(&sc->sc_lock); |
3979 | return; | | 3979 | return; |
3980 | | | 3980 | |
3981 | } | | 3981 | } |
3982 | /* set port bit */ | | 3982 | /* set port bit */ |
3983 | pipe = xfer->pipe; | | 3983 | pipe = xfer->pipe; |
3984 | | | 3984 | |
3985 | p = KERNADDR(&xfer->dmabuf, 0); | | 3985 | p = KERNADDR(&xfer->dmabuf, 0); |
3986 | | | 3986 | |
3987 | p[0] = 0x02; /* we only have one port (1 << 1) */ | | 3987 | p[0] = 0x02; /* we only have one port (1 << 1) */ |
3988 | | | 3988 | |
3989 | xfer->actlen = xfer->length; | | 3989 | xfer->actlen = xfer->length; |
3990 | xfer->status = USBD_NORMAL_COMPLETION; | | 3990 | xfer->status = USBD_NORMAL_COMPLETION; |
3991 | | | 3991 | |
3992 | usb_transfer_complete(xfer); | | 3992 | usb_transfer_complete(xfer); |
3993 | mutex_exit(&sc->sc_lock); | | 3993 | mutex_exit(&sc->sc_lock); |
3994 | | | 3994 | |
3995 | } | | 3995 | } |
3996 | | | 3996 | |
3997 | Static usbd_status | | 3997 | Static usbd_status |
3998 | dwc_otg_standard_done_sub(usbd_xfer_handle xfer) | | 3998 | dwc_otg_standard_done_sub(usbd_xfer_handle xfer) |
3999 | { | | 3999 | { |
4000 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 4000 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
4001 | usbd_pipe_handle pipe = xfer->pipe; | | 4001 | usbd_pipe_handle pipe = xfer->pipe; |
4002 | struct dwc_otg_td *td; | | 4002 | struct dwc_otg_td *td; |
4003 | uint32_t len; | | 4003 | uint32_t len; |
4004 | usbd_status error; | | 4004 | usbd_status error; |
4005 | | | 4005 | |
4006 | DPRINTFN(9, "td %p\n", dxfer->td_transfer_cache); | | 4006 | DPRINTFN(9, "td %p\n", dxfer->td_transfer_cache); |
4007 | | | 4007 | |
4008 | td = dxfer->td_transfer_cache; | | 4008 | td = dxfer->td_transfer_cache; |
4009 | | | 4009 | |
4010 | do { | | 4010 | do { |
4011 | xfer->actlen += td->actlen; | | 4011 | xfer->actlen += td->actlen; |
4012 | | | 4012 | |
4013 | len = td->remainder; | | 4013 | len = td->remainder; |
4014 | | | 4014 | |
4015 | /* store last data toggle */ | | 4015 | /* store last data toggle */ |
4016 | pipe->endpoint->datatoggle = td->toggle; | | 4016 | pipe->endpoint->datatoggle = td->toggle; |
4017 | | | 4017 | |
4018 | /* Check for transfer error */ | | 4018 | /* Check for transfer error */ |
4019 | if (td->error_any) { | | 4019 | if (td->error_any) { |
4020 | /* the transfer is finished */ | | 4020 | /* the transfer is finished */ |
4021 | error = (td->error_stall ? USBD_STALLED : USBD_IOERROR); | | 4021 | error = (td->error_stall ? USBD_STALLED : USBD_IOERROR); |
4022 | td = NULL; | | 4022 | td = NULL; |
4023 | break; | | 4023 | break; |
4024 | } | | 4024 | } |
4025 | /* Check for short transfer */ | | 4025 | /* Check for short transfer */ |
4026 | if (len > 0) { | | 4026 | if (len > 0) { |
4027 | //if (xfer->flags & USBD_SHORT_XFER_OK) { | | 4027 | //if (xfer->flags & USBD_SHORT_XFER_OK) { |
4028 | if (0) { | | 4028 | if (0) { |
4029 | /* follow alt next */ | | 4029 | /* follow alt next */ |
4030 | if (td->alt_next) { | | 4030 | if (td->alt_next) { |
4031 | td = td->obj_next; | | 4031 | td = td->obj_next; |
4032 | } else { | | 4032 | } else { |
4033 | td = NULL; | | 4033 | td = NULL; |
4034 | } | | 4034 | } |
4035 | } else { | | 4035 | } else { |
4036 | /* the transfer is finished */ | | 4036 | /* the transfer is finished */ |
4037 | td = NULL; | | 4037 | td = NULL; |
4038 | } | | 4038 | } |
4039 | error = 0; | | 4039 | error = 0; |
4040 | break; | | 4040 | break; |
4041 | } | | 4041 | } |
4042 | | | 4042 | |
4043 | td = td->obj_next; | | 4043 | td = td->obj_next; |
4044 | | | 4044 | |
4045 | /* this USB frame is complete */ | | 4045 | /* this USB frame is complete */ |
4046 | error = 0; | | 4046 | error = 0; |
4047 | break; | | 4047 | break; |
4048 | | | 4048 | |
4049 | } while (0); | | 4049 | } while (0); |
4050 | | | 4050 | |
4051 | /* update transfer cache */ | | 4051 | /* update transfer cache */ |
4052 | | | 4052 | |
4053 | dxfer->td_transfer_cache = td; | | 4053 | dxfer->td_transfer_cache = td; |
4054 | | | 4054 | |
4055 | return error; | | 4055 | return error; |
4056 | } | | 4056 | } |
4057 | | | 4057 | |
4058 | Static void | | 4058 | Static void |
4059 | dwc_otg_standard_done(usbd_xfer_handle xfer) | | 4059 | dwc_otg_standard_done(usbd_xfer_handle xfer) |
4060 | { | | 4060 | { |
4061 | struct dwc_otg_xfer *dxfer = DWC_OTG_XFER2DXFER(xfer); | | 4061 | struct dwc_otg_xfer *dxfer = DWC_OTG_XFER2DXFER(xfer); |
4062 | | | 4062 | |
4063 | struct dwc_otg_td *td; | | 4063 | struct dwc_otg_td *td; |
4064 | usbd_status err = 0; | | 4064 | usbd_status err = 0; |
4065 | | | 4065 | |
4066 | DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", | | 4066 | DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", |
4067 | xfer, xfer->pipe->endpoint); | | 4067 | xfer, xfer->pipe->endpoint); |
4068 | | | 4068 | |
4069 | /* reset scanner */ | | 4069 | /* reset scanner */ |
4070 | | | 4070 | |
4071 | dxfer->td_transfer_cache = dxfer->td_transfer_first; | | 4071 | dxfer->td_transfer_cache = dxfer->td_transfer_first; |
4072 | td = dxfer->td_transfer_first; | | 4072 | td = dxfer->td_transfer_first; |
4073 | | | 4073 | |
4074 | while (td != NULL) { | | 4074 | while (td != NULL) { |
4075 | err = dwc_otg_standard_done_sub(xfer); | | 4075 | err = dwc_otg_standard_done_sub(xfer); |
4076 | if (dxfer->td_transfer_cache == NULL) { | | 4076 | if (dxfer->td_transfer_cache == NULL) { |
4077 | goto done; | | 4077 | goto done; |
4078 | } | | 4078 | } |
4079 | if (td == dxfer->td_transfer_last) | | 4079 | if (td == dxfer->td_transfer_last) |
4080 | break; | | 4080 | break; |
4081 | td = td->obj_next; | | 4081 | td = td->obj_next; |
4082 | }; | | 4082 | } |
4083 | done: | | 4083 | done: |
4084 | dwc_otg_device_done(xfer, err); | | 4084 | dwc_otg_device_done(xfer, err); |
4085 | } | | 4085 | } |
4086 | | | 4086 | |
4087 | | | 4087 | |
4088 | /*------------------------------------------------------------------------* | | 4088 | /*------------------------------------------------------------------------* |
4089 | * dwc_otg_device_done | | 4089 | * dwc_otg_device_done |
4090 | * | | 4090 | * |
4091 | * NOTE: this function can be called more than one time on the | | 4091 | * NOTE: this function can be called more than one time on the |
4092 | * same USB transfer! | | 4092 | * same USB transfer! |
4093 | *------------------------------------------------------------------------*/ | | 4093 | *------------------------------------------------------------------------*/ |
4094 | Static void | | 4094 | Static void |
4095 | dwc_otg_device_done(usbd_xfer_handle xfer, usbd_status error) | | 4095 | dwc_otg_device_done(usbd_xfer_handle xfer, usbd_status error) |
4096 | { | | 4096 | { |
4097 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 4097 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
4098 | struct dwc_otg_softc *sc = DWC_OTG_XFER2SC(xfer); | | 4098 | struct dwc_otg_softc *sc = DWC_OTG_XFER2SC(xfer); |
4099 | | | 4099 | |
4100 | DPRINTFN(9, "xfer=%p, endpoint=%p, error=%d\n", | | 4100 | DPRINTFN(9, "xfer=%p, endpoint=%p, error=%d\n", |
4101 | xfer, xfer->pipe->endpoint, error); | | 4101 | xfer, xfer->pipe->endpoint, error); |
4102 | struct dwc_otg_td *td; | | 4102 | struct dwc_otg_td *td; |
4103 | | | 4103 | |
4104 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | | 4104 | KASSERT(mutex_owned(&sc->sc_intr_lock)); |
4105 | td = dxfer->td_transfer_first; | | 4105 | td = dxfer->td_transfer_first; |
4106 | | | 4106 | |
4107 | if (td != NULL) | | 4107 | if (td != NULL) |
4108 | dwc_otg_host_channel_free(td); | | 4108 | dwc_otg_host_channel_free(td); |
4109 | | | 4109 | |
4110 | xfer->status = error; | | 4110 | xfer->status = error; |
4111 | TAILQ_REMOVE(&sc->sc_active, dxfer, xnext); | | 4111 | TAILQ_REMOVE(&sc->sc_active, dxfer, xnext); |
4112 | | | 4112 | |
4113 | callout_stop(&xfer->timeout_handle); | | 4113 | callout_stop(&xfer->timeout_handle); |
4114 | | | 4114 | |
4115 | dxfer->queued = false; | | 4115 | dxfer->queued = false; |
4116 | TAILQ_INSERT_TAIL(&sc->sc_complete, dxfer, xnext); | | 4116 | TAILQ_INSERT_TAIL(&sc->sc_complete, dxfer, xnext); |
4117 | | | 4117 | |
4118 | usb_schedsoftintr(&sc->sc_bus); | | 4118 | usb_schedsoftintr(&sc->sc_bus); |
4119 | } | | 4119 | } |
4120 | | | 4120 | |
4121 | /* | | 4121 | /* |
4122 | * curmode is a mode indication bit 0 = device, 1 = host | | 4122 | * curmode is a mode indication bit 0 = device, 1 = host |
4123 | */ | | 4123 | */ |
4124 | static const char * const intnames[32] = { | | 4124 | static const char * const intnames[32] = { |
4125 | "curmode", "modemis", "otgint", "sof", | | 4125 | "curmode", "modemis", "otgint", "sof", |
4126 | "rxflvl", "nptxfemp", "ginnakeff", "goutnakeff", | | 4126 | "rxflvl", "nptxfemp", "ginnakeff", "goutnakeff", |
4127 | "ulpickint", "i2cint", "erlysusp", "usbsusp", | | 4127 | "ulpickint", "i2cint", "erlysusp", "usbsusp", |
4128 | "usbrst", "enumdone", "isooutdrop", "eopf", | | 4128 | "usbrst", "enumdone", "isooutdrop", "eopf", |
4129 | "restore_done", "epmis", "iepint", "oepint", | | 4129 | "restore_done", "epmis", "iepint", "oepint", |
4130 | "incompisoin", "incomplp", "fetsusp", "resetdet", | | 4130 | "incompisoin", "incomplp", "fetsusp", "resetdet", |
4131 | "prtint", "hchint", "ptxfemp", "lpm", | | 4131 | "prtint", "hchint", "ptxfemp", "lpm", |
4132 | "conidstschng", "disconnint", "sessreqint", "wkupint" | | 4132 | "conidstschng", "disconnint", "sessreqint", "wkupint" |
4133 | }; | | 4133 | }; |
4134 | | | 4134 | |
4135 | | | 4135 | |
4136 | usbd_status | | 4136 | usbd_status |
4137 | dwc_otg_init(struct dwc_otg_softc *sc) | | 4137 | dwc_otg_init(struct dwc_otg_softc *sc) |
4138 | { | | 4138 | { |
4139 | const char * const xname = device_xname(sc->sc_dev); | | 4139 | const char * const xname = device_xname(sc->sc_dev); |
4140 | uint32_t temp; | | 4140 | uint32_t temp; |
4141 | | | 4141 | |
4142 | sc->sc_bus.hci_private = sc; | | 4142 | sc->sc_bus.hci_private = sc; |
4143 | sc->sc_bus.usbrev = USBREV_2_0; | | 4143 | sc->sc_bus.usbrev = USBREV_2_0; |
4144 | sc->sc_bus.methods = &dwc_otg_bus_methods; | | 4144 | sc->sc_bus.methods = &dwc_otg_bus_methods; |
4145 | sc->sc_bus.pipe_size = sizeof(struct dwc_otg_pipe); | | 4145 | sc->sc_bus.pipe_size = sizeof(struct dwc_otg_pipe); |
4146 | | | 4146 | |
4147 | sc->sc_noport = 1; | | 4147 | sc->sc_noport = 1; |
4148 | | | 4148 | |
4149 | callout_init(&sc->sc_timer, CALLOUT_MPSAFE); | | 4149 | callout_init(&sc->sc_timer, CALLOUT_MPSAFE); |
4150 | | | 4150 | |
4151 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | | 4151 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); |
4152 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); | | 4152 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); |
4153 | | | 4153 | |
4154 | TAILQ_INIT(&sc->sc_active); | | 4154 | TAILQ_INIT(&sc->sc_active); |
4155 | TAILQ_INIT(&sc->sc_complete); | | 4155 | TAILQ_INIT(&sc->sc_complete); |
4156 | | | 4156 | |
4157 | sc->sc_tdpool = pool_cache_init(sizeof(struct dwc_otg_td), 0, 0, 0, | | 4157 | sc->sc_tdpool = pool_cache_init(sizeof(struct dwc_otg_td), 0, 0, 0, |
4158 | "dotgtd", NULL, IPL_USB, NULL, NULL, NULL); | | 4158 | "dotgtd", NULL, IPL_USB, NULL, NULL, NULL); |
4159 | sc->sc_xferpool = pool_cache_init(sizeof(struct dwc_otg_xfer), 0, 0, 0, | | 4159 | sc->sc_xferpool = pool_cache_init(sizeof(struct dwc_otg_xfer), 0, 0, 0, |
4160 | "dotgxfer", NULL, IPL_USB, NULL, NULL, NULL); | | 4160 | "dotgxfer", NULL, IPL_USB, NULL, NULL, NULL); |
4161 | | | 4161 | |
4162 | sc->sc_rhc_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | | 4162 | sc->sc_rhc_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, |
4163 | dwc_otg_rhc, sc); | | 4163 | dwc_otg_rhc, sc); |
4164 | | | 4164 | |
4165 | workqueue_create(&sc->sc_wq, xname, dwc_otg_worker, sc, PRI_NONE, | | 4165 | workqueue_create(&sc->sc_wq, xname, dwc_otg_worker, sc, PRI_NONE, |
4166 | IPL_USB, WQ_MPSAFE); | | 4166 | IPL_USB, WQ_MPSAFE); |
4167 | sc->sc_timer_work.sc = sc; | | 4167 | sc->sc_timer_work.sc = sc; |
4168 | | | 4168 | |
4169 | usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag, | | 4169 | usb_setup_reserve(sc->sc_dev, &sc->sc_dma_reserve, sc->sc_bus.dmatag, |
4170 | USB_MEM_RESERVE); | | 4170 | USB_MEM_RESERVE); |
4171 | | | 4171 | |
4172 | #ifdef DOTG_COUNTERS | | 4172 | #ifdef DOTG_COUNTERS |
4173 | evcnt_attach_dynamic(&sc->sc_ev_intr, EVCNT_TYPE_INTR, | | 4173 | evcnt_attach_dynamic(&sc->sc_ev_intr, EVCNT_TYPE_INTR, |
4174 | NULL, xname, "intr"); | | 4174 | NULL, xname, "intr"); |
4175 | evcnt_attach_dynamic(&sc->sc_ev_soft_intr, EVCNT_TYPE_INTR, | | 4175 | evcnt_attach_dynamic(&sc->sc_ev_soft_intr, EVCNT_TYPE_INTR, |
4176 | NULL, xname, "soft intr"); | | 4176 | NULL, xname, "soft intr"); |
4177 | evcnt_attach_dynamic(&sc->sc_ev_work, EVCNT_TYPE_MISC, | | 4177 | evcnt_attach_dynamic(&sc->sc_ev_work, EVCNT_TYPE_MISC, |
4178 | NULL, xname, "work items"); | | 4178 | NULL, xname, "work items"); |
4179 | | | 4179 | |
4180 | evcnt_attach_dynamic(&sc->sc_ev_tdpoolget, EVCNT_TYPE_MISC, | | 4180 | evcnt_attach_dynamic(&sc->sc_ev_tdpoolget, EVCNT_TYPE_MISC, |
4181 | NULL, xname, "td pool get"); | | 4181 | NULL, xname, "td pool get"); |
4182 | evcnt_attach_dynamic(&sc->sc_ev_tdpoolput, EVCNT_TYPE_MISC, | | 4182 | evcnt_attach_dynamic(&sc->sc_ev_tdpoolput, EVCNT_TYPE_MISC, |
4183 | NULL, xname, "td pool put"); | | 4183 | NULL, xname, "td pool put"); |
4184 | | | 4184 | |
4185 | evcnt_attach_dynamic(&sc->sc_ev_xferpoolget, EVCNT_TYPE_MISC, | | 4185 | evcnt_attach_dynamic(&sc->sc_ev_xferpoolget, EVCNT_TYPE_MISC, |
4186 | NULL, xname, "xfer pool get"); | | 4186 | NULL, xname, "xfer pool get"); |
4187 | evcnt_attach_dynamic(&sc->sc_ev_xferpoolput, EVCNT_TYPE_MISC, | | 4187 | evcnt_attach_dynamic(&sc->sc_ev_xferpoolput, EVCNT_TYPE_MISC, |
4188 | NULL, xname, "xfer pool put"); | | 4188 | NULL, xname, "xfer pool put"); |
4189 | | | 4189 | |
4190 | for (size_t i = DWC_OTG_INTRBITF; i < DWC_OTG_NINTRBITS; i++) { | | 4190 | for (size_t i = DWC_OTG_INTRBITF; i < DWC_OTG_NINTRBITS; i++) { |
4191 | evcnt_attach_dynamic(&sc->sc_ev_intr_bit[i], EVCNT_TYPE_INTR, | | 4191 | evcnt_attach_dynamic(&sc->sc_ev_intr_bit[i], EVCNT_TYPE_INTR, |
4192 | NULL, xname, intnames[i]); | | 4192 | NULL, xname, intnames[i]); |
4193 | } | | 4193 | } |
4194 | | | 4194 | |
4195 | #endif | | 4195 | #endif |
4196 | | | 4196 | |
4197 | temp = DWC_OTG_READ_4(sc, DOTG_GUSBCFG); | | 4197 | temp = DWC_OTG_READ_4(sc, DOTG_GUSBCFG); |
4198 | temp |= GUSBCFG_FORCEHOSTMODE; | | 4198 | temp |= GUSBCFG_FORCEHOSTMODE; |
4199 | temp &= ~GUSBCFG_TERMSELDLPULSE; | | 4199 | temp &= ~GUSBCFG_TERMSELDLPULSE; |
4200 | temp &= ~GUSBCFG_USBTRDTIM_MASK; | | 4200 | temp &= ~GUSBCFG_USBTRDTIM_MASK; |
4201 | temp |= GUSBCFG_TRD_TIM_SET(9); | | 4201 | temp |= GUSBCFG_TRD_TIM_SET(9); |
4202 | temp |= GUSBCFG_HNPCAP | GUSBCFG_SRPCAP; | | 4202 | temp |= GUSBCFG_HNPCAP | GUSBCFG_SRPCAP; |
4203 | | | 4203 | |
4204 | DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG, temp); | | 4204 | DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG, temp); |
4205 | delay(100000); | | 4205 | delay(100000); |
4206 | | | 4206 | |
4207 | temp = DWC_OTG_READ_4(sc, DOTG_GUSBCFG); | | 4207 | temp = DWC_OTG_READ_4(sc, DOTG_GUSBCFG); |
4208 | temp &= ~GUSBCFG_FORCEHOSTMODE; | | 4208 | temp &= ~GUSBCFG_FORCEHOSTMODE; |
4209 | DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG, temp); | | 4209 | DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG, temp); |
4210 | delay(100000); | | 4210 | delay(100000); |
4211 | | | 4211 | |
4212 | temp = DWC_OTG_READ_4(sc, DOTG_GSNPSID); | | 4212 | temp = DWC_OTG_READ_4(sc, DOTG_GSNPSID); |
4213 | DPRINTF("Version = 0x%08x\n", temp); | | 4213 | DPRINTF("Version = 0x%08x\n", temp); |
4214 | switch (temp & 0xfffff000) { | | 4214 | switch (temp & 0xfffff000) { |
4215 | case 0x4f542000: | | 4215 | case 0x4f542000: |
4216 | case 0x4f543000: | | 4216 | case 0x4f543000: |
4217 | break; | | 4217 | break; |
4218 | default: | | 4218 | default: |
4219 | printf("oops\n"); | | 4219 | printf("oops\n"); |
4220 | return 1; | | 4220 | return 1; |
4221 | } | | 4221 | } |
4222 | | | 4222 | |
4223 | temp = DWC_OTG_READ_4(sc, DOTG_GAHBCFG); | | 4223 | temp = DWC_OTG_READ_4(sc, DOTG_GAHBCFG); |
4224 | temp &= ~GAHBCFG_GLBLINTRMSK; | | 4224 | temp &= ~GAHBCFG_GLBLINTRMSK; |
4225 | DWC_OTG_WRITE_4(sc, DOTG_GAHBCFG, temp); | | 4225 | DWC_OTG_WRITE_4(sc, DOTG_GAHBCFG, temp); |
4226 | | | 4226 | |
4227 | temp = DWC_OTG_READ_4(sc, DOTG_GUSBCFG); | | 4227 | temp = DWC_OTG_READ_4(sc, DOTG_GUSBCFG); |
4228 | temp &= ~GUSBCFG_ULPIEXTVBUSDRV; | | 4228 | temp &= ~GUSBCFG_ULPIEXTVBUSDRV; |
4229 | temp &= ~GUSBCFG_TERMSELDLPULSE; | | 4229 | temp &= ~GUSBCFG_TERMSELDLPULSE; |
4230 | | | 4230 | |
4231 | DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG, temp); | | 4231 | DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG, temp); |
4232 | | | 4232 | |
4233 | dwc_otg_core_reset(sc); | | 4233 | dwc_otg_core_reset(sc); |
4234 | | | 4234 | |
4235 | /* --------------------------------*/ | | 4235 | /* --------------------------------*/ |
4236 | | | 4236 | |
4237 | DWC_OTG_WRITE_4(sc, DOTG_PCGCCTL, 0); | | 4237 | DWC_OTG_WRITE_4(sc, DOTG_PCGCCTL, 0); |
4238 | | | 4238 | |
4239 | temp = 0; | | 4239 | temp = 0; |
4240 | // temp = DWC_OTG_READ_4(sc, DOTG_HCFG); | | 4240 | // temp = DWC_OTG_READ_4(sc, DOTG_HCFG); |
4241 | temp &= ~HCFG_FSLSPCLKSEL_MASK; | | 4241 | temp &= ~HCFG_FSLSPCLKSEL_MASK; |
4242 | temp |= 1; /* 30 or 60 Mhz */ | | 4242 | temp |= 1; /* 30 or 60 Mhz */ |
4243 | | | 4243 | |
4244 | DWC_OTG_WRITE_4(sc, DOTG_HCFG, temp); | | 4244 | DWC_OTG_WRITE_4(sc, DOTG_HCFG, temp); |
4245 | | | 4245 | |
4246 | /* enable PORT reset */ | | 4246 | /* enable PORT reset */ |
4247 | temp = DWC_OTG_READ_4(sc, DOTG_HPRT); | | 4247 | temp = DWC_OTG_READ_4(sc, DOTG_HPRT); |
4248 | temp |= HPRT_PRTRST; | | 4248 | temp |= HPRT_PRTRST; |
4249 | DWC_OTG_WRITE_4(sc, DOTG_HPRT, temp); | | 4249 | DWC_OTG_WRITE_4(sc, DOTG_HPRT, temp); |
4250 | | | 4250 | |
4251 | delay(1000); | | 4251 | delay(1000); |
4252 | temp &= ~HPRT_PRTRST; | | 4252 | temp &= ~HPRT_PRTRST; |
4253 | DWC_OTG_WRITE_4(sc, DOTG_HPRT, temp); | | 4253 | DWC_OTG_WRITE_4(sc, DOTG_HPRT, temp); |
4254 | delay(1000); | | 4254 | delay(1000); |
4255 | | | 4255 | |
4256 | temp = DWC_OTG_READ_4(sc, DOTG_HPRT); | | 4256 | temp = DWC_OTG_READ_4(sc, DOTG_HPRT); |
4257 | | | 4257 | |
4258 | usb_delay_ms(&sc->sc_bus, 8); | | 4258 | usb_delay_ms(&sc->sc_bus, 8); |
4259 | | | 4259 | |
4260 | sc->sc_mode = DWC_MODE_HOST; | | 4260 | sc->sc_mode = DWC_MODE_HOST; |
4261 | | | 4261 | |
4262 | switch (sc->sc_mode) { | | 4262 | switch (sc->sc_mode) { |
4263 | case DWC_MODE_DEVICE: | | 4263 | case DWC_MODE_DEVICE: |
4264 | temp = GUSBCFG_FORCEDEVMODE; | | 4264 | temp = GUSBCFG_FORCEDEVMODE; |
4265 | break; | | 4265 | break; |
4266 | case DWC_MODE_HOST: | | 4266 | case DWC_MODE_HOST: |
4267 | temp = GUSBCFG_FORCEHOSTMODE; | | 4267 | temp = GUSBCFG_FORCEHOSTMODE; |
4268 | break; | | 4268 | break; |
4269 | default: | | 4269 | default: |
4270 | temp = 0; | | 4270 | temp = 0; |
4271 | break; | | 4271 | break; |
4272 | } | | 4272 | } |
4273 | | | 4273 | |
4274 | /* flag based? */ | | 4274 | /* flag based? */ |
4275 | #ifdef DWC_OTG_USE_HSIC | | 4275 | #ifdef DWC_OTG_USE_HSIC |
4276 | DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG, | | 4276 | DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG, |
4277 | GUSBCFG_PHYIF | | | 4277 | GUSBCFG_PHYIF | |
4278 | GUSBCFG_TRD_TIM_SET(5) | temp); | | 4278 | GUSBCFG_TRD_TIM_SET(5) | temp); |
4279 | DWC_OTG_WRITE_4(sc, DOTG_GOTGCTL, 0x000000ec); | | 4279 | DWC_OTG_WRITE_4(sc, DOTG_GOTGCTL, 0x000000ec); |
4280 | | | 4280 | |
4281 | temp = DWC_OTG_READ_4(sc, DOTG_GLPMCFG); | | 4281 | temp = DWC_OTG_READ_4(sc, DOTG_GLPMCFG); |
4282 | DWC_OTG_WRITE_4(sc, DOTG_GLPMCFG, temp & ~GLPMCFG_HSIC_CONN); | | 4282 | DWC_OTG_WRITE_4(sc, DOTG_GLPMCFG, temp & ~GLPMCFG_HSIC_CONN); |
4283 | DWC_OTG_WRITE_4(sc, DOTG_GLPMCFG, temp | GLPMCFG_HSIC_CONN); | | 4283 | DWC_OTG_WRITE_4(sc, DOTG_GLPMCFG, temp | GLPMCFG_HSIC_CONN); |
4284 | #else | | 4284 | #else |
4285 | DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG, | | 4285 | DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG, |
4286 | GUSBCFG_ULPI_UTMI_SEL | | | 4286 | GUSBCFG_ULPI_UTMI_SEL | |
4287 | GUSBCFG_TRD_TIM_SET(5) | temp); | | 4287 | GUSBCFG_TRD_TIM_SET(5) | temp); |
4288 | DWC_OTG_WRITE_4(sc, DOTG_GOTGCTL, 0); | | 4288 | DWC_OTG_WRITE_4(sc, DOTG_GOTGCTL, 0); |
4289 | | | 4289 | |
4290 | temp = DWC_OTG_READ_4(sc, DOTG_GLPMCFG); | | 4290 | temp = DWC_OTG_READ_4(sc, DOTG_GLPMCFG); |
4291 | DWC_OTG_WRITE_4(sc, DOTG_GLPMCFG, temp & ~GLPMCFG_HSIC_CONN); | | 4291 | DWC_OTG_WRITE_4(sc, DOTG_GLPMCFG, temp & ~GLPMCFG_HSIC_CONN); |
4292 | #endif | | 4292 | #endif |
4293 | | | 4293 | |
4294 | /* clear global nak */ | | 4294 | /* clear global nak */ |
4295 | DWC_OTG_WRITE_4(sc, DOTG_DCTL, DCTL_CGOUTNAK | DCTL_CGNPINNAK); | | 4295 | DWC_OTG_WRITE_4(sc, DOTG_DCTL, DCTL_CGOUTNAK | DCTL_CGNPINNAK); |
4296 | | | 4296 | |
4297 | /* disable USB port */ | | 4297 | /* disable USB port */ |
4298 | DWC_OTG_WRITE_4(sc, DOTG_PCGCCTL, 0xffffffff); | | 4298 | DWC_OTG_WRITE_4(sc, DOTG_PCGCCTL, 0xffffffff); |
4299 | usb_delay_ms(&sc->sc_bus, 10); | | 4299 | usb_delay_ms(&sc->sc_bus, 10); |
4300 | | | 4300 | |
4301 | /* enable USB port */ | | 4301 | /* enable USB port */ |
4302 | DWC_OTG_WRITE_4(sc, DOTG_PCGCCTL, 0); | | 4302 | DWC_OTG_WRITE_4(sc, DOTG_PCGCCTL, 0); |
4303 | | | 4303 | |
4304 | /* wait 10ms */ | | 4304 | /* wait 10ms */ |
4305 | usb_delay_ms(&sc->sc_bus, 10); | | 4305 | usb_delay_ms(&sc->sc_bus, 10); |
4306 | | | 4306 | |
4307 | /* pull up D+ */ | | 4307 | /* pull up D+ */ |
4308 | dwc_otg_pull_up(sc); | | 4308 | dwc_otg_pull_up(sc); |
4309 | | | 4309 | |
4310 | temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG3); | | 4310 | temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG3); |
4311 | | | 4311 | |
4312 | sc->sc_fifo_size = 4 * GHWCFG3_DFIFODEPTH_GET(temp); | | 4312 | sc->sc_fifo_size = 4 * GHWCFG3_DFIFODEPTH_GET(temp); |
4313 | | | 4313 | |
4314 | temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG2); | | 4314 | temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG2); |
4315 | | | 4315 | |
4316 | sc->sc_dev_ep_max = min(GHWCFG2_NUMDEVEPS_GET(temp),DWC_OTG_MAX_ENDPOINTS); | | 4316 | sc->sc_dev_ep_max = min(GHWCFG2_NUMDEVEPS_GET(temp),DWC_OTG_MAX_ENDPOINTS); |
4317 | sc->sc_host_ch_max = min(GHWCFG2_NUMHSTCHNL_GET(temp),DWC_OTG_MAX_CHANNELS); | | 4317 | sc->sc_host_ch_max = min(GHWCFG2_NUMHSTCHNL_GET(temp),DWC_OTG_MAX_CHANNELS); |
4318 | | | 4318 | |
4319 | temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG4); | | 4319 | temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG4); |
4320 | sc->sc_dev_in_ep_max = GHWCFG4_NUM_IN_EP_GET(temp); | | 4320 | sc->sc_dev_in_ep_max = GHWCFG4_NUM_IN_EP_GET(temp); |
4321 | | | 4321 | |
4322 | DPRINTF("Total FIFO size = %d bytes, Device EPs = %d/%d Host CHs = %d\n", | | 4322 | DPRINTF("Total FIFO size = %d bytes, Device EPs = %d/%d Host CHs = %d\n", |
4323 | sc->sc_fifo_size, sc->sc_dev_ep_max, sc->sc_dev_in_ep_max, | | 4323 | sc->sc_fifo_size, sc->sc_dev_ep_max, sc->sc_dev_in_ep_max, |
4324 | sc->sc_host_ch_max); | | 4324 | sc->sc_host_ch_max); |
4325 | | | 4325 | |
4326 | /* setup fifo */ | | 4326 | /* setup fifo */ |
4327 | if (dwc_otg_init_fifo(sc, DWC_MODE_OTG)) | | 4327 | if (dwc_otg_init_fifo(sc, DWC_MODE_OTG)) |
4328 | return EINVAL; | | 4328 | return EINVAL; |
4329 | | | 4329 | |
4330 | DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, 0); | | 4330 | DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, 0); |
4331 | | | 4331 | |
4332 | DWC_OTG_WRITE_4(sc, DOTG_GOTGINT, 0xffffffff); | | 4332 | DWC_OTG_WRITE_4(sc, DOTG_GOTGINT, 0xffffffff); |
4333 | DWC_OTG_WRITE_4(sc, DOTG_GINTSTS, 0xffffffff); | | 4333 | DWC_OTG_WRITE_4(sc, DOTG_GINTSTS, 0xffffffff); |
4334 | | | 4334 | |
4335 | /* enable interrupts */ | | 4335 | /* enable interrupts */ |
4336 | sc->sc_irq_mask = DWC_OTG_MSK_GINT_ENABLED; | | 4336 | sc->sc_irq_mask = DWC_OTG_MSK_GINT_ENABLED; |
4337 | DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); | | 4337 | DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); |
4338 | | | 4338 | |
4339 | if (sc->sc_mode == DWC_MODE_OTG || sc->sc_mode == DWC_MODE_DEVICE) { | | 4339 | if (sc->sc_mode == DWC_MODE_OTG || sc->sc_mode == DWC_MODE_DEVICE) { |
4340 | | | 4340 | |
4341 | /* enable all endpoint interrupts */ | | 4341 | /* enable all endpoint interrupts */ |
4342 | temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG2); | | 4342 | temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG2); |
4343 | if (temp & GHWCFG2_MPI) { | | 4343 | if (temp & GHWCFG2_MPI) { |
4344 | uint8_t x; | | 4344 | uint8_t x; |
4345 | | | 4345 | |
4346 | DPRINTF("Multi Process Interrupts\n"); | | 4346 | DPRINTF("Multi Process Interrupts\n"); |
4347 | | | 4347 | |
4348 | for (x = 0; x != sc->sc_dev_in_ep_max; x++) { | | 4348 | for (x = 0; x != sc->sc_dev_in_ep_max; x++) { |
4349 | DWC_OTG_WRITE_4(sc, DOTG_DIEPEACHINTMSK(x), | | 4349 | DWC_OTG_WRITE_4(sc, DOTG_DIEPEACHINTMSK(x), |
4350 | DIEPMSK_XFERCOMPLMSK); | | 4350 | DIEPMSK_XFERCOMPLMSK); |
4351 | DWC_OTG_WRITE_4(sc, DOTG_DOEPEACHINTMSK(x), 0); | | 4351 | DWC_OTG_WRITE_4(sc, DOTG_DOEPEACHINTMSK(x), 0); |
4352 | } | | 4352 | } |
4353 | DWC_OTG_WRITE_4(sc, DOTG_DEACHINTMSK, 0xFFFF); | | 4353 | DWC_OTG_WRITE_4(sc, DOTG_DEACHINTMSK, 0xFFFF); |
4354 | } else { | | 4354 | } else { |
4355 | DWC_OTG_WRITE_4(sc, DOTG_DIEPMSK, | | 4355 | DWC_OTG_WRITE_4(sc, DOTG_DIEPMSK, |
4356 | DIEPMSK_XFERCOMPLMSK); | | 4356 | DIEPMSK_XFERCOMPLMSK); |
4357 | DWC_OTG_WRITE_4(sc, DOTG_DOEPMSK, 0); | | 4357 | DWC_OTG_WRITE_4(sc, DOTG_DOEPMSK, 0); |
4358 | DWC_OTG_WRITE_4(sc, DOTG_DAINTMSK, 0xFFFF); | | 4358 | DWC_OTG_WRITE_4(sc, DOTG_DAINTMSK, 0xFFFF); |
4359 | } | | 4359 | } |
4360 | } | | 4360 | } |
4361 | | | 4361 | |
4362 | if (sc->sc_mode == DWC_MODE_OTG || sc->sc_mode == DWC_MODE_HOST) { | | 4362 | if (sc->sc_mode == DWC_MODE_OTG || sc->sc_mode == DWC_MODE_HOST) { |
4363 | /* setup clocks */ | | 4363 | /* setup clocks */ |
4364 | temp = DWC_OTG_READ_4(sc, DOTG_HCFG); | | 4364 | temp = DWC_OTG_READ_4(sc, DOTG_HCFG); |
4365 | temp &= ~(HCFG_FSLSSUPP | HCFG_FSLSPCLKSEL_MASK); | | 4365 | temp &= ~(HCFG_FSLSSUPP | HCFG_FSLSPCLKSEL_MASK); |
4366 | temp |= (1 << HCFG_FSLSPCLKSEL_SHIFT); | | 4366 | temp |= (1 << HCFG_FSLSPCLKSEL_SHIFT); |
4367 | DWC_OTG_WRITE_4(sc, DOTG_HCFG, temp); | | 4367 | DWC_OTG_WRITE_4(sc, DOTG_HCFG, temp); |
4368 | } | | 4368 | } |
4369 | | | 4369 | |
4370 | /* only enable global IRQ */ | | 4370 | /* only enable global IRQ */ |
4371 | DWC_OTG_WRITE_4(sc, DOTG_GAHBCFG, GAHBCFG_GLBLINTRMSK); | | 4371 | DWC_OTG_WRITE_4(sc, DOTG_GAHBCFG, GAHBCFG_GLBLINTRMSK); |
4372 | | | 4372 | |
4373 | /* turn off clocks */ | | 4373 | /* turn off clocks */ |
4374 | dwc_otg_clocks_off(sc); | | 4374 | dwc_otg_clocks_off(sc); |
4375 | | | 4375 | |
4376 | /* read initial VBUS state */ | | 4376 | /* read initial VBUS state */ |
4377 | | | 4377 | |
4378 | temp = DWC_OTG_READ_4(sc, DOTG_GOTGCTL); | | 4378 | temp = DWC_OTG_READ_4(sc, DOTG_GOTGCTL); |
4379 | | | 4379 | |
4380 | DPRINTFN(5, "GOTGCTL=0x%08x\n", temp); | | 4380 | DPRINTFN(5, "GOTGCTL=0x%08x\n", temp); |
4381 | | | 4381 | |
4382 | dwc_otg_vbus_interrupt(sc); | | 4382 | dwc_otg_vbus_interrupt(sc); |
4383 | | | 4383 | |
4384 | mutex_enter(&sc->sc_lock); | | 4384 | mutex_enter(&sc->sc_lock); |
4385 | /* catch any lost interrupts */ | | 4385 | /* catch any lost interrupts */ |
4386 | dwc_otg_do_poll(&sc->sc_bus); | | 4386 | dwc_otg_do_poll(&sc->sc_bus); |
4387 | mutex_exit(&sc->sc_lock); | | 4387 | mutex_exit(&sc->sc_lock); |
4388 | | | 4388 | |
4389 | return 0; | | 4389 | return 0; |
4390 | } | | 4390 | } |
4391 | | | 4391 | |
4392 | /***********************************************************************/ | | 4392 | /***********************************************************************/ |
4393 | | | 4393 | |
4394 | Static void | | 4394 | Static void |
4395 | dwc_otg_xfer_setup(usbd_xfer_handle xfer) | | 4395 | dwc_otg_xfer_setup(usbd_xfer_handle xfer) |
4396 | { | | 4396 | { |
4397 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 4397 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
4398 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; | | 4398 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; |
4399 | struct dwc_otg_softc *sc = dpipe->pipe.device->bus->hci_private; | | 4399 | struct dwc_otg_softc *sc = dpipe->pipe.device->bus->hci_private; |
4400 | usb_endpoint_descriptor_t *ed = dpipe->pipe.endpoint->edesc; | | 4400 | usb_endpoint_descriptor_t *ed = dpipe->pipe.endpoint->edesc; |
4401 | uint16_t mps = UGETW(ed->wMaxPacketSize); | | 4401 | uint16_t mps = UGETW(ed->wMaxPacketSize); |
4402 | uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes); | | 4402 | uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes); |
4403 | uint8_t ep_no = UE_GET_ADDR(ed->bEndpointAddress); | | 4403 | uint8_t ep_no = UE_GET_ADDR(ed->bEndpointAddress); |
4404 | void *last_obj; | | 4404 | void *last_obj; |
4405 | int ntd, n; | | 4405 | int ntd, n; |
4406 | | | 4406 | |
4407 | dxfer->work.sc = sc; | | 4407 | dxfer->work.sc = sc; |
4408 | dxfer->work.xfer = xfer; | | 4408 | dxfer->work.xfer = xfer; |
4409 | | | 4409 | |
4410 | /* | | 4410 | /* |
4411 | * compute maximum number of TDs | | 4411 | * compute maximum number of TDs |
4412 | */ | | 4412 | */ |
4413 | if (xfertype == UE_CONTROL) { | | 4413 | if (xfertype == UE_CONTROL) { |
4414 | ntd = howmany(xfer->length, mps) + 1 /* STATUS */ + 1 /* SYNC 1 */ | | 4414 | ntd = howmany(xfer->length, mps) + 1 /* STATUS */ + 1 /* SYNC 1 */ |
4415 | + 1 /* SYNC 2 */ + 1 /* SYNC 3 */; | | 4415 | + 1 /* SYNC 2 */ + 1 /* SYNC 3 */; |
4416 | } else { | | 4416 | } else { |
4417 | ntd = howmany(xfer->length, mps) + 1 /* SYNC */ ; | | 4417 | ntd = howmany(xfer->length, mps) + 1 /* SYNC */ ; |
4418 | } | | 4418 | } |
4419 | | | 4419 | |
4420 | /* | | 4420 | /* |
4421 | * allocate transfer descriptors | | 4421 | * allocate transfer descriptors |
4422 | */ | | 4422 | */ |
4423 | last_obj = NULL; | | 4423 | last_obj = NULL; |
4424 | for (n = 0; n != ntd; n++) { | | 4424 | for (n = 0; n != ntd; n++) { |
4425 | struct dwc_otg_td *td; | | 4425 | struct dwc_otg_td *td; |
4426 | | | 4426 | |
4427 | DOTG_EVCNT_INCR(sc->sc_ev_tdpoolget); | | 4427 | DOTG_EVCNT_INCR(sc->sc_ev_tdpoolget); |
4428 | | | 4428 | |
4429 | td = pool_cache_get(sc->sc_tdpool, PR_NOWAIT); | | 4429 | td = pool_cache_get(sc->sc_tdpool, PR_NOWAIT); |
4430 | if (td == NULL) { | | 4430 | if (td == NULL) { |
4431 | printf("%s: pool empty\n", __func__); | | 4431 | printf("%s: pool empty\n", __func__); |
4432 | goto done; | | 4432 | goto done; |
4433 | } | | 4433 | } |
4434 | | | 4434 | |
4435 | /* init TD */ | | 4435 | /* init TD */ |
4436 | memset(td, 0, sizeof(*td)); | | 4436 | memset(td, 0, sizeof(*td)); |
4437 | td->max_packet_size = UGETW(ed->wMaxPacketSize); | | 4437 | td->max_packet_size = UGETW(ed->wMaxPacketSize); |
4438 | td->ep_no = ep_no; | | 4438 | td->ep_no = ep_no; |
4439 | td->obj_next = last_obj; | | 4439 | td->obj_next = last_obj; |
4440 | td->channel = DWC_OTG_MAX_CHANNELS; | | 4440 | td->channel = DWC_OTG_MAX_CHANNELS; |
4441 | | | 4441 | |
4442 | last_obj = td; | | 4442 | last_obj = td; |
4443 | } | | 4443 | } |
4444 | | | 4444 | |
4445 | done: | | 4445 | done: |
4446 | dxfer->td_start[0] = last_obj; | | 4446 | dxfer->td_start[0] = last_obj; |
4447 | } | | 4447 | } |
4448 | | | 4448 | |
4449 | Static void | | 4449 | Static void |
4450 | dwc_otg_xfer_start(usbd_xfer_handle xfer) | | 4450 | dwc_otg_xfer_start(usbd_xfer_handle xfer) |
4451 | { | | 4451 | { |
4452 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 4452 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
4453 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; | | 4453 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; |
4454 | struct dwc_otg_softc *sc = dpipe->pipe.device->bus->hci_private; | | 4454 | struct dwc_otg_softc *sc = dpipe->pipe.device->bus->hci_private; |
4455 | | | 4455 | |
4456 | KASSERT(mutex_owned(&sc->sc_lock)); | | 4456 | KASSERT(mutex_owned(&sc->sc_lock)); |
4457 | | | 4457 | |
4458 | if (sc->sc_bus.use_polling) { | | 4458 | if (sc->sc_bus.use_polling) { |
4459 | dwc_otg_start_standard_chain(xfer); | | 4459 | dwc_otg_start_standard_chain(xfer); |
4460 | } else { | | 4460 | } else { |
4461 | workqueue_enqueue(sc->sc_wq, | | 4461 | workqueue_enqueue(sc->sc_wq, |
4462 | (struct work *)&dxfer->work, NULL); | | 4462 | (struct work *)&dxfer->work, NULL); |
4463 | } | | 4463 | } |
4464 | } | | 4464 | } |
4465 | | | 4465 | |
4466 | Static void | | 4466 | Static void |
4467 | dwc_otg_xfer_end(usbd_xfer_handle xfer) | | 4467 | dwc_otg_xfer_end(usbd_xfer_handle xfer) |
4468 | { | | 4468 | { |
4469 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; | | 4469 | struct dwc_otg_xfer *dxfer = (struct dwc_otg_xfer *)xfer; |
4470 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; | | 4470 | struct dwc_otg_pipe *dpipe = (struct dwc_otg_pipe *)xfer->pipe; |
4471 | struct dwc_otg_softc *sc = dpipe->pipe.device->bus->hci_private; | | 4471 | struct dwc_otg_softc *sc = dpipe->pipe.device->bus->hci_private; |
4472 | struct dwc_otg_td *td, *td_next; | | 4472 | struct dwc_otg_td *td, *td_next; |
4473 | | | 4473 | |
4474 | DPRINTF("\n"); | | 4474 | DPRINTF("\n"); |
4475 | | | 4475 | |
4476 | for (td = dxfer->td_start[0]; td; ) { | | 4476 | for (td = dxfer->td_start[0]; td; ) { |
4477 | td_next = td->obj_next; | | 4477 | td_next = td->obj_next; |
4478 | DOTG_EVCNT_INCR(sc->sc_ev_tdpoolput); | | 4478 | DOTG_EVCNT_INCR(sc->sc_ev_tdpoolput); |
4479 | | | 4479 | |
4480 | pool_cache_put(sc->sc_tdpool, td); | | 4480 | pool_cache_put(sc->sc_tdpool, td); |
4481 | td = td_next; | | 4481 | td = td_next; |
4482 | } | | 4482 | } |
4483 | } | | 4483 | } |