1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /* $FreeBSD$ */ |
---|
4 | /*- |
---|
5 | * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. |
---|
6 | * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. |
---|
7 | * Copyright (c) 1998 Lennart Augustsson. All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions |
---|
11 | * are met: |
---|
12 | * 1. Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer. |
---|
14 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
15 | * notice, this list of conditions and the following disclaimer in the |
---|
16 | * documentation and/or other materials provided with the distribution. |
---|
17 | * |
---|
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
---|
19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
---|
22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
28 | * SUCH DAMAGE. |
---|
29 | */ |
---|
30 | |
---|
31 | /* |
---|
32 | * USB Open Host Controller driver. |
---|
33 | * |
---|
34 | * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html |
---|
35 | * USB spec: http://www.usb.org/developers/docs/usbspec.zip |
---|
36 | */ |
---|
37 | |
---|
38 | #ifdef USB_GLOBAL_INCLUDE_FILE |
---|
39 | #include USB_GLOBAL_INCLUDE_FILE |
---|
40 | #else |
---|
41 | #include <sys/stdint.h> |
---|
42 | #include <sys/stddef.h> |
---|
43 | #include <rtems/bsd/sys/param.h> |
---|
44 | #include <sys/queue.h> |
---|
45 | #include <sys/types.h> |
---|
46 | #include <sys/systm.h> |
---|
47 | #include <sys/kernel.h> |
---|
48 | #include <sys/bus.h> |
---|
49 | #include <sys/module.h> |
---|
50 | #include <rtems/bsd/sys/lock.h> |
---|
51 | #include <sys/mutex.h> |
---|
52 | #include <sys/condvar.h> |
---|
53 | #include <sys/sysctl.h> |
---|
54 | #include <sys/sx.h> |
---|
55 | #include <rtems/bsd/sys/unistd.h> |
---|
56 | #include <sys/callout.h> |
---|
57 | #include <sys/malloc.h> |
---|
58 | #include <sys/priv.h> |
---|
59 | |
---|
60 | #include <dev/usb/usb.h> |
---|
61 | #include <dev/usb/usbdi.h> |
---|
62 | |
---|
63 | #define USB_DEBUG_VAR ohcidebug |
---|
64 | |
---|
65 | #include <dev/usb/usb_core.h> |
---|
66 | #include <dev/usb/usb_debug.h> |
---|
67 | #include <dev/usb/usb_busdma.h> |
---|
68 | #include <dev/usb/usb_process.h> |
---|
69 | #include <dev/usb/usb_transfer.h> |
---|
70 | #include <dev/usb/usb_device.h> |
---|
71 | #include <dev/usb/usb_hub.h> |
---|
72 | #include <dev/usb/usb_util.h> |
---|
73 | |
---|
74 | #include <dev/usb/usb_controller.h> |
---|
75 | #include <dev/usb/usb_bus.h> |
---|
76 | #endif /* USB_GLOBAL_INCLUDE_FILE */ |
---|
77 | |
---|
78 | #include <dev/usb/controller/ohci.h> |
---|
79 | #include <dev/usb/controller/ohcireg.h> |
---|
80 | |
---|
81 | #define OHCI_BUS2SC(bus) \ |
---|
82 | ((ohci_softc_t *)(((uint8_t *)(bus)) - \ |
---|
83 | ((uint8_t *)&(((ohci_softc_t *)0)->sc_bus)))) |
---|
84 | |
---|
85 | #ifdef USB_DEBUG |
---|
86 | static int ohcidebug = 0; |
---|
87 | |
---|
88 | static SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci"); |
---|
89 | SYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RWTUN, |
---|
90 | &ohcidebug, 0, "ohci debug level"); |
---|
91 | |
---|
92 | static void ohci_dumpregs(ohci_softc_t *); |
---|
93 | static void ohci_dump_tds(ohci_td_t *); |
---|
94 | static uint8_t ohci_dump_td(ohci_td_t *); |
---|
95 | static void ohci_dump_ed(ohci_ed_t *); |
---|
96 | static uint8_t ohci_dump_itd(ohci_itd_t *); |
---|
97 | static void ohci_dump_itds(ohci_itd_t *); |
---|
98 | |
---|
99 | #endif |
---|
100 | |
---|
101 | #define OBARR(sc) bus_space_barrier((sc)->sc_io_tag, (sc)->sc_io_hdl, 0, (sc)->sc_io_size, \ |
---|
102 | BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) |
---|
103 | #define OWRITE1(sc, r, x) \ |
---|
104 | do { OBARR(sc); bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) |
---|
105 | #define OWRITE2(sc, r, x) \ |
---|
106 | do { OBARR(sc); bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) |
---|
107 | #define OWRITE4(sc, r, x) \ |
---|
108 | do { OBARR(sc); bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) |
---|
109 | #define OREAD1(sc, r) (OBARR(sc), bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) |
---|
110 | #define OREAD2(sc, r) (OBARR(sc), bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) |
---|
111 | #define OREAD4(sc, r) (OBARR(sc), bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) |
---|
112 | |
---|
113 | #define OHCI_INTR_ENDPT 1 |
---|
114 | |
---|
115 | static const struct usb_bus_methods ohci_bus_methods; |
---|
116 | static const struct usb_pipe_methods ohci_device_bulk_methods; |
---|
117 | static const struct usb_pipe_methods ohci_device_ctrl_methods; |
---|
118 | static const struct usb_pipe_methods ohci_device_intr_methods; |
---|
119 | static const struct usb_pipe_methods ohci_device_isoc_methods; |
---|
120 | |
---|
121 | static void ohci_do_poll(struct usb_bus *bus); |
---|
122 | static void ohci_device_done(struct usb_xfer *xfer, usb_error_t error); |
---|
123 | static void ohci_timeout(void *arg); |
---|
124 | static uint8_t ohci_check_transfer(struct usb_xfer *xfer); |
---|
125 | static void ohci_root_intr(ohci_softc_t *sc); |
---|
126 | |
---|
127 | struct ohci_std_temp { |
---|
128 | struct usb_page_cache *pc; |
---|
129 | ohci_td_t *td; |
---|
130 | ohci_td_t *td_next; |
---|
131 | uint32_t average; |
---|
132 | uint32_t td_flags; |
---|
133 | uint32_t len; |
---|
134 | uint16_t max_frame_size; |
---|
135 | uint8_t shortpkt; |
---|
136 | uint8_t setup_alt_next; |
---|
137 | uint8_t last_frame; |
---|
138 | }; |
---|
139 | |
---|
140 | static struct ohci_hcca * |
---|
141 | ohci_get_hcca(ohci_softc_t *sc) |
---|
142 | { |
---|
143 | usb_pc_cpu_invalidate(&sc->sc_hw.hcca_pc); |
---|
144 | return (sc->sc_hcca_p); |
---|
145 | } |
---|
146 | |
---|
147 | void |
---|
148 | ohci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) |
---|
149 | { |
---|
150 | struct ohci_softc *sc = OHCI_BUS2SC(bus); |
---|
151 | uint32_t i; |
---|
152 | |
---|
153 | cb(bus, &sc->sc_hw.hcca_pc, &sc->sc_hw.hcca_pg, |
---|
154 | sizeof(ohci_hcca_t), OHCI_HCCA_ALIGN); |
---|
155 | |
---|
156 | cb(bus, &sc->sc_hw.ctrl_start_pc, &sc->sc_hw.ctrl_start_pg, |
---|
157 | sizeof(ohci_ed_t), OHCI_ED_ALIGN); |
---|
158 | |
---|
159 | cb(bus, &sc->sc_hw.bulk_start_pc, &sc->sc_hw.bulk_start_pg, |
---|
160 | sizeof(ohci_ed_t), OHCI_ED_ALIGN); |
---|
161 | |
---|
162 | cb(bus, &sc->sc_hw.isoc_start_pc, &sc->sc_hw.isoc_start_pg, |
---|
163 | sizeof(ohci_ed_t), OHCI_ED_ALIGN); |
---|
164 | |
---|
165 | for (i = 0; i != OHCI_NO_EDS; i++) { |
---|
166 | cb(bus, sc->sc_hw.intr_start_pc + i, sc->sc_hw.intr_start_pg + i, |
---|
167 | sizeof(ohci_ed_t), OHCI_ED_ALIGN); |
---|
168 | } |
---|
169 | } |
---|
170 | |
---|
171 | static usb_error_t |
---|
172 | ohci_controller_init(ohci_softc_t *sc, int do_suspend) |
---|
173 | { |
---|
174 | struct usb_page_search buf_res; |
---|
175 | uint32_t i; |
---|
176 | uint32_t ctl; |
---|
177 | uint32_t ival; |
---|
178 | uint32_t hcr; |
---|
179 | uint32_t fm; |
---|
180 | uint32_t per; |
---|
181 | uint32_t desca; |
---|
182 | |
---|
183 | /* Determine in what context we are running. */ |
---|
184 | ctl = OREAD4(sc, OHCI_CONTROL); |
---|
185 | if (ctl & OHCI_IR) { |
---|
186 | /* SMM active, request change */ |
---|
187 | DPRINTF("SMM active, request owner change\n"); |
---|
188 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_OCR); |
---|
189 | for (i = 0; (i < 100) && (ctl & OHCI_IR); i++) { |
---|
190 | usb_pause_mtx(NULL, hz / 1000); |
---|
191 | ctl = OREAD4(sc, OHCI_CONTROL); |
---|
192 | } |
---|
193 | if (ctl & OHCI_IR) { |
---|
194 | device_printf(sc->sc_bus.bdev, |
---|
195 | "SMM does not respond, resetting\n"); |
---|
196 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); |
---|
197 | goto reset; |
---|
198 | } |
---|
199 | } else { |
---|
200 | DPRINTF("cold started\n"); |
---|
201 | reset: |
---|
202 | /* controller was cold started */ |
---|
203 | usb_pause_mtx(NULL, |
---|
204 | USB_MS_TO_TICKS(USB_BUS_RESET_DELAY)); |
---|
205 | } |
---|
206 | |
---|
207 | /* |
---|
208 | * This reset should not be necessary according to the OHCI spec, but |
---|
209 | * without it some controllers do not start. |
---|
210 | */ |
---|
211 | DPRINTF("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev)); |
---|
212 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); |
---|
213 | |
---|
214 | usb_pause_mtx(NULL, |
---|
215 | USB_MS_TO_TICKS(USB_BUS_RESET_DELAY)); |
---|
216 | |
---|
217 | /* we now own the host controller and the bus has been reset */ |
---|
218 | ival = OHCI_GET_IVAL(OREAD4(sc, OHCI_FM_INTERVAL)); |
---|
219 | |
---|
220 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ |
---|
221 | /* nominal time for a reset is 10 us */ |
---|
222 | for (i = 0; i < 10; i++) { |
---|
223 | DELAY(10); |
---|
224 | hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; |
---|
225 | if (!hcr) { |
---|
226 | break; |
---|
227 | } |
---|
228 | } |
---|
229 | if (hcr) { |
---|
230 | device_printf(sc->sc_bus.bdev, "reset timeout\n"); |
---|
231 | return (USB_ERR_IOERROR); |
---|
232 | } |
---|
233 | #ifdef USB_DEBUG |
---|
234 | if (ohcidebug > 15) { |
---|
235 | ohci_dumpregs(sc); |
---|
236 | } |
---|
237 | #endif |
---|
238 | |
---|
239 | if (do_suspend) { |
---|
240 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_SUSPEND); |
---|
241 | return (USB_ERR_NORMAL_COMPLETION); |
---|
242 | } |
---|
243 | |
---|
244 | /* The controller is now in SUSPEND state, we have 2ms to finish. */ |
---|
245 | |
---|
246 | /* set up HC registers */ |
---|
247 | usbd_get_page(&sc->sc_hw.hcca_pc, 0, &buf_res); |
---|
248 | OWRITE4(sc, OHCI_HCCA, buf_res.physaddr); |
---|
249 | |
---|
250 | usbd_get_page(&sc->sc_hw.ctrl_start_pc, 0, &buf_res); |
---|
251 | OWRITE4(sc, OHCI_CONTROL_HEAD_ED, buf_res.physaddr); |
---|
252 | |
---|
253 | usbd_get_page(&sc->sc_hw.bulk_start_pc, 0, &buf_res); |
---|
254 | OWRITE4(sc, OHCI_BULK_HEAD_ED, buf_res.physaddr); |
---|
255 | |
---|
256 | /* disable all interrupts and then switch on all desired interrupts */ |
---|
257 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); |
---|
258 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); |
---|
259 | /* switch on desired functional features */ |
---|
260 | ctl = OREAD4(sc, OHCI_CONTROL); |
---|
261 | ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); |
---|
262 | ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | |
---|
263 | OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL; |
---|
264 | /* And finally start it! */ |
---|
265 | OWRITE4(sc, OHCI_CONTROL, ctl); |
---|
266 | |
---|
267 | /* |
---|
268 | * The controller is now OPERATIONAL. Set a some final |
---|
269 | * registers that should be set earlier, but that the |
---|
270 | * controller ignores when in the SUSPEND state. |
---|
271 | */ |
---|
272 | fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; |
---|
273 | fm |= OHCI_FSMPS(ival) | ival; |
---|
274 | OWRITE4(sc, OHCI_FM_INTERVAL, fm); |
---|
275 | per = OHCI_PERIODIC(ival); /* 90% periodic */ |
---|
276 | OWRITE4(sc, OHCI_PERIODIC_START, per); |
---|
277 | |
---|
278 | /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ |
---|
279 | desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); |
---|
280 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); |
---|
281 | OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ |
---|
282 | usb_pause_mtx(NULL, |
---|
283 | USB_MS_TO_TICKS(OHCI_ENABLE_POWER_DELAY)); |
---|
284 | OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); |
---|
285 | |
---|
286 | /* |
---|
287 | * The AMD756 requires a delay before re-reading the register, |
---|
288 | * otherwise it will occasionally report 0 ports. |
---|
289 | */ |
---|
290 | sc->sc_noport = 0; |
---|
291 | for (i = 0; (i < 10) && (sc->sc_noport == 0); i++) { |
---|
292 | usb_pause_mtx(NULL, |
---|
293 | USB_MS_TO_TICKS(OHCI_READ_DESC_DELAY)); |
---|
294 | sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); |
---|
295 | } |
---|
296 | |
---|
297 | #ifdef USB_DEBUG |
---|
298 | if (ohcidebug > 5) { |
---|
299 | ohci_dumpregs(sc); |
---|
300 | } |
---|
301 | #endif |
---|
302 | return (USB_ERR_NORMAL_COMPLETION); |
---|
303 | } |
---|
304 | |
---|
305 | static struct ohci_ed * |
---|
306 | ohci_init_ed(struct usb_page_cache *pc) |
---|
307 | { |
---|
308 | struct usb_page_search buf_res; |
---|
309 | struct ohci_ed *ed; |
---|
310 | |
---|
311 | usbd_get_page(pc, 0, &buf_res); |
---|
312 | |
---|
313 | ed = buf_res.buffer; |
---|
314 | |
---|
315 | ed->ed_self = htole32(buf_res.physaddr); |
---|
316 | ed->ed_flags = htole32(OHCI_ED_SKIP); |
---|
317 | ed->page_cache = pc; |
---|
318 | |
---|
319 | return (ed); |
---|
320 | } |
---|
321 | |
---|
322 | usb_error_t |
---|
323 | ohci_init(ohci_softc_t *sc) |
---|
324 | { |
---|
325 | struct usb_page_search buf_res; |
---|
326 | uint16_t i; |
---|
327 | uint16_t bit; |
---|
328 | uint16_t x; |
---|
329 | uint16_t y; |
---|
330 | |
---|
331 | DPRINTF("start\n"); |
---|
332 | |
---|
333 | sc->sc_eintrs = OHCI_NORMAL_INTRS; |
---|
334 | |
---|
335 | /* |
---|
336 | * Setup all ED's |
---|
337 | */ |
---|
338 | |
---|
339 | sc->sc_ctrl_p_last = |
---|
340 | ohci_init_ed(&sc->sc_hw.ctrl_start_pc); |
---|
341 | |
---|
342 | sc->sc_bulk_p_last = |
---|
343 | ohci_init_ed(&sc->sc_hw.bulk_start_pc); |
---|
344 | |
---|
345 | sc->sc_isoc_p_last = |
---|
346 | ohci_init_ed(&sc->sc_hw.isoc_start_pc); |
---|
347 | |
---|
348 | for (i = 0; i != OHCI_NO_EDS; i++) { |
---|
349 | sc->sc_intr_p_last[i] = |
---|
350 | ohci_init_ed(sc->sc_hw.intr_start_pc + i); |
---|
351 | } |
---|
352 | |
---|
353 | /* |
---|
354 | * the QHs are arranged to give poll intervals that are |
---|
355 | * powers of 2 times 1ms |
---|
356 | */ |
---|
357 | bit = OHCI_NO_EDS / 2; |
---|
358 | while (bit) { |
---|
359 | x = bit; |
---|
360 | while (x & bit) { |
---|
361 | ohci_ed_t *ed_x; |
---|
362 | ohci_ed_t *ed_y; |
---|
363 | |
---|
364 | y = (x ^ bit) | (bit / 2); |
---|
365 | |
---|
366 | /* |
---|
367 | * the next QH has half the poll interval |
---|
368 | */ |
---|
369 | ed_x = sc->sc_intr_p_last[x]; |
---|
370 | ed_y = sc->sc_intr_p_last[y]; |
---|
371 | |
---|
372 | ed_x->next = NULL; |
---|
373 | ed_x->ed_next = ed_y->ed_self; |
---|
374 | |
---|
375 | x++; |
---|
376 | } |
---|
377 | bit >>= 1; |
---|
378 | } |
---|
379 | |
---|
380 | if (1) { |
---|
381 | |
---|
382 | ohci_ed_t *ed_int; |
---|
383 | ohci_ed_t *ed_isc; |
---|
384 | |
---|
385 | ed_int = sc->sc_intr_p_last[0]; |
---|
386 | ed_isc = sc->sc_isoc_p_last; |
---|
387 | |
---|
388 | /* the last (1ms) QH */ |
---|
389 | ed_int->next = ed_isc; |
---|
390 | ed_int->ed_next = ed_isc->ed_self; |
---|
391 | } |
---|
392 | usbd_get_page(&sc->sc_hw.hcca_pc, 0, &buf_res); |
---|
393 | |
---|
394 | sc->sc_hcca_p = buf_res.buffer; |
---|
395 | |
---|
396 | /* |
---|
397 | * Fill HCCA interrupt table. The bit reversal is to get |
---|
398 | * the tree set up properly to spread the interrupts. |
---|
399 | */ |
---|
400 | for (i = 0; i != OHCI_NO_INTRS; i++) { |
---|
401 | sc->sc_hcca_p->hcca_interrupt_table[i] = |
---|
402 | sc->sc_intr_p_last[i | (OHCI_NO_EDS / 2)]->ed_self; |
---|
403 | } |
---|
404 | /* flush all cache into memory */ |
---|
405 | |
---|
406 | usb_bus_mem_flush_all(&sc->sc_bus, &ohci_iterate_hw_softc); |
---|
407 | |
---|
408 | /* set up the bus struct */ |
---|
409 | sc->sc_bus.methods = &ohci_bus_methods; |
---|
410 | |
---|
411 | usb_callout_init_mtx(&sc->sc_tmo_rhsc, &sc->sc_bus.bus_mtx, 0); |
---|
412 | |
---|
413 | #ifdef USB_DEBUG |
---|
414 | if (ohcidebug > 15) { |
---|
415 | for (i = 0; i != OHCI_NO_EDS; i++) { |
---|
416 | printf("ed#%d ", i); |
---|
417 | ohci_dump_ed(sc->sc_intr_p_last[i]); |
---|
418 | } |
---|
419 | printf("iso "); |
---|
420 | ohci_dump_ed(sc->sc_isoc_p_last); |
---|
421 | } |
---|
422 | #endif |
---|
423 | |
---|
424 | sc->sc_bus.usbrev = USB_REV_1_0; |
---|
425 | |
---|
426 | if (ohci_controller_init(sc, 0) != 0) |
---|
427 | return (USB_ERR_INVAL); |
---|
428 | |
---|
429 | /* catch any lost interrupts */ |
---|
430 | ohci_do_poll(&sc->sc_bus); |
---|
431 | return (USB_ERR_NORMAL_COMPLETION); |
---|
432 | } |
---|
433 | |
---|
434 | /* |
---|
435 | * shut down the controller when the system is going down |
---|
436 | */ |
---|
437 | void |
---|
438 | ohci_detach(struct ohci_softc *sc) |
---|
439 | { |
---|
440 | USB_BUS_LOCK(&sc->sc_bus); |
---|
441 | |
---|
442 | usb_callout_stop(&sc->sc_tmo_rhsc); |
---|
443 | |
---|
444 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); |
---|
445 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); |
---|
446 | |
---|
447 | USB_BUS_UNLOCK(&sc->sc_bus); |
---|
448 | |
---|
449 | /* XXX let stray task complete */ |
---|
450 | usb_pause_mtx(NULL, hz / 20); |
---|
451 | |
---|
452 | usb_callout_drain(&sc->sc_tmo_rhsc); |
---|
453 | } |
---|
454 | |
---|
455 | static void |
---|
456 | ohci_suspend(ohci_softc_t *sc) |
---|
457 | { |
---|
458 | DPRINTF("\n"); |
---|
459 | |
---|
460 | #ifdef USB_DEBUG |
---|
461 | if (ohcidebug > 2) |
---|
462 | ohci_dumpregs(sc); |
---|
463 | #endif |
---|
464 | |
---|
465 | /* reset HC and leave it suspended */ |
---|
466 | ohci_controller_init(sc, 1); |
---|
467 | } |
---|
468 | |
---|
469 | static void |
---|
470 | ohci_resume(ohci_softc_t *sc) |
---|
471 | { |
---|
472 | DPRINTF("\n"); |
---|
473 | |
---|
474 | #ifdef USB_DEBUG |
---|
475 | if (ohcidebug > 2) |
---|
476 | ohci_dumpregs(sc); |
---|
477 | #endif |
---|
478 | |
---|
479 | /* some broken BIOSes never initialize the Controller chip */ |
---|
480 | ohci_controller_init(sc, 0); |
---|
481 | |
---|
482 | /* catch any lost interrupts */ |
---|
483 | ohci_do_poll(&sc->sc_bus); |
---|
484 | } |
---|
485 | |
---|
486 | #ifdef USB_DEBUG |
---|
487 | static void |
---|
488 | ohci_dumpregs(ohci_softc_t *sc) |
---|
489 | { |
---|
490 | struct ohci_hcca *hcca; |
---|
491 | |
---|
492 | DPRINTF("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n", |
---|
493 | OREAD4(sc, OHCI_REVISION), |
---|
494 | OREAD4(sc, OHCI_CONTROL), |
---|
495 | OREAD4(sc, OHCI_COMMAND_STATUS)); |
---|
496 | DPRINTF(" intrstat=0x%08x intre=0x%08x intrd=0x%08x\n", |
---|
497 | OREAD4(sc, OHCI_INTERRUPT_STATUS), |
---|
498 | OREAD4(sc, OHCI_INTERRUPT_ENABLE), |
---|
499 | OREAD4(sc, OHCI_INTERRUPT_DISABLE)); |
---|
500 | DPRINTF(" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n", |
---|
501 | OREAD4(sc, OHCI_HCCA), |
---|
502 | OREAD4(sc, OHCI_PERIOD_CURRENT_ED), |
---|
503 | OREAD4(sc, OHCI_CONTROL_HEAD_ED)); |
---|
504 | DPRINTF(" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n", |
---|
505 | OREAD4(sc, OHCI_CONTROL_CURRENT_ED), |
---|
506 | OREAD4(sc, OHCI_BULK_HEAD_ED), |
---|
507 | OREAD4(sc, OHCI_BULK_CURRENT_ED)); |
---|
508 | DPRINTF(" done=0x%08x fmival=0x%08x fmrem=0x%08x\n", |
---|
509 | OREAD4(sc, OHCI_DONE_HEAD), |
---|
510 | OREAD4(sc, OHCI_FM_INTERVAL), |
---|
511 | OREAD4(sc, OHCI_FM_REMAINING)); |
---|
512 | DPRINTF(" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n", |
---|
513 | OREAD4(sc, OHCI_FM_NUMBER), |
---|
514 | OREAD4(sc, OHCI_PERIODIC_START), |
---|
515 | OREAD4(sc, OHCI_LS_THRESHOLD)); |
---|
516 | DPRINTF(" desca=0x%08x descb=0x%08x stat=0x%08x\n", |
---|
517 | OREAD4(sc, OHCI_RH_DESCRIPTOR_A), |
---|
518 | OREAD4(sc, OHCI_RH_DESCRIPTOR_B), |
---|
519 | OREAD4(sc, OHCI_RH_STATUS)); |
---|
520 | DPRINTF(" port1=0x%08x port2=0x%08x\n", |
---|
521 | OREAD4(sc, OHCI_RH_PORT_STATUS(1)), |
---|
522 | OREAD4(sc, OHCI_RH_PORT_STATUS(2))); |
---|
523 | |
---|
524 | hcca = ohci_get_hcca(sc); |
---|
525 | |
---|
526 | DPRINTF(" HCCA: frame_number=0x%04x done_head=0x%08x\n", |
---|
527 | le32toh(hcca->hcca_frame_number), |
---|
528 | le32toh(hcca->hcca_done_head)); |
---|
529 | } |
---|
530 | static void |
---|
531 | ohci_dump_tds(ohci_td_t *std) |
---|
532 | { |
---|
533 | for (; std; std = std->obj_next) { |
---|
534 | if (ohci_dump_td(std)) { |
---|
535 | break; |
---|
536 | } |
---|
537 | } |
---|
538 | } |
---|
539 | |
---|
540 | static uint8_t |
---|
541 | ohci_dump_td(ohci_td_t *std) |
---|
542 | { |
---|
543 | uint32_t td_flags; |
---|
544 | uint8_t temp; |
---|
545 | |
---|
546 | usb_pc_cpu_invalidate(std->page_cache); |
---|
547 | |
---|
548 | td_flags = le32toh(std->td_flags); |
---|
549 | temp = (std->td_next == 0); |
---|
550 | |
---|
551 | printf("TD(%p) at 0x%08x: %s%s%s%s%s delay=%d ec=%d " |
---|
552 | "cc=%d\ncbp=0x%08x next=0x%08x be=0x%08x\n", |
---|
553 | std, le32toh(std->td_self), |
---|
554 | (td_flags & OHCI_TD_R) ? "-R" : "", |
---|
555 | (td_flags & OHCI_TD_OUT) ? "-OUT" : "", |
---|
556 | (td_flags & OHCI_TD_IN) ? "-IN" : "", |
---|
557 | ((td_flags & OHCI_TD_TOGGLE_MASK) == OHCI_TD_TOGGLE_1) ? "-TOG1" : "", |
---|
558 | ((td_flags & OHCI_TD_TOGGLE_MASK) == OHCI_TD_TOGGLE_0) ? "-TOG0" : "", |
---|
559 | OHCI_TD_GET_DI(td_flags), |
---|
560 | OHCI_TD_GET_EC(td_flags), |
---|
561 | OHCI_TD_GET_CC(td_flags), |
---|
562 | le32toh(std->td_cbp), |
---|
563 | le32toh(std->td_next), |
---|
564 | le32toh(std->td_be)); |
---|
565 | |
---|
566 | return (temp); |
---|
567 | } |
---|
568 | |
---|
569 | static uint8_t |
---|
570 | ohci_dump_itd(ohci_itd_t *sitd) |
---|
571 | { |
---|
572 | uint32_t itd_flags; |
---|
573 | uint16_t i; |
---|
574 | uint8_t temp; |
---|
575 | |
---|
576 | usb_pc_cpu_invalidate(sitd->page_cache); |
---|
577 | |
---|
578 | itd_flags = le32toh(sitd->itd_flags); |
---|
579 | temp = (sitd->itd_next == 0); |
---|
580 | |
---|
581 | printf("ITD(%p) at 0x%08x: sf=%d di=%d fc=%d cc=%d\n" |
---|
582 | "bp0=0x%08x next=0x%08x be=0x%08x\n", |
---|
583 | sitd, le32toh(sitd->itd_self), |
---|
584 | OHCI_ITD_GET_SF(itd_flags), |
---|
585 | OHCI_ITD_GET_DI(itd_flags), |
---|
586 | OHCI_ITD_GET_FC(itd_flags), |
---|
587 | OHCI_ITD_GET_CC(itd_flags), |
---|
588 | le32toh(sitd->itd_bp0), |
---|
589 | le32toh(sitd->itd_next), |
---|
590 | le32toh(sitd->itd_be)); |
---|
591 | for (i = 0; i < OHCI_ITD_NOFFSET; i++) { |
---|
592 | printf("offs[%d]=0x%04x ", i, |
---|
593 | (uint32_t)le16toh(sitd->itd_offset[i])); |
---|
594 | } |
---|
595 | printf("\n"); |
---|
596 | |
---|
597 | return (temp); |
---|
598 | } |
---|
599 | |
---|
600 | static void |
---|
601 | ohci_dump_itds(ohci_itd_t *sitd) |
---|
602 | { |
---|
603 | for (; sitd; sitd = sitd->obj_next) { |
---|
604 | if (ohci_dump_itd(sitd)) { |
---|
605 | break; |
---|
606 | } |
---|
607 | } |
---|
608 | } |
---|
609 | |
---|
610 | static void |
---|
611 | ohci_dump_ed(ohci_ed_t *sed) |
---|
612 | { |
---|
613 | uint32_t ed_flags; |
---|
614 | uint32_t ed_headp; |
---|
615 | |
---|
616 | usb_pc_cpu_invalidate(sed->page_cache); |
---|
617 | |
---|
618 | ed_flags = le32toh(sed->ed_flags); |
---|
619 | ed_headp = le32toh(sed->ed_headp); |
---|
620 | |
---|
621 | printf("ED(%p) at 0x%08x: addr=%d endpt=%d maxp=%d flags=%s%s%s%s%s\n" |
---|
622 | "tailp=0x%08x headflags=%s%s headp=0x%08x nexted=0x%08x\n", |
---|
623 | sed, le32toh(sed->ed_self), |
---|
624 | OHCI_ED_GET_FA(ed_flags), |
---|
625 | OHCI_ED_GET_EN(ed_flags), |
---|
626 | OHCI_ED_GET_MAXP(ed_flags), |
---|
627 | (ed_flags & OHCI_ED_DIR_OUT) ? "-OUT" : "", |
---|
628 | (ed_flags & OHCI_ED_DIR_IN) ? "-IN" : "", |
---|
629 | (ed_flags & OHCI_ED_SPEED) ? "-LOWSPEED" : "", |
---|
630 | (ed_flags & OHCI_ED_SKIP) ? "-SKIP" : "", |
---|
631 | (ed_flags & OHCI_ED_FORMAT_ISO) ? "-ISO" : "", |
---|
632 | le32toh(sed->ed_tailp), |
---|
633 | (ed_headp & OHCI_HALTED) ? "-HALTED" : "", |
---|
634 | (ed_headp & OHCI_TOGGLECARRY) ? "-CARRY" : "", |
---|
635 | le32toh(sed->ed_headp), |
---|
636 | le32toh(sed->ed_next)); |
---|
637 | } |
---|
638 | |
---|
639 | #endif |
---|
640 | |
---|
641 | static void |
---|
642 | ohci_transfer_intr_enqueue(struct usb_xfer *xfer) |
---|
643 | { |
---|
644 | /* check for early completion */ |
---|
645 | if (ohci_check_transfer(xfer)) { |
---|
646 | return; |
---|
647 | } |
---|
648 | /* put transfer on interrupt queue */ |
---|
649 | usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); |
---|
650 | |
---|
651 | /* start timeout, if any */ |
---|
652 | if (xfer->timeout != 0) { |
---|
653 | usbd_transfer_timeout_ms(xfer, &ohci_timeout, xfer->timeout); |
---|
654 | } |
---|
655 | } |
---|
656 | |
---|
657 | #define OHCI_APPEND_QH(sed,last) (last) = _ohci_append_qh(sed,last) |
---|
658 | static ohci_ed_t * |
---|
659 | _ohci_append_qh(ohci_ed_t *sed, ohci_ed_t *last) |
---|
660 | { |
---|
661 | DPRINTFN(11, "%p to %p\n", sed, last); |
---|
662 | |
---|
663 | if (sed->prev != NULL) { |
---|
664 | /* should not happen */ |
---|
665 | DPRINTFN(0, "ED already linked!\n"); |
---|
666 | return (last); |
---|
667 | } |
---|
668 | /* (sc->sc_bus.bus_mtx) must be locked */ |
---|
669 | |
---|
670 | sed->next = last->next; |
---|
671 | sed->ed_next = last->ed_next; |
---|
672 | sed->ed_tailp = 0; |
---|
673 | |
---|
674 | sed->prev = last; |
---|
675 | |
---|
676 | usb_pc_cpu_flush(sed->page_cache); |
---|
677 | |
---|
678 | /* |
---|
679 | * the last->next->prev is never followed: sed->next->prev = sed; |
---|
680 | */ |
---|
681 | |
---|
682 | last->next = sed; |
---|
683 | last->ed_next = sed->ed_self; |
---|
684 | |
---|
685 | usb_pc_cpu_flush(last->page_cache); |
---|
686 | |
---|
687 | return (sed); |
---|
688 | } |
---|
689 | |
---|
690 | #define OHCI_REMOVE_QH(sed,last) (last) = _ohci_remove_qh(sed,last) |
---|
691 | static ohci_ed_t * |
---|
692 | _ohci_remove_qh(ohci_ed_t *sed, ohci_ed_t *last) |
---|
693 | { |
---|
694 | DPRINTFN(11, "%p from %p\n", sed, last); |
---|
695 | |
---|
696 | /* (sc->sc_bus.bus_mtx) must be locked */ |
---|
697 | |
---|
698 | /* only remove if not removed from a queue */ |
---|
699 | if (sed->prev) { |
---|
700 | |
---|
701 | sed->prev->next = sed->next; |
---|
702 | sed->prev->ed_next = sed->ed_next; |
---|
703 | |
---|
704 | usb_pc_cpu_flush(sed->prev->page_cache); |
---|
705 | |
---|
706 | if (sed->next) { |
---|
707 | sed->next->prev = sed->prev; |
---|
708 | usb_pc_cpu_flush(sed->next->page_cache); |
---|
709 | } |
---|
710 | last = ((last == sed) ? sed->prev : last); |
---|
711 | |
---|
712 | sed->prev = 0; |
---|
713 | |
---|
714 | usb_pc_cpu_flush(sed->page_cache); |
---|
715 | } |
---|
716 | return (last); |
---|
717 | } |
---|
718 | |
---|
719 | static void |
---|
720 | ohci_isoc_done(struct usb_xfer *xfer) |
---|
721 | { |
---|
722 | uint8_t nframes; |
---|
723 | uint32_t *plen = xfer->frlengths; |
---|
724 | volatile uint16_t *olen; |
---|
725 | uint16_t len = 0; |
---|
726 | ohci_itd_t *td = xfer->td_transfer_first; |
---|
727 | |
---|
728 | while (1) { |
---|
729 | if (td == NULL) { |
---|
730 | panic("%s:%d: out of TD's\n", |
---|
731 | __FUNCTION__, __LINE__); |
---|
732 | } |
---|
733 | #ifdef USB_DEBUG |
---|
734 | if (ohcidebug > 5) { |
---|
735 | DPRINTF("isoc TD\n"); |
---|
736 | ohci_dump_itd(td); |
---|
737 | } |
---|
738 | #endif |
---|
739 | usb_pc_cpu_invalidate(td->page_cache); |
---|
740 | |
---|
741 | nframes = td->frames; |
---|
742 | olen = &td->itd_offset[0]; |
---|
743 | |
---|
744 | if (nframes > 8) { |
---|
745 | nframes = 8; |
---|
746 | } |
---|
747 | while (nframes--) { |
---|
748 | len = le16toh(*olen); |
---|
749 | |
---|
750 | if ((len >> 12) == OHCI_CC_NOT_ACCESSED) { |
---|
751 | len = 0; |
---|
752 | } else { |
---|
753 | len &= ((1 << 12) - 1); |
---|
754 | } |
---|
755 | |
---|
756 | if (len > *plen) { |
---|
757 | len = 0;/* invalid length */ |
---|
758 | } |
---|
759 | *plen = len; |
---|
760 | plen++; |
---|
761 | olen++; |
---|
762 | } |
---|
763 | |
---|
764 | if (((void *)td) == xfer->td_transfer_last) { |
---|
765 | break; |
---|
766 | } |
---|
767 | td = td->obj_next; |
---|
768 | } |
---|
769 | |
---|
770 | xfer->aframes = xfer->nframes; |
---|
771 | ohci_device_done(xfer, USB_ERR_NORMAL_COMPLETION); |
---|
772 | } |
---|
773 | |
---|
774 | #ifdef USB_DEBUG |
---|
775 | static const char *const |
---|
776 | ohci_cc_strs[] = |
---|
777 | { |
---|
778 | "NO_ERROR", |
---|
779 | "CRC", |
---|
780 | "BIT_STUFFING", |
---|
781 | "DATA_TOGGLE_MISMATCH", |
---|
782 | |
---|
783 | "STALL", |
---|
784 | "DEVICE_NOT_RESPONDING", |
---|
785 | "PID_CHECK_FAILURE", |
---|
786 | "UNEXPECTED_PID", |
---|
787 | |
---|
788 | "DATA_OVERRUN", |
---|
789 | "DATA_UNDERRUN", |
---|
790 | "BUFFER_OVERRUN", |
---|
791 | "BUFFER_UNDERRUN", |
---|
792 | |
---|
793 | "reserved", |
---|
794 | "reserved", |
---|
795 | "NOT_ACCESSED", |
---|
796 | "NOT_ACCESSED" |
---|
797 | }; |
---|
798 | |
---|
799 | #endif |
---|
800 | |
---|
801 | static usb_error_t |
---|
802 | ohci_non_isoc_done_sub(struct usb_xfer *xfer) |
---|
803 | { |
---|
804 | ohci_td_t *td; |
---|
805 | ohci_td_t *td_alt_next; |
---|
806 | uint32_t temp; |
---|
807 | uint32_t phy_start; |
---|
808 | uint32_t phy_end; |
---|
809 | uint32_t td_flags; |
---|
810 | uint16_t cc; |
---|
811 | |
---|
812 | td = xfer->td_transfer_cache; |
---|
813 | td_alt_next = td->alt_next; |
---|
814 | td_flags = 0; |
---|
815 | |
---|
816 | if (xfer->aframes != xfer->nframes) { |
---|
817 | usbd_xfer_set_frame_len(xfer, xfer->aframes, 0); |
---|
818 | } |
---|
819 | while (1) { |
---|
820 | |
---|
821 | usb_pc_cpu_invalidate(td->page_cache); |
---|
822 | phy_start = le32toh(td->td_cbp); |
---|
823 | td_flags = le32toh(td->td_flags); |
---|
824 | cc = OHCI_TD_GET_CC(td_flags); |
---|
825 | |
---|
826 | if (phy_start) { |
---|
827 | /* |
---|
828 | * short transfer - compute the number of remaining |
---|
829 | * bytes in the hardware buffer: |
---|
830 | */ |
---|
831 | phy_end = le32toh(td->td_be); |
---|
832 | temp = (OHCI_PAGE(phy_start ^ phy_end) ? |
---|
833 | (OHCI_PAGE_SIZE + 1) : 0x0001); |
---|
834 | temp += OHCI_PAGE_OFFSET(phy_end); |
---|
835 | temp -= OHCI_PAGE_OFFSET(phy_start); |
---|
836 | |
---|
837 | if (temp > td->len) { |
---|
838 | /* guard against corruption */ |
---|
839 | cc = OHCI_CC_STALL; |
---|
840 | } else if (xfer->aframes != xfer->nframes) { |
---|
841 | /* |
---|
842 | * Sum up total transfer length |
---|
843 | * in "frlengths[]": |
---|
844 | */ |
---|
845 | xfer->frlengths[xfer->aframes] += td->len - temp; |
---|
846 | } |
---|
847 | } else { |
---|
848 | if (xfer->aframes != xfer->nframes) { |
---|
849 | /* transfer was complete */ |
---|
850 | xfer->frlengths[xfer->aframes] += td->len; |
---|
851 | } |
---|
852 | } |
---|
853 | /* Check for last transfer */ |
---|
854 | if (((void *)td) == xfer->td_transfer_last) { |
---|
855 | td = NULL; |
---|
856 | break; |
---|
857 | } |
---|
858 | /* Check transfer status */ |
---|
859 | if (cc) { |
---|
860 | /* the transfer is finished */ |
---|
861 | td = NULL; |
---|
862 | break; |
---|
863 | } |
---|
864 | /* Check for short transfer */ |
---|
865 | if (phy_start) { |
---|
866 | if (xfer->flags_int.short_frames_ok) { |
---|
867 | /* follow alt next */ |
---|
868 | td = td->alt_next; |
---|
869 | } else { |
---|
870 | /* the transfer is finished */ |
---|
871 | td = NULL; |
---|
872 | } |
---|
873 | break; |
---|
874 | } |
---|
875 | td = td->obj_next; |
---|
876 | |
---|
877 | if (td->alt_next != td_alt_next) { |
---|
878 | /* this USB frame is complete */ |
---|
879 | break; |
---|
880 | } |
---|
881 | } |
---|
882 | |
---|
883 | /* update transfer cache */ |
---|
884 | |
---|
885 | xfer->td_transfer_cache = td; |
---|
886 | |
---|
887 | DPRINTFN(16, "error cc=%d (%s)\n", |
---|
888 | cc, ohci_cc_strs[cc]); |
---|
889 | |
---|
890 | return ((cc == 0) ? USB_ERR_NORMAL_COMPLETION : |
---|
891 | (cc == OHCI_CC_STALL) ? USB_ERR_STALLED : USB_ERR_IOERROR); |
---|
892 | } |
---|
893 | |
---|
894 | static void |
---|
895 | ohci_non_isoc_done(struct usb_xfer *xfer) |
---|
896 | { |
---|
897 | usb_error_t err = 0; |
---|
898 | |
---|
899 | DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", |
---|
900 | xfer, xfer->endpoint); |
---|
901 | |
---|
902 | #ifdef USB_DEBUG |
---|
903 | if (ohcidebug > 10) { |
---|
904 | ohci_dump_tds(xfer->td_transfer_first); |
---|
905 | } |
---|
906 | #endif |
---|
907 | |
---|
908 | /* reset scanner */ |
---|
909 | |
---|
910 | xfer->td_transfer_cache = xfer->td_transfer_first; |
---|
911 | |
---|
912 | if (xfer->flags_int.control_xfr) { |
---|
913 | |
---|
914 | if (xfer->flags_int.control_hdr) { |
---|
915 | |
---|
916 | err = ohci_non_isoc_done_sub(xfer); |
---|
917 | } |
---|
918 | xfer->aframes = 1; |
---|
919 | |
---|
920 | if (xfer->td_transfer_cache == NULL) { |
---|
921 | goto done; |
---|
922 | } |
---|
923 | } |
---|
924 | while (xfer->aframes != xfer->nframes) { |
---|
925 | |
---|
926 | err = ohci_non_isoc_done_sub(xfer); |
---|
927 | xfer->aframes++; |
---|
928 | |
---|
929 | if (xfer->td_transfer_cache == NULL) { |
---|
930 | goto done; |
---|
931 | } |
---|
932 | } |
---|
933 | |
---|
934 | if (xfer->flags_int.control_xfr && |
---|
935 | !xfer->flags_int.control_act) { |
---|
936 | |
---|
937 | err = ohci_non_isoc_done_sub(xfer); |
---|
938 | } |
---|
939 | done: |
---|
940 | ohci_device_done(xfer, err); |
---|
941 | } |
---|
942 | |
---|
943 | /*------------------------------------------------------------------------* |
---|
944 | * ohci_check_transfer_sub |
---|
945 | *------------------------------------------------------------------------*/ |
---|
946 | static void |
---|
947 | ohci_check_transfer_sub(struct usb_xfer *xfer) |
---|
948 | { |
---|
949 | ohci_td_t *td; |
---|
950 | ohci_ed_t *ed; |
---|
951 | uint32_t phy_start; |
---|
952 | uint32_t td_flags; |
---|
953 | uint32_t td_next; |
---|
954 | uint16_t cc; |
---|
955 | |
---|
956 | td = xfer->td_transfer_cache; |
---|
957 | |
---|
958 | while (1) { |
---|
959 | |
---|
960 | usb_pc_cpu_invalidate(td->page_cache); |
---|
961 | phy_start = le32toh(td->td_cbp); |
---|
962 | td_flags = le32toh(td->td_flags); |
---|
963 | td_next = le32toh(td->td_next); |
---|
964 | |
---|
965 | /* Check for last transfer */ |
---|
966 | if (((void *)td) == xfer->td_transfer_last) { |
---|
967 | /* the transfer is finished */ |
---|
968 | td = NULL; |
---|
969 | break; |
---|
970 | } |
---|
971 | /* Check transfer status */ |
---|
972 | cc = OHCI_TD_GET_CC(td_flags); |
---|
973 | if (cc) { |
---|
974 | /* the transfer is finished */ |
---|
975 | td = NULL; |
---|
976 | break; |
---|
977 | } |
---|
978 | /* |
---|
979 | * Check if we reached the last packet |
---|
980 | * or if there is a short packet: |
---|
981 | */ |
---|
982 | |
---|
983 | if (((td_next & (~0xF)) == OHCI_TD_NEXT_END) || phy_start) { |
---|
984 | /* follow alt next */ |
---|
985 | td = td->alt_next; |
---|
986 | break; |
---|
987 | } |
---|
988 | td = td->obj_next; |
---|
989 | } |
---|
990 | |
---|
991 | /* update transfer cache */ |
---|
992 | |
---|
993 | xfer->td_transfer_cache = td; |
---|
994 | |
---|
995 | if (td) { |
---|
996 | |
---|
997 | ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; |
---|
998 | |
---|
999 | ed->ed_headp = td->td_self; |
---|
1000 | usb_pc_cpu_flush(ed->page_cache); |
---|
1001 | |
---|
1002 | DPRINTFN(13, "xfer=%p following alt next\n", xfer); |
---|
1003 | |
---|
1004 | /* |
---|
1005 | * Make sure that the OHCI re-scans the schedule by |
---|
1006 | * writing the BLF and CLF bits: |
---|
1007 | */ |
---|
1008 | |
---|
1009 | if (xfer->xroot->udev->flags.self_suspended) { |
---|
1010 | /* nothing to do */ |
---|
1011 | } else if (xfer->endpoint->methods == &ohci_device_bulk_methods) { |
---|
1012 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1013 | |
---|
1014 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); |
---|
1015 | } else if (xfer->endpoint->methods == &ohci_device_ctrl_methods) { |
---|
1016 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1017 | |
---|
1018 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); |
---|
1019 | } |
---|
1020 | } |
---|
1021 | } |
---|
1022 | |
---|
1023 | /*------------------------------------------------------------------------* |
---|
1024 | * ohci_check_transfer |
---|
1025 | * |
---|
1026 | * Return values: |
---|
1027 | * 0: USB transfer is not finished |
---|
1028 | * Else: USB transfer is finished |
---|
1029 | *------------------------------------------------------------------------*/ |
---|
1030 | static uint8_t |
---|
1031 | ohci_check_transfer(struct usb_xfer *xfer) |
---|
1032 | { |
---|
1033 | ohci_ed_t *ed; |
---|
1034 | uint32_t ed_headp; |
---|
1035 | uint32_t ed_tailp; |
---|
1036 | |
---|
1037 | DPRINTFN(13, "xfer=%p checking transfer\n", xfer); |
---|
1038 | |
---|
1039 | ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; |
---|
1040 | |
---|
1041 | usb_pc_cpu_invalidate(ed->page_cache); |
---|
1042 | ed_headp = le32toh(ed->ed_headp); |
---|
1043 | ed_tailp = le32toh(ed->ed_tailp); |
---|
1044 | |
---|
1045 | if ((ed_headp & OHCI_HALTED) || |
---|
1046 | (((ed_headp ^ ed_tailp) & (~0xF)) == 0)) { |
---|
1047 | if (xfer->endpoint->methods == &ohci_device_isoc_methods) { |
---|
1048 | /* isochronous transfer */ |
---|
1049 | ohci_isoc_done(xfer); |
---|
1050 | } else { |
---|
1051 | if (xfer->flags_int.short_frames_ok) { |
---|
1052 | ohci_check_transfer_sub(xfer); |
---|
1053 | if (xfer->td_transfer_cache) { |
---|
1054 | /* not finished yet */ |
---|
1055 | return (0); |
---|
1056 | } |
---|
1057 | } |
---|
1058 | /* store data-toggle */ |
---|
1059 | if (ed_headp & OHCI_TOGGLECARRY) { |
---|
1060 | xfer->endpoint->toggle_next = 1; |
---|
1061 | } else { |
---|
1062 | xfer->endpoint->toggle_next = 0; |
---|
1063 | } |
---|
1064 | |
---|
1065 | /* non-isochronous transfer */ |
---|
1066 | ohci_non_isoc_done(xfer); |
---|
1067 | } |
---|
1068 | return (1); |
---|
1069 | } |
---|
1070 | DPRINTFN(13, "xfer=%p is still active\n", xfer); |
---|
1071 | return (0); |
---|
1072 | } |
---|
1073 | |
---|
1074 | static void |
---|
1075 | ohci_rhsc_enable(ohci_softc_t *sc) |
---|
1076 | { |
---|
1077 | DPRINTFN(5, "\n"); |
---|
1078 | |
---|
1079 | USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); |
---|
1080 | |
---|
1081 | sc->sc_eintrs |= OHCI_RHSC; |
---|
1082 | OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); |
---|
1083 | |
---|
1084 | /* acknowledge any RHSC interrupt */ |
---|
1085 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_RHSC); |
---|
1086 | |
---|
1087 | ohci_root_intr(sc); |
---|
1088 | } |
---|
1089 | |
---|
1090 | static void |
---|
1091 | ohci_interrupt_poll(ohci_softc_t *sc) |
---|
1092 | { |
---|
1093 | struct usb_xfer *xfer; |
---|
1094 | |
---|
1095 | repeat: |
---|
1096 | TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { |
---|
1097 | /* |
---|
1098 | * check if transfer is transferred |
---|
1099 | */ |
---|
1100 | if (ohci_check_transfer(xfer)) { |
---|
1101 | /* queue has been modified */ |
---|
1102 | goto repeat; |
---|
1103 | } |
---|
1104 | } |
---|
1105 | } |
---|
1106 | |
---|
1107 | /*------------------------------------------------------------------------* |
---|
1108 | * ohci_interrupt - OHCI interrupt handler |
---|
1109 | * |
---|
1110 | * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler, |
---|
1111 | * hence the interrupt handler will be setup before "sc->sc_bus.bdev" |
---|
1112 | * is present ! |
---|
1113 | *------------------------------------------------------------------------*/ |
---|
1114 | void |
---|
1115 | ohci_interrupt(ohci_softc_t *sc) |
---|
1116 | { |
---|
1117 | struct ohci_hcca *hcca; |
---|
1118 | uint32_t status; |
---|
1119 | uint32_t done; |
---|
1120 | |
---|
1121 | USB_BUS_LOCK(&sc->sc_bus); |
---|
1122 | |
---|
1123 | hcca = ohci_get_hcca(sc); |
---|
1124 | |
---|
1125 | DPRINTFN(16, "real interrupt\n"); |
---|
1126 | |
---|
1127 | #ifdef USB_DEBUG |
---|
1128 | if (ohcidebug > 15) { |
---|
1129 | ohci_dumpregs(sc); |
---|
1130 | } |
---|
1131 | #endif |
---|
1132 | |
---|
1133 | done = le32toh(hcca->hcca_done_head); |
---|
1134 | |
---|
1135 | /* |
---|
1136 | * The LSb of done is used to inform the HC Driver that an interrupt |
---|
1137 | * condition exists for both the Done list and for another event |
---|
1138 | * recorded in HcInterruptStatus. On an interrupt from the HC, the |
---|
1139 | * HC Driver checks the HccaDoneHead Value. If this value is 0, then |
---|
1140 | * the interrupt was caused by other than the HccaDoneHead update |
---|
1141 | * and the HcInterruptStatus register needs to be accessed to |
---|
1142 | * determine that exact interrupt cause. If HccaDoneHead is nonzero, |
---|
1143 | * then a Done list update interrupt is indicated and if the LSb of |
---|
1144 | * done is nonzero, then an additional interrupt event is indicated |
---|
1145 | * and HcInterruptStatus should be checked to determine its cause. |
---|
1146 | */ |
---|
1147 | if (done != 0) { |
---|
1148 | status = 0; |
---|
1149 | |
---|
1150 | if (done & ~OHCI_DONE_INTRS) { |
---|
1151 | status |= OHCI_WDH; |
---|
1152 | } |
---|
1153 | if (done & OHCI_DONE_INTRS) { |
---|
1154 | status |= OREAD4(sc, OHCI_INTERRUPT_STATUS); |
---|
1155 | } |
---|
1156 | hcca->hcca_done_head = 0; |
---|
1157 | |
---|
1158 | usb_pc_cpu_flush(&sc->sc_hw.hcca_pc); |
---|
1159 | } else { |
---|
1160 | status = OREAD4(sc, OHCI_INTERRUPT_STATUS) & ~OHCI_WDH; |
---|
1161 | } |
---|
1162 | |
---|
1163 | status &= ~OHCI_MIE; |
---|
1164 | if (status == 0) { |
---|
1165 | /* |
---|
1166 | * nothing to be done (PCI shared |
---|
1167 | * interrupt) |
---|
1168 | */ |
---|
1169 | goto done; |
---|
1170 | } |
---|
1171 | OWRITE4(sc, OHCI_INTERRUPT_STATUS, status); /* Acknowledge */ |
---|
1172 | |
---|
1173 | status &= sc->sc_eintrs; |
---|
1174 | if (status == 0) { |
---|
1175 | goto done; |
---|
1176 | } |
---|
1177 | if (status & (OHCI_SO | OHCI_RD | OHCI_UE | OHCI_RHSC)) { |
---|
1178 | #if 0 |
---|
1179 | if (status & OHCI_SO) { |
---|
1180 | /* XXX do what */ |
---|
1181 | } |
---|
1182 | #endif |
---|
1183 | if (status & OHCI_RD) { |
---|
1184 | printf("%s: resume detect\n", __FUNCTION__); |
---|
1185 | /* XXX process resume detect */ |
---|
1186 | } |
---|
1187 | if (status & OHCI_UE) { |
---|
1188 | printf("%s: unrecoverable error, " |
---|
1189 | "controller halted\n", __FUNCTION__); |
---|
1190 | OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); |
---|
1191 | /* XXX what else */ |
---|
1192 | } |
---|
1193 | if (status & OHCI_RHSC) { |
---|
1194 | /* |
---|
1195 | * Disable RHSC interrupt for now, because it will be |
---|
1196 | * on until the port has been reset. |
---|
1197 | */ |
---|
1198 | sc->sc_eintrs &= ~OHCI_RHSC; |
---|
1199 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC); |
---|
1200 | |
---|
1201 | ohci_root_intr(sc); |
---|
1202 | |
---|
1203 | /* do not allow RHSC interrupts > 1 per second */ |
---|
1204 | usb_callout_reset(&sc->sc_tmo_rhsc, hz, |
---|
1205 | (void *)&ohci_rhsc_enable, sc); |
---|
1206 | } |
---|
1207 | } |
---|
1208 | status &= ~(OHCI_RHSC | OHCI_WDH | OHCI_SO); |
---|
1209 | if (status != 0) { |
---|
1210 | /* Block unprocessed interrupts. XXX */ |
---|
1211 | OWRITE4(sc, OHCI_INTERRUPT_DISABLE, status); |
---|
1212 | sc->sc_eintrs &= ~status; |
---|
1213 | printf("%s: blocking intrs 0x%x\n", |
---|
1214 | __FUNCTION__, status); |
---|
1215 | } |
---|
1216 | /* poll all the USB transfers */ |
---|
1217 | ohci_interrupt_poll(sc); |
---|
1218 | |
---|
1219 | done: |
---|
1220 | USB_BUS_UNLOCK(&sc->sc_bus); |
---|
1221 | } |
---|
1222 | |
---|
1223 | /* |
---|
1224 | * called when a request does not complete |
---|
1225 | */ |
---|
1226 | static void |
---|
1227 | ohci_timeout(void *arg) |
---|
1228 | { |
---|
1229 | struct usb_xfer *xfer = arg; |
---|
1230 | |
---|
1231 | DPRINTF("xfer=%p\n", xfer); |
---|
1232 | |
---|
1233 | USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); |
---|
1234 | |
---|
1235 | /* transfer is transferred */ |
---|
1236 | ohci_device_done(xfer, USB_ERR_TIMEOUT); |
---|
1237 | } |
---|
1238 | |
---|
1239 | static void |
---|
1240 | ohci_do_poll(struct usb_bus *bus) |
---|
1241 | { |
---|
1242 | struct ohci_softc *sc = OHCI_BUS2SC(bus); |
---|
1243 | |
---|
1244 | USB_BUS_LOCK(&sc->sc_bus); |
---|
1245 | ohci_interrupt_poll(sc); |
---|
1246 | USB_BUS_UNLOCK(&sc->sc_bus); |
---|
1247 | } |
---|
1248 | |
---|
1249 | static void |
---|
1250 | ohci_setup_standard_chain_sub(struct ohci_std_temp *temp) |
---|
1251 | { |
---|
1252 | struct usb_page_search buf_res; |
---|
1253 | ohci_td_t *td; |
---|
1254 | ohci_td_t *td_next; |
---|
1255 | ohci_td_t *td_alt_next; |
---|
1256 | uint32_t buf_offset; |
---|
1257 | uint32_t average; |
---|
1258 | uint32_t len_old; |
---|
1259 | uint8_t shortpkt_old; |
---|
1260 | uint8_t precompute; |
---|
1261 | |
---|
1262 | td_alt_next = NULL; |
---|
1263 | buf_offset = 0; |
---|
1264 | shortpkt_old = temp->shortpkt; |
---|
1265 | len_old = temp->len; |
---|
1266 | precompute = 1; |
---|
1267 | |
---|
1268 | /* software is used to detect short incoming transfers */ |
---|
1269 | |
---|
1270 | if ((temp->td_flags & htole32(OHCI_TD_DP_MASK)) == htole32(OHCI_TD_IN)) { |
---|
1271 | temp->td_flags |= htole32(OHCI_TD_R); |
---|
1272 | } else { |
---|
1273 | temp->td_flags &= ~htole32(OHCI_TD_R); |
---|
1274 | } |
---|
1275 | |
---|
1276 | restart: |
---|
1277 | |
---|
1278 | td = temp->td; |
---|
1279 | td_next = temp->td_next; |
---|
1280 | |
---|
1281 | while (1) { |
---|
1282 | |
---|
1283 | if (temp->len == 0) { |
---|
1284 | |
---|
1285 | if (temp->shortpkt) { |
---|
1286 | break; |
---|
1287 | } |
---|
1288 | /* send a Zero Length Packet, ZLP, last */ |
---|
1289 | |
---|
1290 | temp->shortpkt = 1; |
---|
1291 | average = 0; |
---|
1292 | |
---|
1293 | } else { |
---|
1294 | |
---|
1295 | average = temp->average; |
---|
1296 | |
---|
1297 | if (temp->len < average) { |
---|
1298 | if (temp->len % temp->max_frame_size) { |
---|
1299 | temp->shortpkt = 1; |
---|
1300 | } |
---|
1301 | average = temp->len; |
---|
1302 | } |
---|
1303 | } |
---|
1304 | |
---|
1305 | if (td_next == NULL) { |
---|
1306 | panic("%s: out of OHCI transfer descriptors!", __FUNCTION__); |
---|
1307 | } |
---|
1308 | /* get next TD */ |
---|
1309 | |
---|
1310 | td = td_next; |
---|
1311 | td_next = td->obj_next; |
---|
1312 | |
---|
1313 | /* check if we are pre-computing */ |
---|
1314 | |
---|
1315 | if (precompute) { |
---|
1316 | |
---|
1317 | /* update remaining length */ |
---|
1318 | |
---|
1319 | temp->len -= average; |
---|
1320 | |
---|
1321 | continue; |
---|
1322 | } |
---|
1323 | /* fill out current TD */ |
---|
1324 | td->td_flags = temp->td_flags; |
---|
1325 | |
---|
1326 | /* the next TD uses TOGGLE_CARRY */ |
---|
1327 | temp->td_flags &= ~htole32(OHCI_TD_TOGGLE_MASK); |
---|
1328 | |
---|
1329 | if (average == 0) { |
---|
1330 | /* |
---|
1331 | * The buffer start and end phys addresses should be |
---|
1332 | * 0x0 for a zero length packet. |
---|
1333 | */ |
---|
1334 | td->td_cbp = 0; |
---|
1335 | td->td_be = 0; |
---|
1336 | td->len = 0; |
---|
1337 | |
---|
1338 | } else { |
---|
1339 | |
---|
1340 | usbd_get_page(temp->pc, buf_offset, &buf_res); |
---|
1341 | td->td_cbp = htole32(buf_res.physaddr); |
---|
1342 | buf_offset += (average - 1); |
---|
1343 | |
---|
1344 | usbd_get_page(temp->pc, buf_offset, &buf_res); |
---|
1345 | td->td_be = htole32(buf_res.physaddr); |
---|
1346 | buf_offset++; |
---|
1347 | |
---|
1348 | td->len = average; |
---|
1349 | |
---|
1350 | /* update remaining length */ |
---|
1351 | |
---|
1352 | temp->len -= average; |
---|
1353 | } |
---|
1354 | |
---|
1355 | if ((td_next == td_alt_next) && temp->setup_alt_next) { |
---|
1356 | /* we need to receive these frames one by one ! */ |
---|
1357 | td->td_flags &= htole32(~OHCI_TD_INTR_MASK); |
---|
1358 | td->td_flags |= htole32(OHCI_TD_SET_DI(1)); |
---|
1359 | td->td_next = htole32(OHCI_TD_NEXT_END); |
---|
1360 | } else { |
---|
1361 | if (td_next) { |
---|
1362 | /* link the current TD with the next one */ |
---|
1363 | td->td_next = td_next->td_self; |
---|
1364 | } |
---|
1365 | } |
---|
1366 | |
---|
1367 | td->alt_next = td_alt_next; |
---|
1368 | |
---|
1369 | usb_pc_cpu_flush(td->page_cache); |
---|
1370 | } |
---|
1371 | |
---|
1372 | if (precompute) { |
---|
1373 | precompute = 0; |
---|
1374 | |
---|
1375 | /* setup alt next pointer, if any */ |
---|
1376 | if (temp->last_frame) { |
---|
1377 | /* no alternate next */ |
---|
1378 | td_alt_next = NULL; |
---|
1379 | } else { |
---|
1380 | /* we use this field internally */ |
---|
1381 | td_alt_next = td_next; |
---|
1382 | } |
---|
1383 | |
---|
1384 | /* restore */ |
---|
1385 | temp->shortpkt = shortpkt_old; |
---|
1386 | temp->len = len_old; |
---|
1387 | goto restart; |
---|
1388 | } |
---|
1389 | temp->td = td; |
---|
1390 | temp->td_next = td_next; |
---|
1391 | } |
---|
1392 | |
---|
1393 | static void |
---|
1394 | ohci_setup_standard_chain(struct usb_xfer *xfer, ohci_ed_t **ed_last) |
---|
1395 | { |
---|
1396 | struct ohci_std_temp temp; |
---|
1397 | const struct usb_pipe_methods *methods; |
---|
1398 | ohci_ed_t *ed; |
---|
1399 | ohci_td_t *td; |
---|
1400 | uint32_t ed_flags; |
---|
1401 | uint32_t x; |
---|
1402 | |
---|
1403 | DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", |
---|
1404 | xfer->address, UE_GET_ADDR(xfer->endpointno), |
---|
1405 | xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); |
---|
1406 | |
---|
1407 | temp.average = xfer->max_hc_frame_size; |
---|
1408 | temp.max_frame_size = xfer->max_frame_size; |
---|
1409 | |
---|
1410 | /* toggle the DMA set we are using */ |
---|
1411 | xfer->flags_int.curr_dma_set ^= 1; |
---|
1412 | |
---|
1413 | /* get next DMA set */ |
---|
1414 | td = xfer->td_start[xfer->flags_int.curr_dma_set]; |
---|
1415 | |
---|
1416 | xfer->td_transfer_first = td; |
---|
1417 | xfer->td_transfer_cache = td; |
---|
1418 | |
---|
1419 | temp.td = NULL; |
---|
1420 | temp.td_next = td; |
---|
1421 | temp.last_frame = 0; |
---|
1422 | temp.setup_alt_next = xfer->flags_int.short_frames_ok; |
---|
1423 | |
---|
1424 | methods = xfer->endpoint->methods; |
---|
1425 | |
---|
1426 | /* check if we should prepend a setup message */ |
---|
1427 | |
---|
1428 | if (xfer->flags_int.control_xfr) { |
---|
1429 | if (xfer->flags_int.control_hdr) { |
---|
1430 | |
---|
1431 | temp.td_flags = htole32(OHCI_TD_SETUP | OHCI_TD_NOCC | |
---|
1432 | OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); |
---|
1433 | |
---|
1434 | temp.len = xfer->frlengths[0]; |
---|
1435 | temp.pc = xfer->frbuffers + 0; |
---|
1436 | temp.shortpkt = temp.len ? 1 : 0; |
---|
1437 | /* check for last frame */ |
---|
1438 | if (xfer->nframes == 1) { |
---|
1439 | /* no STATUS stage yet, SETUP is last */ |
---|
1440 | if (xfer->flags_int.control_act) { |
---|
1441 | temp.last_frame = 1; |
---|
1442 | temp.setup_alt_next = 0; |
---|
1443 | } |
---|
1444 | } |
---|
1445 | ohci_setup_standard_chain_sub(&temp); |
---|
1446 | |
---|
1447 | /* |
---|
1448 | * XXX assume that the setup message is |
---|
1449 | * contained within one USB packet: |
---|
1450 | */ |
---|
1451 | xfer->endpoint->toggle_next = 1; |
---|
1452 | } |
---|
1453 | x = 1; |
---|
1454 | } else { |
---|
1455 | x = 0; |
---|
1456 | } |
---|
1457 | temp.td_flags = htole32(OHCI_TD_NOCC | OHCI_TD_NOINTR); |
---|
1458 | |
---|
1459 | /* set data toggle */ |
---|
1460 | |
---|
1461 | if (xfer->endpoint->toggle_next) { |
---|
1462 | temp.td_flags |= htole32(OHCI_TD_TOGGLE_1); |
---|
1463 | } else { |
---|
1464 | temp.td_flags |= htole32(OHCI_TD_TOGGLE_0); |
---|
1465 | } |
---|
1466 | |
---|
1467 | /* set endpoint direction */ |
---|
1468 | |
---|
1469 | if (UE_GET_DIR(xfer->endpointno) == UE_DIR_IN) { |
---|
1470 | temp.td_flags |= htole32(OHCI_TD_IN); |
---|
1471 | } else { |
---|
1472 | temp.td_flags |= htole32(OHCI_TD_OUT); |
---|
1473 | } |
---|
1474 | |
---|
1475 | while (x != xfer->nframes) { |
---|
1476 | |
---|
1477 | /* DATA0 / DATA1 message */ |
---|
1478 | |
---|
1479 | temp.len = xfer->frlengths[x]; |
---|
1480 | temp.pc = xfer->frbuffers + x; |
---|
1481 | |
---|
1482 | x++; |
---|
1483 | |
---|
1484 | if (x == xfer->nframes) { |
---|
1485 | if (xfer->flags_int.control_xfr) { |
---|
1486 | /* no STATUS stage yet, DATA is last */ |
---|
1487 | if (xfer->flags_int.control_act) { |
---|
1488 | temp.last_frame = 1; |
---|
1489 | temp.setup_alt_next = 0; |
---|
1490 | } |
---|
1491 | } else { |
---|
1492 | temp.last_frame = 1; |
---|
1493 | temp.setup_alt_next = 0; |
---|
1494 | } |
---|
1495 | } |
---|
1496 | if (temp.len == 0) { |
---|
1497 | |
---|
1498 | /* make sure that we send an USB packet */ |
---|
1499 | |
---|
1500 | temp.shortpkt = 0; |
---|
1501 | |
---|
1502 | } else { |
---|
1503 | |
---|
1504 | /* regular data transfer */ |
---|
1505 | |
---|
1506 | temp.shortpkt = (xfer->flags.force_short_xfer) ? 0 : 1; |
---|
1507 | } |
---|
1508 | |
---|
1509 | ohci_setup_standard_chain_sub(&temp); |
---|
1510 | } |
---|
1511 | |
---|
1512 | /* check if we should append a status stage */ |
---|
1513 | |
---|
1514 | if (xfer->flags_int.control_xfr && |
---|
1515 | !xfer->flags_int.control_act) { |
---|
1516 | |
---|
1517 | /* |
---|
1518 | * Send a DATA1 message and invert the current endpoint |
---|
1519 | * direction. |
---|
1520 | */ |
---|
1521 | |
---|
1522 | /* set endpoint direction and data toggle */ |
---|
1523 | |
---|
1524 | if (UE_GET_DIR(xfer->endpointno) == UE_DIR_IN) { |
---|
1525 | temp.td_flags = htole32(OHCI_TD_OUT | |
---|
1526 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); |
---|
1527 | } else { |
---|
1528 | temp.td_flags = htole32(OHCI_TD_IN | |
---|
1529 | OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); |
---|
1530 | } |
---|
1531 | |
---|
1532 | temp.len = 0; |
---|
1533 | temp.pc = NULL; |
---|
1534 | temp.shortpkt = 0; |
---|
1535 | temp.last_frame = 1; |
---|
1536 | temp.setup_alt_next = 0; |
---|
1537 | |
---|
1538 | ohci_setup_standard_chain_sub(&temp); |
---|
1539 | } |
---|
1540 | td = temp.td; |
---|
1541 | |
---|
1542 | /* Ensure that last TD is terminating: */ |
---|
1543 | td->td_next = htole32(OHCI_TD_NEXT_END); |
---|
1544 | td->td_flags &= ~htole32(OHCI_TD_INTR_MASK); |
---|
1545 | td->td_flags |= htole32(OHCI_TD_SET_DI(1)); |
---|
1546 | |
---|
1547 | usb_pc_cpu_flush(td->page_cache); |
---|
1548 | |
---|
1549 | /* must have at least one frame! */ |
---|
1550 | |
---|
1551 | xfer->td_transfer_last = td; |
---|
1552 | |
---|
1553 | #ifdef USB_DEBUG |
---|
1554 | if (ohcidebug > 8) { |
---|
1555 | DPRINTF("nexttog=%d; data before transfer:\n", |
---|
1556 | xfer->endpoint->toggle_next); |
---|
1557 | ohci_dump_tds(xfer->td_transfer_first); |
---|
1558 | } |
---|
1559 | #endif |
---|
1560 | |
---|
1561 | ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; |
---|
1562 | |
---|
1563 | ed_flags = (OHCI_ED_SET_FA(xfer->address) | |
---|
1564 | OHCI_ED_SET_EN(UE_GET_ADDR(xfer->endpointno)) | |
---|
1565 | OHCI_ED_SET_MAXP(xfer->max_frame_size)); |
---|
1566 | |
---|
1567 | ed_flags |= (OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD); |
---|
1568 | |
---|
1569 | if (xfer->xroot->udev->speed == USB_SPEED_LOW) { |
---|
1570 | ed_flags |= OHCI_ED_SPEED; |
---|
1571 | } |
---|
1572 | ed->ed_flags = htole32(ed_flags); |
---|
1573 | |
---|
1574 | td = xfer->td_transfer_first; |
---|
1575 | |
---|
1576 | ed->ed_headp = td->td_self; |
---|
1577 | |
---|
1578 | if (xfer->xroot->udev->flags.self_suspended == 0) { |
---|
1579 | /* the append function will flush the endpoint descriptor */ |
---|
1580 | OHCI_APPEND_QH(ed, *ed_last); |
---|
1581 | |
---|
1582 | if (methods == &ohci_device_bulk_methods) { |
---|
1583 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1584 | |
---|
1585 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); |
---|
1586 | } |
---|
1587 | if (methods == &ohci_device_ctrl_methods) { |
---|
1588 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1589 | |
---|
1590 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); |
---|
1591 | } |
---|
1592 | } else { |
---|
1593 | usb_pc_cpu_flush(ed->page_cache); |
---|
1594 | } |
---|
1595 | } |
---|
1596 | |
---|
1597 | static void |
---|
1598 | ohci_root_intr(ohci_softc_t *sc) |
---|
1599 | { |
---|
1600 | uint32_t hstatus; |
---|
1601 | uint16_t i; |
---|
1602 | uint16_t m; |
---|
1603 | |
---|
1604 | USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); |
---|
1605 | |
---|
1606 | /* clear any old interrupt data */ |
---|
1607 | memset(sc->sc_hub_idata, 0, sizeof(sc->sc_hub_idata)); |
---|
1608 | |
---|
1609 | hstatus = OREAD4(sc, OHCI_RH_STATUS); |
---|
1610 | DPRINTF("sc=%p hstatus=0x%08x\n", |
---|
1611 | sc, hstatus); |
---|
1612 | |
---|
1613 | /* set bits */ |
---|
1614 | m = (sc->sc_noport + 1); |
---|
1615 | if (m > (8 * sizeof(sc->sc_hub_idata))) { |
---|
1616 | m = (8 * sizeof(sc->sc_hub_idata)); |
---|
1617 | } |
---|
1618 | for (i = 1; i < m; i++) { |
---|
1619 | /* pick out CHANGE bits from the status register */ |
---|
1620 | if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16) { |
---|
1621 | sc->sc_hub_idata[i / 8] |= 1 << (i % 8); |
---|
1622 | DPRINTF("port %d changed\n", i); |
---|
1623 | } |
---|
1624 | } |
---|
1625 | |
---|
1626 | uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, |
---|
1627 | sizeof(sc->sc_hub_idata)); |
---|
1628 | } |
---|
1629 | |
---|
1630 | /* NOTE: "done" can be run two times in a row, |
---|
1631 | * from close and from interrupt |
---|
1632 | */ |
---|
1633 | static void |
---|
1634 | ohci_device_done(struct usb_xfer *xfer, usb_error_t error) |
---|
1635 | { |
---|
1636 | const struct usb_pipe_methods *methods = xfer->endpoint->methods; |
---|
1637 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1638 | ohci_ed_t *ed; |
---|
1639 | |
---|
1640 | USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); |
---|
1641 | |
---|
1642 | |
---|
1643 | DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", |
---|
1644 | xfer, xfer->endpoint, error); |
---|
1645 | |
---|
1646 | ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; |
---|
1647 | if (ed) { |
---|
1648 | usb_pc_cpu_invalidate(ed->page_cache); |
---|
1649 | } |
---|
1650 | if (methods == &ohci_device_bulk_methods) { |
---|
1651 | OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last); |
---|
1652 | } |
---|
1653 | if (methods == &ohci_device_ctrl_methods) { |
---|
1654 | OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last); |
---|
1655 | } |
---|
1656 | if (methods == &ohci_device_intr_methods) { |
---|
1657 | OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); |
---|
1658 | } |
---|
1659 | if (methods == &ohci_device_isoc_methods) { |
---|
1660 | OHCI_REMOVE_QH(ed, sc->sc_isoc_p_last); |
---|
1661 | } |
---|
1662 | xfer->td_transfer_first = NULL; |
---|
1663 | xfer->td_transfer_last = NULL; |
---|
1664 | |
---|
1665 | /* dequeue transfer and start next transfer */ |
---|
1666 | usbd_transfer_done(xfer, error); |
---|
1667 | } |
---|
1668 | |
---|
1669 | /*------------------------------------------------------------------------* |
---|
1670 | * ohci bulk support |
---|
1671 | *------------------------------------------------------------------------*/ |
---|
1672 | static void |
---|
1673 | ohci_device_bulk_open(struct usb_xfer *xfer) |
---|
1674 | { |
---|
1675 | return; |
---|
1676 | } |
---|
1677 | |
---|
1678 | static void |
---|
1679 | ohci_device_bulk_close(struct usb_xfer *xfer) |
---|
1680 | { |
---|
1681 | ohci_device_done(xfer, USB_ERR_CANCELLED); |
---|
1682 | } |
---|
1683 | |
---|
1684 | static void |
---|
1685 | ohci_device_bulk_enter(struct usb_xfer *xfer) |
---|
1686 | { |
---|
1687 | return; |
---|
1688 | } |
---|
1689 | |
---|
1690 | static void |
---|
1691 | ohci_device_bulk_start(struct usb_xfer *xfer) |
---|
1692 | { |
---|
1693 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1694 | |
---|
1695 | /* setup TD's and QH */ |
---|
1696 | ohci_setup_standard_chain(xfer, &sc->sc_bulk_p_last); |
---|
1697 | |
---|
1698 | /* put transfer on interrupt queue */ |
---|
1699 | ohci_transfer_intr_enqueue(xfer); |
---|
1700 | } |
---|
1701 | |
---|
1702 | static const struct usb_pipe_methods ohci_device_bulk_methods = |
---|
1703 | { |
---|
1704 | .open = ohci_device_bulk_open, |
---|
1705 | .close = ohci_device_bulk_close, |
---|
1706 | .enter = ohci_device_bulk_enter, |
---|
1707 | .start = ohci_device_bulk_start, |
---|
1708 | }; |
---|
1709 | |
---|
1710 | /*------------------------------------------------------------------------* |
---|
1711 | * ohci control support |
---|
1712 | *------------------------------------------------------------------------*/ |
---|
1713 | static void |
---|
1714 | ohci_device_ctrl_open(struct usb_xfer *xfer) |
---|
1715 | { |
---|
1716 | return; |
---|
1717 | } |
---|
1718 | |
---|
1719 | static void |
---|
1720 | ohci_device_ctrl_close(struct usb_xfer *xfer) |
---|
1721 | { |
---|
1722 | ohci_device_done(xfer, USB_ERR_CANCELLED); |
---|
1723 | } |
---|
1724 | |
---|
1725 | static void |
---|
1726 | ohci_device_ctrl_enter(struct usb_xfer *xfer) |
---|
1727 | { |
---|
1728 | return; |
---|
1729 | } |
---|
1730 | |
---|
1731 | static void |
---|
1732 | ohci_device_ctrl_start(struct usb_xfer *xfer) |
---|
1733 | { |
---|
1734 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1735 | |
---|
1736 | /* setup TD's and QH */ |
---|
1737 | ohci_setup_standard_chain(xfer, &sc->sc_ctrl_p_last); |
---|
1738 | |
---|
1739 | /* put transfer on interrupt queue */ |
---|
1740 | ohci_transfer_intr_enqueue(xfer); |
---|
1741 | } |
---|
1742 | |
---|
1743 | static const struct usb_pipe_methods ohci_device_ctrl_methods = |
---|
1744 | { |
---|
1745 | .open = ohci_device_ctrl_open, |
---|
1746 | .close = ohci_device_ctrl_close, |
---|
1747 | .enter = ohci_device_ctrl_enter, |
---|
1748 | .start = ohci_device_ctrl_start, |
---|
1749 | }; |
---|
1750 | |
---|
1751 | /*------------------------------------------------------------------------* |
---|
1752 | * ohci interrupt support |
---|
1753 | *------------------------------------------------------------------------*/ |
---|
1754 | static void |
---|
1755 | ohci_device_intr_open(struct usb_xfer *xfer) |
---|
1756 | { |
---|
1757 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1758 | uint16_t best; |
---|
1759 | uint16_t bit; |
---|
1760 | uint16_t x; |
---|
1761 | |
---|
1762 | best = 0; |
---|
1763 | bit = OHCI_NO_EDS / 2; |
---|
1764 | while (bit) { |
---|
1765 | if (xfer->interval >= bit) { |
---|
1766 | x = bit; |
---|
1767 | best = bit; |
---|
1768 | while (x & bit) { |
---|
1769 | if (sc->sc_intr_stat[x] < |
---|
1770 | sc->sc_intr_stat[best]) { |
---|
1771 | best = x; |
---|
1772 | } |
---|
1773 | x++; |
---|
1774 | } |
---|
1775 | break; |
---|
1776 | } |
---|
1777 | bit >>= 1; |
---|
1778 | } |
---|
1779 | |
---|
1780 | sc->sc_intr_stat[best]++; |
---|
1781 | xfer->qh_pos = best; |
---|
1782 | |
---|
1783 | DPRINTFN(3, "best=%d interval=%d\n", |
---|
1784 | best, xfer->interval); |
---|
1785 | } |
---|
1786 | |
---|
1787 | static void |
---|
1788 | ohci_device_intr_close(struct usb_xfer *xfer) |
---|
1789 | { |
---|
1790 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1791 | |
---|
1792 | sc->sc_intr_stat[xfer->qh_pos]--; |
---|
1793 | |
---|
1794 | ohci_device_done(xfer, USB_ERR_CANCELLED); |
---|
1795 | } |
---|
1796 | |
---|
1797 | static void |
---|
1798 | ohci_device_intr_enter(struct usb_xfer *xfer) |
---|
1799 | { |
---|
1800 | return; |
---|
1801 | } |
---|
1802 | |
---|
1803 | static void |
---|
1804 | ohci_device_intr_start(struct usb_xfer *xfer) |
---|
1805 | { |
---|
1806 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1807 | |
---|
1808 | /* setup TD's and QH */ |
---|
1809 | ohci_setup_standard_chain(xfer, &sc->sc_intr_p_last[xfer->qh_pos]); |
---|
1810 | |
---|
1811 | /* put transfer on interrupt queue */ |
---|
1812 | ohci_transfer_intr_enqueue(xfer); |
---|
1813 | } |
---|
1814 | |
---|
1815 | static const struct usb_pipe_methods ohci_device_intr_methods = |
---|
1816 | { |
---|
1817 | .open = ohci_device_intr_open, |
---|
1818 | .close = ohci_device_intr_close, |
---|
1819 | .enter = ohci_device_intr_enter, |
---|
1820 | .start = ohci_device_intr_start, |
---|
1821 | }; |
---|
1822 | |
---|
1823 | /*------------------------------------------------------------------------* |
---|
1824 | * ohci isochronous support |
---|
1825 | *------------------------------------------------------------------------*/ |
---|
1826 | static void |
---|
1827 | ohci_device_isoc_open(struct usb_xfer *xfer) |
---|
1828 | { |
---|
1829 | return; |
---|
1830 | } |
---|
1831 | |
---|
1832 | static void |
---|
1833 | ohci_device_isoc_close(struct usb_xfer *xfer) |
---|
1834 | { |
---|
1835 | /**/ |
---|
1836 | ohci_device_done(xfer, USB_ERR_CANCELLED); |
---|
1837 | } |
---|
1838 | |
---|
1839 | static void |
---|
1840 | ohci_device_isoc_enter(struct usb_xfer *xfer) |
---|
1841 | { |
---|
1842 | struct usb_page_search buf_res; |
---|
1843 | ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); |
---|
1844 | struct ohci_hcca *hcca; |
---|
1845 | uint32_t buf_offset; |
---|
1846 | uint32_t nframes; |
---|
1847 | uint32_t ed_flags; |
---|
1848 | uint32_t *plen; |
---|
1849 | uint16_t itd_offset[OHCI_ITD_NOFFSET]; |
---|
1850 | uint16_t length; |
---|
1851 | uint8_t ncur; |
---|
1852 | ohci_itd_t *td; |
---|
1853 | ohci_itd_t *td_last = NULL; |
---|
1854 | ohci_ed_t *ed; |
---|
1855 | |
---|
1856 | hcca = ohci_get_hcca(sc); |
---|
1857 | |
---|
1858 | nframes = le32toh(hcca->hcca_frame_number); |
---|
1859 | |
---|
1860 | DPRINTFN(6, "xfer=%p isoc_next=%u nframes=%u hcca_fn=%u\n", |
---|
1861 | xfer, xfer->endpoint->isoc_next, xfer->nframes, nframes); |
---|
1862 | |
---|
1863 | if ((xfer->endpoint->is_synced == 0) || |
---|
1864 | (((nframes - xfer->endpoint->isoc_next) & 0xFFFF) < xfer->nframes) || |
---|
1865 | (((xfer->endpoint->isoc_next - nframes) & 0xFFFF) >= 128)) { |
---|
1866 | /* |
---|
1867 | * If there is data underflow or the pipe queue is empty we |
---|
1868 | * schedule the transfer a few frames ahead of the current |
---|
1869 | * frame position. Else two isochronous transfers might |
---|
1870 | * overlap. |
---|
1871 | */ |
---|
1872 | xfer->endpoint->isoc_next = (nframes + 3) & 0xFFFF; |
---|
1873 | xfer->endpoint->is_synced = 1; |
---|
1874 | DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); |
---|
1875 | } |
---|
1876 | /* |
---|
1877 | * compute how many milliseconds the insertion is ahead of the |
---|
1878 | * current frame position: |
---|
1879 | */ |
---|
1880 | buf_offset = ((xfer->endpoint->isoc_next - nframes) & 0xFFFF); |
---|
1881 | |
---|
1882 | /* |
---|
1883 | * pre-compute when the isochronous transfer will be finished: |
---|
1884 | */ |
---|
1885 | xfer->isoc_time_complete = |
---|
1886 | (usb_isoc_time_expand(&sc->sc_bus, nframes) + buf_offset + |
---|
1887 | xfer->nframes); |
---|
1888 | |
---|
1889 | /* get the real number of frames */ |
---|
1890 | |
---|
1891 | nframes = xfer->nframes; |
---|
1892 | |
---|
1893 | buf_offset = 0; |
---|
1894 | |
---|
1895 | plen = xfer->frlengths; |
---|
1896 | |
---|
1897 | /* toggle the DMA set we are using */ |
---|
1898 | xfer->flags_int.curr_dma_set ^= 1; |
---|
1899 | |
---|
1900 | /* get next DMA set */ |
---|
1901 | td = xfer->td_start[xfer->flags_int.curr_dma_set]; |
---|
1902 | |
---|
1903 | xfer->td_transfer_first = td; |
---|
1904 | |
---|
1905 | ncur = 0; |
---|
1906 | length = 0; |
---|
1907 | |
---|
1908 | while (nframes--) { |
---|
1909 | if (td == NULL) { |
---|
1910 | panic("%s:%d: out of TD's\n", |
---|
1911 | __FUNCTION__, __LINE__); |
---|
1912 | } |
---|
1913 | itd_offset[ncur] = length; |
---|
1914 | buf_offset += *plen; |
---|
1915 | length += *plen; |
---|
1916 | plen++; |
---|
1917 | ncur++; |
---|
1918 | |
---|
1919 | if ( /* check if the ITD is full */ |
---|
1920 | (ncur == OHCI_ITD_NOFFSET) || |
---|
1921 | /* check if we have put more than 4K into the ITD */ |
---|
1922 | (length & 0xF000) || |
---|
1923 | /* check if it is the last frame */ |
---|
1924 | (nframes == 0)) { |
---|
1925 | |
---|
1926 | /* fill current ITD */ |
---|
1927 | td->itd_flags = htole32( |
---|
1928 | OHCI_ITD_NOCC | |
---|
1929 | OHCI_ITD_SET_SF(xfer->endpoint->isoc_next) | |
---|
1930 | OHCI_ITD_NOINTR | |
---|
1931 | OHCI_ITD_SET_FC(ncur)); |
---|
1932 | |
---|
1933 | td->frames = ncur; |
---|
1934 | xfer->endpoint->isoc_next += ncur; |
---|
1935 | |
---|
1936 | if (length == 0) { |
---|
1937 | /* all zero */ |
---|
1938 | td->itd_bp0 = 0; |
---|
1939 | td->itd_be = ~0; |
---|
1940 | |
---|
1941 | while (ncur--) { |
---|
1942 | td->itd_offset[ncur] = |
---|
1943 | htole16(OHCI_ITD_MK_OFFS(0)); |
---|
1944 | } |
---|
1945 | } else { |
---|
1946 | usbd_get_page(xfer->frbuffers, buf_offset - length, &buf_res); |
---|
1947 | length = OHCI_PAGE_MASK(buf_res.physaddr); |
---|
1948 | buf_res.physaddr = |
---|
1949 | OHCI_PAGE(buf_res.physaddr); |
---|
1950 | td->itd_bp0 = htole32(buf_res.physaddr); |
---|
1951 | usbd_get_page(xfer->frbuffers, buf_offset - 1, &buf_res); |
---|
1952 | td->itd_be = htole32(buf_res.physaddr); |
---|
1953 | |
---|
1954 | while (ncur--) { |
---|
1955 | itd_offset[ncur] += length; |
---|
1956 | itd_offset[ncur] = |
---|
1957 | OHCI_ITD_MK_OFFS(itd_offset[ncur]); |
---|
1958 | td->itd_offset[ncur] = |
---|
1959 | htole16(itd_offset[ncur]); |
---|
1960 | } |
---|
1961 | } |
---|
1962 | ncur = 0; |
---|
1963 | length = 0; |
---|
1964 | td_last = td; |
---|
1965 | td = td->obj_next; |
---|
1966 | |
---|
1967 | if (td) { |
---|
1968 | /* link the last TD with the next one */ |
---|
1969 | td_last->itd_next = td->itd_self; |
---|
1970 | } |
---|
1971 | usb_pc_cpu_flush(td_last->page_cache); |
---|
1972 | } |
---|
1973 | } |
---|
1974 | |
---|
1975 | /* update the last TD */ |
---|
1976 | td_last->itd_flags &= ~htole32(OHCI_ITD_NOINTR); |
---|
1977 | td_last->itd_flags |= htole32(OHCI_ITD_SET_DI(0)); |
---|
1978 | td_last->itd_next = 0; |
---|
1979 | |
---|
1980 | usb_pc_cpu_flush(td_last->page_cache); |
---|
1981 | |
---|
1982 | xfer->td_transfer_last = td_last; |
---|
1983 | |
---|
1984 | #ifdef USB_DEBUG |
---|
1985 | if (ohcidebug > 8) { |
---|
1986 | DPRINTF("data before transfer:\n"); |
---|
1987 | ohci_dump_itds(xfer->td_transfer_first); |
---|
1988 | } |
---|
1989 | #endif |
---|
1990 | ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; |
---|
1991 | |
---|
1992 | if (UE_GET_DIR(xfer->endpointno) == UE_DIR_IN) |
---|
1993 | ed_flags = (OHCI_ED_DIR_IN | OHCI_ED_FORMAT_ISO); |
---|
1994 | else |
---|
1995 | ed_flags = (OHCI_ED_DIR_OUT | OHCI_ED_FORMAT_ISO); |
---|
1996 | |
---|
1997 | ed_flags |= (OHCI_ED_SET_FA(xfer->address) | |
---|
1998 | OHCI_ED_SET_EN(UE_GET_ADDR(xfer->endpointno)) | |
---|
1999 | OHCI_ED_SET_MAXP(xfer->max_frame_size)); |
---|
2000 | |
---|
2001 | if (xfer->xroot->udev->speed == USB_SPEED_LOW) { |
---|
2002 | ed_flags |= OHCI_ED_SPEED; |
---|
2003 | } |
---|
2004 | ed->ed_flags = htole32(ed_flags); |
---|
2005 | |
---|
2006 | td = xfer->td_transfer_first; |
---|
2007 | |
---|
2008 | ed->ed_headp = td->itd_self; |
---|
2009 | |
---|
2010 | /* isochronous transfers are not affected by suspend / resume */ |
---|
2011 | /* the append function will flush the endpoint descriptor */ |
---|
2012 | |
---|
2013 | OHCI_APPEND_QH(ed, sc->sc_isoc_p_last); |
---|
2014 | } |
---|
2015 | |
---|
2016 | static void |
---|
2017 | ohci_device_isoc_start(struct usb_xfer *xfer) |
---|
2018 | { |
---|
2019 | /* put transfer on interrupt queue */ |
---|
2020 | ohci_transfer_intr_enqueue(xfer); |
---|
2021 | } |
---|
2022 | |
---|
2023 | static const struct usb_pipe_methods ohci_device_isoc_methods = |
---|
2024 | { |
---|
2025 | .open = ohci_device_isoc_open, |
---|
2026 | .close = ohci_device_isoc_close, |
---|
2027 | .enter = ohci_device_isoc_enter, |
---|
2028 | .start = ohci_device_isoc_start, |
---|
2029 | }; |
---|
2030 | |
---|
2031 | /*------------------------------------------------------------------------* |
---|
2032 | * ohci root control support |
---|
2033 | *------------------------------------------------------------------------* |
---|
2034 | * Simulate a hardware hub by handling all the necessary requests. |
---|
2035 | *------------------------------------------------------------------------*/ |
---|
2036 | |
---|
2037 | static const |
---|
2038 | struct usb_device_descriptor ohci_devd = |
---|
2039 | { |
---|
2040 | sizeof(struct usb_device_descriptor), |
---|
2041 | UDESC_DEVICE, /* type */ |
---|
2042 | {0x00, 0x01}, /* USB version */ |
---|
2043 | UDCLASS_HUB, /* class */ |
---|
2044 | UDSUBCLASS_HUB, /* subclass */ |
---|
2045 | UDPROTO_FSHUB, /* protocol */ |
---|
2046 | 64, /* max packet */ |
---|
2047 | {0}, {0}, {0x00, 0x01}, /* device id */ |
---|
2048 | 1, 2, 0, /* string indexes */ |
---|
2049 | 1 /* # of configurations */ |
---|
2050 | }; |
---|
2051 | |
---|
2052 | static const |
---|
2053 | struct ohci_config_desc ohci_confd = |
---|
2054 | { |
---|
2055 | .confd = { |
---|
2056 | .bLength = sizeof(struct usb_config_descriptor), |
---|
2057 | .bDescriptorType = UDESC_CONFIG, |
---|
2058 | .wTotalLength[0] = sizeof(ohci_confd), |
---|
2059 | .bNumInterface = 1, |
---|
2060 | .bConfigurationValue = 1, |
---|
2061 | .iConfiguration = 0, |
---|
2062 | .bmAttributes = UC_SELF_POWERED, |
---|
2063 | .bMaxPower = 0, /* max power */ |
---|
2064 | }, |
---|
2065 | .ifcd = { |
---|
2066 | .bLength = sizeof(struct usb_interface_descriptor), |
---|
2067 | .bDescriptorType = UDESC_INTERFACE, |
---|
2068 | .bNumEndpoints = 1, |
---|
2069 | .bInterfaceClass = UICLASS_HUB, |
---|
2070 | .bInterfaceSubClass = UISUBCLASS_HUB, |
---|
2071 | .bInterfaceProtocol = 0, |
---|
2072 | }, |
---|
2073 | .endpd = { |
---|
2074 | .bLength = sizeof(struct usb_endpoint_descriptor), |
---|
2075 | .bDescriptorType = UDESC_ENDPOINT, |
---|
2076 | .bEndpointAddress = UE_DIR_IN | OHCI_INTR_ENDPT, |
---|
2077 | .bmAttributes = UE_INTERRUPT, |
---|
2078 | .wMaxPacketSize[0] = 32,/* max packet (255 ports) */ |
---|
2079 | .bInterval = 255, |
---|
2080 | }, |
---|
2081 | }; |
---|
2082 | |
---|
2083 | static const |
---|
2084 | struct usb_hub_descriptor ohci_hubd = |
---|
2085 | { |
---|
2086 | .bDescLength = 0, /* dynamic length */ |
---|
2087 | .bDescriptorType = UDESC_HUB, |
---|
2088 | }; |
---|
2089 | |
---|
2090 | static usb_error_t |
---|
2091 | ohci_roothub_exec(struct usb_device *udev, |
---|
2092 | struct usb_device_request *req, const void **pptr, uint16_t *plength) |
---|
2093 | { |
---|
2094 | ohci_softc_t *sc = OHCI_BUS2SC(udev->bus); |
---|
2095 | const void *ptr; |
---|
2096 | const char *str_ptr; |
---|
2097 | uint32_t port; |
---|
2098 | uint32_t v; |
---|
2099 | uint16_t len; |
---|
2100 | uint16_t value; |
---|
2101 | uint16_t index; |
---|
2102 | uint8_t l; |
---|
2103 | usb_error_t err; |
---|
2104 | |
---|
2105 | USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); |
---|
2106 | |
---|
2107 | /* buffer reset */ |
---|
2108 | ptr = (const void *)&sc->sc_hub_desc.temp; |
---|
2109 | len = 0; |
---|
2110 | err = 0; |
---|
2111 | |
---|
2112 | value = UGETW(req->wValue); |
---|
2113 | index = UGETW(req->wIndex); |
---|
2114 | |
---|
2115 | DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " |
---|
2116 | "wValue=0x%04x wIndex=0x%04x\n", |
---|
2117 | req->bmRequestType, req->bRequest, |
---|
2118 | UGETW(req->wLength), value, index); |
---|
2119 | |
---|
2120 | #define C(x,y) ((x) | ((y) << 8)) |
---|
2121 | switch (C(req->bRequest, req->bmRequestType)) { |
---|
2122 | case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): |
---|
2123 | case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): |
---|
2124 | case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): |
---|
2125 | /* |
---|
2126 | * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops |
---|
2127 | * for the integrated root hub. |
---|
2128 | */ |
---|
2129 | break; |
---|
2130 | case C(UR_GET_CONFIG, UT_READ_DEVICE): |
---|
2131 | len = 1; |
---|
2132 | sc->sc_hub_desc.temp[0] = sc->sc_conf; |
---|
2133 | break; |
---|
2134 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): |
---|
2135 | switch (value >> 8) { |
---|
2136 | case UDESC_DEVICE: |
---|
2137 | if ((value & 0xff) != 0) { |
---|
2138 | err = USB_ERR_IOERROR; |
---|
2139 | goto done; |
---|
2140 | } |
---|
2141 | len = sizeof(ohci_devd); |
---|
2142 | ptr = (const void *)&ohci_devd; |
---|
2143 | break; |
---|
2144 | |
---|
2145 | case UDESC_CONFIG: |
---|
2146 | if ((value & 0xff) != 0) { |
---|
2147 | err = USB_ERR_IOERROR; |
---|
2148 | goto done; |
---|
2149 | } |
---|
2150 | len = sizeof(ohci_confd); |
---|
2151 | ptr = (const void *)&ohci_confd; |
---|
2152 | break; |
---|
2153 | |
---|
2154 | case UDESC_STRING: |
---|
2155 | switch (value & 0xff) { |
---|
2156 | case 0: /* Language table */ |
---|
2157 | str_ptr = "\001"; |
---|
2158 | break; |
---|
2159 | |
---|
2160 | case 1: /* Vendor */ |
---|
2161 | str_ptr = sc->sc_vendor; |
---|
2162 | break; |
---|
2163 | |
---|
2164 | case 2: /* Product */ |
---|
2165 | str_ptr = "OHCI root HUB"; |
---|
2166 | break; |
---|
2167 | |
---|
2168 | default: |
---|
2169 | str_ptr = ""; |
---|
2170 | break; |
---|
2171 | } |
---|
2172 | |
---|
2173 | len = usb_make_str_desc( |
---|
2174 | sc->sc_hub_desc.temp, |
---|
2175 | sizeof(sc->sc_hub_desc.temp), |
---|
2176 | str_ptr); |
---|
2177 | break; |
---|
2178 | |
---|
2179 | default: |
---|
2180 | err = USB_ERR_IOERROR; |
---|
2181 | goto done; |
---|
2182 | } |
---|
2183 | break; |
---|
2184 | case C(UR_GET_INTERFACE, UT_READ_INTERFACE): |
---|
2185 | len = 1; |
---|
2186 | sc->sc_hub_desc.temp[0] = 0; |
---|
2187 | break; |
---|
2188 | case C(UR_GET_STATUS, UT_READ_DEVICE): |
---|
2189 | len = 2; |
---|
2190 | USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); |
---|
2191 | break; |
---|
2192 | case C(UR_GET_STATUS, UT_READ_INTERFACE): |
---|
2193 | case C(UR_GET_STATUS, UT_READ_ENDPOINT): |
---|
2194 | len = 2; |
---|
2195 | USETW(sc->sc_hub_desc.stat.wStatus, 0); |
---|
2196 | break; |
---|
2197 | case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): |
---|
2198 | if (value >= OHCI_MAX_DEVICES) { |
---|
2199 | err = USB_ERR_IOERROR; |
---|
2200 | goto done; |
---|
2201 | } |
---|
2202 | sc->sc_addr = value; |
---|
2203 | break; |
---|
2204 | case C(UR_SET_CONFIG, UT_WRITE_DEVICE): |
---|
2205 | if ((value != 0) && (value != 1)) { |
---|
2206 | err = USB_ERR_IOERROR; |
---|
2207 | goto done; |
---|
2208 | } |
---|
2209 | sc->sc_conf = value; |
---|
2210 | break; |
---|
2211 | case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): |
---|
2212 | break; |
---|
2213 | case C(UR_SET_FEATURE, UT_WRITE_DEVICE): |
---|
2214 | case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): |
---|
2215 | case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): |
---|
2216 | err = USB_ERR_IOERROR; |
---|
2217 | goto done; |
---|
2218 | case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): |
---|
2219 | break; |
---|
2220 | case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): |
---|
2221 | break; |
---|
2222 | /* Hub requests */ |
---|
2223 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): |
---|
2224 | break; |
---|
2225 | case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): |
---|
2226 | DPRINTFN(9, "UR_CLEAR_PORT_FEATURE " |
---|
2227 | "port=%d feature=%d\n", |
---|
2228 | index, value); |
---|
2229 | if ((index < 1) || |
---|
2230 | (index > sc->sc_noport)) { |
---|
2231 | err = USB_ERR_IOERROR; |
---|
2232 | goto done; |
---|
2233 | } |
---|
2234 | port = OHCI_RH_PORT_STATUS(index); |
---|
2235 | switch (value) { |
---|
2236 | case UHF_PORT_ENABLE: |
---|
2237 | OWRITE4(sc, port, UPS_CURRENT_CONNECT_STATUS); |
---|
2238 | break; |
---|
2239 | case UHF_PORT_SUSPEND: |
---|
2240 | OWRITE4(sc, port, UPS_OVERCURRENT_INDICATOR); |
---|
2241 | break; |
---|
2242 | case UHF_PORT_POWER: |
---|
2243 | /* Yes, writing to the LOW_SPEED bit clears power. */ |
---|
2244 | OWRITE4(sc, port, UPS_LOW_SPEED); |
---|
2245 | break; |
---|
2246 | case UHF_C_PORT_CONNECTION: |
---|
2247 | OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16); |
---|
2248 | break; |
---|
2249 | case UHF_C_PORT_ENABLE: |
---|
2250 | OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16); |
---|
2251 | break; |
---|
2252 | case UHF_C_PORT_SUSPEND: |
---|
2253 | OWRITE4(sc, port, UPS_C_SUSPEND << 16); |
---|
2254 | break; |
---|
2255 | case UHF_C_PORT_OVER_CURRENT: |
---|
2256 | OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16); |
---|
2257 | break; |
---|
2258 | case UHF_C_PORT_RESET: |
---|
2259 | OWRITE4(sc, port, UPS_C_PORT_RESET << 16); |
---|
2260 | break; |
---|
2261 | default: |
---|
2262 | err = USB_ERR_IOERROR; |
---|
2263 | goto done; |
---|
2264 | } |
---|
2265 | switch (value) { |
---|
2266 | case UHF_C_PORT_CONNECTION: |
---|
2267 | case UHF_C_PORT_ENABLE: |
---|
2268 | case UHF_C_PORT_SUSPEND: |
---|
2269 | case UHF_C_PORT_OVER_CURRENT: |
---|
2270 | case UHF_C_PORT_RESET: |
---|
2271 | /* enable RHSC interrupt if condition is cleared. */ |
---|
2272 | if ((OREAD4(sc, port) >> 16) == 0) |
---|
2273 | ohci_rhsc_enable(sc); |
---|
2274 | break; |
---|
2275 | default: |
---|
2276 | break; |
---|
2277 | } |
---|
2278 | break; |
---|
2279 | case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): |
---|
2280 | if ((value & 0xff) != 0) { |
---|
2281 | err = USB_ERR_IOERROR; |
---|
2282 | goto done; |
---|
2283 | } |
---|
2284 | v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); |
---|
2285 | |
---|
2286 | sc->sc_hub_desc.hubd = ohci_hubd; |
---|
2287 | sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport; |
---|
2288 | USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, |
---|
2289 | (v & OHCI_NPS ? UHD_PWR_NO_SWITCH : |
---|
2290 | v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL) |
---|
2291 | /* XXX overcurrent */ |
---|
2292 | ); |
---|
2293 | sc->sc_hub_desc.hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v); |
---|
2294 | v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); |
---|
2295 | |
---|
2296 | for (l = 0; l < sc->sc_noport; l++) { |
---|
2297 | if (v & 1) { |
---|
2298 | sc->sc_hub_desc.hubd.DeviceRemovable[l / 8] |= (1 << (l % 8)); |
---|
2299 | } |
---|
2300 | v >>= 1; |
---|
2301 | } |
---|
2302 | sc->sc_hub_desc.hubd.bDescLength = |
---|
2303 | 8 + ((sc->sc_noport + 7) / 8); |
---|
2304 | len = sc->sc_hub_desc.hubd.bDescLength; |
---|
2305 | break; |
---|
2306 | |
---|
2307 | case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): |
---|
2308 | len = 16; |
---|
2309 | memset(sc->sc_hub_desc.temp, 0, 16); |
---|
2310 | break; |
---|
2311 | case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): |
---|
2312 | DPRINTFN(9, "get port status i=%d\n", |
---|
2313 | index); |
---|
2314 | if ((index < 1) || |
---|
2315 | (index > sc->sc_noport)) { |
---|
2316 | err = USB_ERR_IOERROR; |
---|
2317 | goto done; |
---|
2318 | } |
---|
2319 | v = OREAD4(sc, OHCI_RH_PORT_STATUS(index)); |
---|
2320 | DPRINTFN(9, "port status=0x%04x\n", v); |
---|
2321 | v &= ~UPS_PORT_MODE_DEVICE; /* force host mode */ |
---|
2322 | USETW(sc->sc_hub_desc.ps.wPortStatus, v); |
---|
2323 | USETW(sc->sc_hub_desc.ps.wPortChange, v >> 16); |
---|
2324 | len = sizeof(sc->sc_hub_desc.ps); |
---|
2325 | break; |
---|
2326 | case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): |
---|
2327 | err = USB_ERR_IOERROR; |
---|
2328 | goto done; |
---|
2329 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): |
---|
2330 | break; |
---|
2331 | case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): |
---|
2332 | if ((index < 1) || |
---|
2333 | (index > sc->sc_noport)) { |
---|
2334 | err = USB_ERR_IOERROR; |
---|
2335 | goto done; |
---|
2336 | } |
---|
2337 | port = OHCI_RH_PORT_STATUS(index); |
---|
2338 | switch (value) { |
---|
2339 | case UHF_PORT_ENABLE: |
---|
2340 | OWRITE4(sc, port, UPS_PORT_ENABLED); |
---|
2341 | break; |
---|
2342 | case UHF_PORT_SUSPEND: |
---|
2343 | OWRITE4(sc, port, UPS_SUSPEND); |
---|
2344 | break; |
---|
2345 | case UHF_PORT_RESET: |
---|
2346 | DPRINTFN(6, "reset port %d\n", index); |
---|
2347 | OWRITE4(sc, port, UPS_RESET); |
---|
2348 | for (v = 0;; v++) { |
---|
2349 | if (v < 12) { |
---|
2350 | usb_pause_mtx(&sc->sc_bus.bus_mtx, |
---|
2351 | USB_MS_TO_TICKS(usb_port_root_reset_delay)); |
---|
2352 | |
---|
2353 | if ((OREAD4(sc, port) & UPS_RESET) == 0) { |
---|
2354 | break; |
---|
2355 | } |
---|
2356 | } else { |
---|
2357 | err = USB_ERR_TIMEOUT; |
---|
2358 | goto done; |
---|
2359 | } |
---|
2360 | } |
---|
2361 | DPRINTFN(9, "ohci port %d reset, status = 0x%04x\n", |
---|
2362 | index, OREAD4(sc, port)); |
---|
2363 | break; |
---|
2364 | case UHF_PORT_POWER: |
---|
2365 | DPRINTFN(3, "set port power %d\n", index); |
---|
2366 | OWRITE4(sc, port, UPS_PORT_POWER); |
---|
2367 | break; |
---|
2368 | default: |
---|
2369 | err = USB_ERR_IOERROR; |
---|
2370 | goto done; |
---|
2371 | } |
---|
2372 | break; |
---|
2373 | default: |
---|
2374 | err = USB_ERR_IOERROR; |
---|
2375 | goto done; |
---|
2376 | } |
---|
2377 | done: |
---|
2378 | *plength = len; |
---|
2379 | *pptr = ptr; |
---|
2380 | return (err); |
---|
2381 | } |
---|
2382 | |
---|
2383 | static void |
---|
2384 | ohci_xfer_setup(struct usb_setup_params *parm) |
---|
2385 | { |
---|
2386 | struct usb_page_search page_info; |
---|
2387 | struct usb_page_cache *pc; |
---|
2388 | ohci_softc_t *sc; |
---|
2389 | struct usb_xfer *xfer; |
---|
2390 | void *last_obj; |
---|
2391 | uint32_t ntd; |
---|
2392 | uint32_t nitd; |
---|
2393 | uint32_t nqh; |
---|
2394 | uint32_t n; |
---|
2395 | |
---|
2396 | sc = OHCI_BUS2SC(parm->udev->bus); |
---|
2397 | xfer = parm->curr_xfer; |
---|
2398 | |
---|
2399 | parm->hc_max_packet_size = 0x500; |
---|
2400 | parm->hc_max_packet_count = 1; |
---|
2401 | parm->hc_max_frame_size = OHCI_PAGE_SIZE; |
---|
2402 | |
---|
2403 | /* |
---|
2404 | * calculate ntd and nqh |
---|
2405 | */ |
---|
2406 | if (parm->methods == &ohci_device_ctrl_methods) { |
---|
2407 | xfer->flags_int.bdma_enable = 1; |
---|
2408 | |
---|
2409 | usbd_transfer_setup_sub(parm); |
---|
2410 | |
---|
2411 | nitd = 0; |
---|
2412 | ntd = ((2 * xfer->nframes) + 1 /* STATUS */ |
---|
2413 | + (xfer->max_data_length / xfer->max_hc_frame_size)); |
---|
2414 | nqh = 1; |
---|
2415 | |
---|
2416 | } else if (parm->methods == &ohci_device_bulk_methods) { |
---|
2417 | xfer->flags_int.bdma_enable = 1; |
---|
2418 | |
---|
2419 | usbd_transfer_setup_sub(parm); |
---|
2420 | |
---|
2421 | nitd = 0; |
---|
2422 | ntd = ((2 * xfer->nframes) |
---|
2423 | + (xfer->max_data_length / xfer->max_hc_frame_size)); |
---|
2424 | nqh = 1; |
---|
2425 | |
---|
2426 | } else if (parm->methods == &ohci_device_intr_methods) { |
---|
2427 | xfer->flags_int.bdma_enable = 1; |
---|
2428 | |
---|
2429 | usbd_transfer_setup_sub(parm); |
---|
2430 | |
---|
2431 | nitd = 0; |
---|
2432 | ntd = ((2 * xfer->nframes) |
---|
2433 | + (xfer->max_data_length / xfer->max_hc_frame_size)); |
---|
2434 | nqh = 1; |
---|
2435 | |
---|
2436 | } else if (parm->methods == &ohci_device_isoc_methods) { |
---|
2437 | xfer->flags_int.bdma_enable = 1; |
---|
2438 | |
---|
2439 | usbd_transfer_setup_sub(parm); |
---|
2440 | |
---|
2441 | nitd = ((xfer->max_data_length / OHCI_PAGE_SIZE) + |
---|
2442 | howmany(xfer->nframes, OHCI_ITD_NOFFSET) + |
---|
2443 | 1 /* EXTRA */ ); |
---|
2444 | ntd = 0; |
---|
2445 | nqh = 1; |
---|
2446 | |
---|
2447 | } else { |
---|
2448 | |
---|
2449 | usbd_transfer_setup_sub(parm); |
---|
2450 | |
---|
2451 | nitd = 0; |
---|
2452 | ntd = 0; |
---|
2453 | nqh = 0; |
---|
2454 | } |
---|
2455 | |
---|
2456 | alloc_dma_set: |
---|
2457 | |
---|
2458 | if (parm->err) { |
---|
2459 | return; |
---|
2460 | } |
---|
2461 | last_obj = NULL; |
---|
2462 | |
---|
2463 | if (usbd_transfer_setup_sub_malloc( |
---|
2464 | parm, &pc, sizeof(ohci_td_t), |
---|
2465 | OHCI_TD_ALIGN, ntd)) { |
---|
2466 | parm->err = USB_ERR_NOMEM; |
---|
2467 | return; |
---|
2468 | } |
---|
2469 | if (parm->buf) { |
---|
2470 | for (n = 0; n != ntd; n++) { |
---|
2471 | ohci_td_t *td; |
---|
2472 | |
---|
2473 | usbd_get_page(pc + n, 0, &page_info); |
---|
2474 | |
---|
2475 | td = page_info.buffer; |
---|
2476 | |
---|
2477 | /* init TD */ |
---|
2478 | td->td_self = htole32(page_info.physaddr); |
---|
2479 | td->obj_next = last_obj; |
---|
2480 | td->page_cache = pc + n; |
---|
2481 | |
---|
2482 | last_obj = td; |
---|
2483 | |
---|
2484 | usb_pc_cpu_flush(pc + n); |
---|
2485 | } |
---|
2486 | } |
---|
2487 | if (usbd_transfer_setup_sub_malloc( |
---|
2488 | parm, &pc, sizeof(ohci_itd_t), |
---|
2489 | OHCI_ITD_ALIGN, nitd)) { |
---|
2490 | parm->err = USB_ERR_NOMEM; |
---|
2491 | return; |
---|
2492 | } |
---|
2493 | if (parm->buf) { |
---|
2494 | for (n = 0; n != nitd; n++) { |
---|
2495 | ohci_itd_t *itd; |
---|
2496 | |
---|
2497 | usbd_get_page(pc + n, 0, &page_info); |
---|
2498 | |
---|
2499 | itd = page_info.buffer; |
---|
2500 | |
---|
2501 | /* init TD */ |
---|
2502 | itd->itd_self = htole32(page_info.physaddr); |
---|
2503 | itd->obj_next = last_obj; |
---|
2504 | itd->page_cache = pc + n; |
---|
2505 | |
---|
2506 | last_obj = itd; |
---|
2507 | |
---|
2508 | usb_pc_cpu_flush(pc + n); |
---|
2509 | } |
---|
2510 | } |
---|
2511 | xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; |
---|
2512 | |
---|
2513 | last_obj = NULL; |
---|
2514 | |
---|
2515 | if (usbd_transfer_setup_sub_malloc( |
---|
2516 | parm, &pc, sizeof(ohci_ed_t), |
---|
2517 | OHCI_ED_ALIGN, nqh)) { |
---|
2518 | parm->err = USB_ERR_NOMEM; |
---|
2519 | return; |
---|
2520 | } |
---|
2521 | if (parm->buf) { |
---|
2522 | for (n = 0; n != nqh; n++) { |
---|
2523 | ohci_ed_t *ed; |
---|
2524 | |
---|
2525 | usbd_get_page(pc + n, 0, &page_info); |
---|
2526 | |
---|
2527 | ed = page_info.buffer; |
---|
2528 | |
---|
2529 | /* init QH */ |
---|
2530 | ed->ed_self = htole32(page_info.physaddr); |
---|
2531 | ed->obj_next = last_obj; |
---|
2532 | ed->page_cache = pc + n; |
---|
2533 | |
---|
2534 | last_obj = ed; |
---|
2535 | |
---|
2536 | usb_pc_cpu_flush(pc + n); |
---|
2537 | } |
---|
2538 | } |
---|
2539 | xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj; |
---|
2540 | |
---|
2541 | if (!xfer->flags_int.curr_dma_set) { |
---|
2542 | xfer->flags_int.curr_dma_set = 1; |
---|
2543 | goto alloc_dma_set; |
---|
2544 | } |
---|
2545 | } |
---|
2546 | |
---|
2547 | static void |
---|
2548 | ohci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, |
---|
2549 | struct usb_endpoint *ep) |
---|
2550 | { |
---|
2551 | ohci_softc_t *sc = OHCI_BUS2SC(udev->bus); |
---|
2552 | |
---|
2553 | DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n", |
---|
2554 | ep, udev->address, |
---|
2555 | edesc->bEndpointAddress, udev->flags.usb_mode, |
---|
2556 | sc->sc_addr); |
---|
2557 | |
---|
2558 | if (udev->device_index != sc->sc_addr) { |
---|
2559 | switch (edesc->bmAttributes & UE_XFERTYPE) { |
---|
2560 | case UE_CONTROL: |
---|
2561 | ep->methods = &ohci_device_ctrl_methods; |
---|
2562 | break; |
---|
2563 | case UE_INTERRUPT: |
---|
2564 | ep->methods = &ohci_device_intr_methods; |
---|
2565 | break; |
---|
2566 | case UE_ISOCHRONOUS: |
---|
2567 | if (udev->speed == USB_SPEED_FULL) { |
---|
2568 | ep->methods = &ohci_device_isoc_methods; |
---|
2569 | } |
---|
2570 | break; |
---|
2571 | case UE_BULK: |
---|
2572 | ep->methods = &ohci_device_bulk_methods; |
---|
2573 | break; |
---|
2574 | default: |
---|
2575 | /* do nothing */ |
---|
2576 | break; |
---|
2577 | } |
---|
2578 | } |
---|
2579 | } |
---|
2580 | |
---|
2581 | static void |
---|
2582 | ohci_xfer_unsetup(struct usb_xfer *xfer) |
---|
2583 | { |
---|
2584 | return; |
---|
2585 | } |
---|
2586 | |
---|
2587 | static void |
---|
2588 | ohci_get_dma_delay(struct usb_device *udev, uint32_t *pus) |
---|
2589 | { |
---|
2590 | /* |
---|
2591 | * Wait until hardware has finished any possible use of the |
---|
2592 | * transfer descriptor(s) and QH |
---|
2593 | */ |
---|
2594 | *pus = (1125); /* microseconds */ |
---|
2595 | } |
---|
2596 | |
---|
2597 | static void |
---|
2598 | ohci_device_resume(struct usb_device *udev) |
---|
2599 | { |
---|
2600 | struct ohci_softc *sc = OHCI_BUS2SC(udev->bus); |
---|
2601 | struct usb_xfer *xfer; |
---|
2602 | const struct usb_pipe_methods *methods; |
---|
2603 | ohci_ed_t *ed; |
---|
2604 | |
---|
2605 | DPRINTF("\n"); |
---|
2606 | |
---|
2607 | USB_BUS_LOCK(udev->bus); |
---|
2608 | |
---|
2609 | TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { |
---|
2610 | |
---|
2611 | if (xfer->xroot->udev == udev) { |
---|
2612 | |
---|
2613 | methods = xfer->endpoint->methods; |
---|
2614 | ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; |
---|
2615 | |
---|
2616 | if (methods == &ohci_device_bulk_methods) { |
---|
2617 | OHCI_APPEND_QH(ed, sc->sc_bulk_p_last); |
---|
2618 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); |
---|
2619 | } |
---|
2620 | if (methods == &ohci_device_ctrl_methods) { |
---|
2621 | OHCI_APPEND_QH(ed, sc->sc_ctrl_p_last); |
---|
2622 | OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); |
---|
2623 | } |
---|
2624 | if (methods == &ohci_device_intr_methods) { |
---|
2625 | OHCI_APPEND_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); |
---|
2626 | } |
---|
2627 | } |
---|
2628 | } |
---|
2629 | |
---|
2630 | USB_BUS_UNLOCK(udev->bus); |
---|
2631 | |
---|
2632 | return; |
---|
2633 | } |
---|
2634 | |
---|
2635 | static void |
---|
2636 | ohci_device_suspend(struct usb_device *udev) |
---|
2637 | { |
---|
2638 | struct ohci_softc *sc = OHCI_BUS2SC(udev->bus); |
---|
2639 | struct usb_xfer *xfer; |
---|
2640 | const struct usb_pipe_methods *methods; |
---|
2641 | ohci_ed_t *ed; |
---|
2642 | |
---|
2643 | DPRINTF("\n"); |
---|
2644 | |
---|
2645 | USB_BUS_LOCK(udev->bus); |
---|
2646 | |
---|
2647 | TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { |
---|
2648 | |
---|
2649 | if (xfer->xroot->udev == udev) { |
---|
2650 | |
---|
2651 | methods = xfer->endpoint->methods; |
---|
2652 | ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; |
---|
2653 | |
---|
2654 | if (methods == &ohci_device_bulk_methods) { |
---|
2655 | OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last); |
---|
2656 | } |
---|
2657 | if (methods == &ohci_device_ctrl_methods) { |
---|
2658 | OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last); |
---|
2659 | } |
---|
2660 | if (methods == &ohci_device_intr_methods) { |
---|
2661 | OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); |
---|
2662 | } |
---|
2663 | } |
---|
2664 | } |
---|
2665 | |
---|
2666 | USB_BUS_UNLOCK(udev->bus); |
---|
2667 | |
---|
2668 | return; |
---|
2669 | } |
---|
2670 | |
---|
2671 | static void |
---|
2672 | ohci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) |
---|
2673 | { |
---|
2674 | struct ohci_softc *sc = OHCI_BUS2SC(bus); |
---|
2675 | |
---|
2676 | switch (state) { |
---|
2677 | case USB_HW_POWER_SUSPEND: |
---|
2678 | case USB_HW_POWER_SHUTDOWN: |
---|
2679 | ohci_suspend(sc); |
---|
2680 | break; |
---|
2681 | case USB_HW_POWER_RESUME: |
---|
2682 | ohci_resume(sc); |
---|
2683 | break; |
---|
2684 | default: |
---|
2685 | break; |
---|
2686 | } |
---|
2687 | } |
---|
2688 | |
---|
2689 | static void |
---|
2690 | ohci_set_hw_power(struct usb_bus *bus) |
---|
2691 | { |
---|
2692 | struct ohci_softc *sc = OHCI_BUS2SC(bus); |
---|
2693 | uint32_t temp; |
---|
2694 | uint32_t flags; |
---|
2695 | |
---|
2696 | DPRINTF("\n"); |
---|
2697 | |
---|
2698 | USB_BUS_LOCK(bus); |
---|
2699 | |
---|
2700 | flags = bus->hw_power_state; |
---|
2701 | |
---|
2702 | temp = OREAD4(sc, OHCI_CONTROL); |
---|
2703 | temp &= ~(OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE); |
---|
2704 | |
---|
2705 | if (flags & USB_HW_POWER_CONTROL) |
---|
2706 | temp |= OHCI_CLE; |
---|
2707 | |
---|
2708 | if (flags & USB_HW_POWER_BULK) |
---|
2709 | temp |= OHCI_BLE; |
---|
2710 | |
---|
2711 | if (flags & USB_HW_POWER_INTERRUPT) |
---|
2712 | temp |= OHCI_PLE; |
---|
2713 | |
---|
2714 | if (flags & USB_HW_POWER_ISOC) |
---|
2715 | temp |= OHCI_IE | OHCI_PLE; |
---|
2716 | |
---|
2717 | OWRITE4(sc, OHCI_CONTROL, temp); |
---|
2718 | |
---|
2719 | USB_BUS_UNLOCK(bus); |
---|
2720 | |
---|
2721 | return; |
---|
2722 | } |
---|
2723 | |
---|
2724 | static const struct usb_bus_methods ohci_bus_methods = |
---|
2725 | { |
---|
2726 | .endpoint_init = ohci_ep_init, |
---|
2727 | .xfer_setup = ohci_xfer_setup, |
---|
2728 | .xfer_unsetup = ohci_xfer_unsetup, |
---|
2729 | .get_dma_delay = ohci_get_dma_delay, |
---|
2730 | .device_resume = ohci_device_resume, |
---|
2731 | .device_suspend = ohci_device_suspend, |
---|
2732 | .set_hw_power = ohci_set_hw_power, |
---|
2733 | .set_hw_power_sleep = ohci_set_hw_power_sleep, |
---|
2734 | .roothub_exec = ohci_roothub_exec, |
---|
2735 | .xfer_poll = ohci_do_poll, |
---|
2736 | }; |
---|