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