Annotation of sys/dev/usb/uhci.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: uhci.c,v 1.61 2007/07/20 14:31:17 mbalmer Exp $ */
2: /* $NetBSD: uhci.c,v 1.172 2003/02/23 04:19:26 simonb Exp $ */
3: /* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */
4:
5: /*
6: * Copyright (c) 1998 The NetBSD Foundation, Inc.
7: * All rights reserved.
8: *
9: * This code is derived from software contributed to The NetBSD Foundation
10: * by Lennart Augustsson (lennart@augustsson.net) at
11: * Carlstedt Research & Technology.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. All advertising materials mentioning features or use of this software
22: * must display the following acknowledgement:
23: * This product includes software developed by the NetBSD
24: * Foundation, Inc. and its contributors.
25: * 4. Neither the name of The NetBSD Foundation nor the names of its
26: * contributors may be used to endorse or promote products derived
27: * from this software without specific prior written permission.
28: *
29: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39: * POSSIBILITY OF SUCH DAMAGE.
40: */
41:
42: /*
43: * USB Universal Host Controller driver.
44: * Handles e.g. PIIX3 and PIIX4.
45: *
46: * UHCI spec: http://download.intel.com/technology/usb/UHCI11D.pdf
47: * USB spec: http://www.usb.org/developers/docs/usbspec.zip
48: * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf
49: * ftp://download.intel.com/design/intarch/datashts/29056201.pdf
50: */
51:
52: #include <sys/param.h>
53: #include <sys/systm.h>
54: #include <sys/kernel.h>
55: #include <sys/malloc.h>
56: #include <sys/device.h>
57: #include <sys/selinfo.h>
58: #include <sys/proc.h>
59: #include <sys/queue.h>
60:
61: #include <machine/bus.h>
62: #include <machine/endian.h>
63:
64: #include <dev/usb/usb.h>
65: #include <dev/usb/usbdi.h>
66: #include <dev/usb/usbdivar.h>
67: #include <dev/usb/usb_mem.h>
68: #include <dev/usb/usb_quirks.h>
69:
70: #include <dev/usb/uhcireg.h>
71: #include <dev/usb/uhcivar.h>
72:
73: /* Use bandwidth reclamation for control transfers. Some devices choke on it. */
74: /*#define UHCI_CTL_LOOP */
75:
76: struct cfdriver uhci_cd = {
77: NULL, "uhci", DV_DULL
78: };
79:
80: #ifdef UHCI_DEBUG
81: uhci_softc_t *thesc;
82: #define DPRINTF(x) if (uhcidebug) printf x
83: #define DPRINTFN(n,x) if (uhcidebug>(n)) printf x
84: int uhcidebug = 0;
85: int uhcinoloop = 0;
86: #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
87: #else
88: #define DPRINTF(x)
89: #define DPRINTFN(n,x)
90: #endif
91:
92: #define mstohz(ms) ((ms) * hz / 1000)
93:
94: /*
95: * The UHCI controller is little endian, so on big endian machines
96: * the data stored in memory needs to be swapped.
97: */
98:
99: struct uhci_pipe {
100: struct usbd_pipe pipe;
101: int nexttoggle;
102:
103: u_char aborting;
104: usbd_xfer_handle abortstart, abortend;
105:
106: /* Info needed for different pipe kinds. */
107: union {
108: /* Control pipe */
109: struct {
110: uhci_soft_qh_t *sqh;
111: usb_dma_t reqdma;
112: uhci_soft_td_t *setup, *stat;
113: u_int length;
114: } ctl;
115: /* Interrupt pipe */
116: struct {
117: int npoll;
118: int isread;
119: uhci_soft_qh_t **qhs;
120: } intr;
121: /* Bulk pipe */
122: struct {
123: uhci_soft_qh_t *sqh;
124: u_int length;
125: int isread;
126: } bulk;
127: /* Iso pipe */
128: struct iso {
129: uhci_soft_td_t **stds;
130: int next, inuse;
131: } iso;
132: } u;
133: };
134:
135: void uhci_globalreset(uhci_softc_t *);
136: usbd_status uhci_portreset(uhci_softc_t*, int);
137: void uhci_reset(uhci_softc_t *);
138: void uhci_shutdown(void *v);
139: void uhci_power(int, void *);
140: usbd_status uhci_run(uhci_softc_t *, int run);
141: uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *);
142: void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *);
143: uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *);
144: void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *);
145: #if 0
146: void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *,
147: uhci_intr_info_t *);
148: void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *);
149: #endif
150:
151: void uhci_free_std_chain(uhci_softc_t *,
152: uhci_soft_td_t *, uhci_soft_td_t *);
153: usbd_status uhci_alloc_std_chain(struct uhci_pipe *,
154: uhci_softc_t *, int, int, u_int16_t, usb_dma_t *,
155: uhci_soft_td_t **, uhci_soft_td_t **);
156: void uhci_poll_hub(void *);
157: void uhci_waitintr(uhci_softc_t *, usbd_xfer_handle);
158: void uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *);
159: void uhci_idone(uhci_intr_info_t *);
160:
161: void uhci_abort_xfer(usbd_xfer_handle, usbd_status status);
162:
163: void uhci_timeout(void *);
164: void uhci_timeout_task(void *);
165: void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
166: void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
167: void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *);
168: void uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
169: void uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
170: void uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *);
171: int uhci_str(usb_string_descriptor_t *, int, char *);
172: void uhci_add_loop(uhci_softc_t *sc);
173: void uhci_rem_loop(uhci_softc_t *sc);
174:
175: usbd_status uhci_setup_isoc(usbd_pipe_handle pipe);
176: void uhci_device_isoc_enter(usbd_xfer_handle);
177:
178: usbd_status uhci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t);
179: void uhci_freem(struct usbd_bus *, usb_dma_t *);
180:
181: usbd_xfer_handle uhci_allocx(struct usbd_bus *);
182: void uhci_freex(struct usbd_bus *, usbd_xfer_handle);
183:
184: usbd_status uhci_device_ctrl_transfer(usbd_xfer_handle);
185: usbd_status uhci_device_ctrl_start(usbd_xfer_handle);
186: void uhci_device_ctrl_abort(usbd_xfer_handle);
187: void uhci_device_ctrl_close(usbd_pipe_handle);
188: void uhci_device_ctrl_done(usbd_xfer_handle);
189:
190: usbd_status uhci_device_intr_transfer(usbd_xfer_handle);
191: usbd_status uhci_device_intr_start(usbd_xfer_handle);
192: void uhci_device_intr_abort(usbd_xfer_handle);
193: void uhci_device_intr_close(usbd_pipe_handle);
194: void uhci_device_intr_done(usbd_xfer_handle);
195:
196: usbd_status uhci_device_bulk_transfer(usbd_xfer_handle);
197: usbd_status uhci_device_bulk_start(usbd_xfer_handle);
198: void uhci_device_bulk_abort(usbd_xfer_handle);
199: void uhci_device_bulk_close(usbd_pipe_handle);
200: void uhci_device_bulk_done(usbd_xfer_handle);
201:
202: usbd_status uhci_device_isoc_transfer(usbd_xfer_handle);
203: usbd_status uhci_device_isoc_start(usbd_xfer_handle);
204: void uhci_device_isoc_abort(usbd_xfer_handle);
205: void uhci_device_isoc_close(usbd_pipe_handle);
206: void uhci_device_isoc_done(usbd_xfer_handle);
207:
208: usbd_status uhci_root_ctrl_transfer(usbd_xfer_handle);
209: usbd_status uhci_root_ctrl_start(usbd_xfer_handle);
210: void uhci_root_ctrl_abort(usbd_xfer_handle);
211: void uhci_root_ctrl_close(usbd_pipe_handle);
212: void uhci_root_ctrl_done(usbd_xfer_handle);
213:
214: usbd_status uhci_root_intr_transfer(usbd_xfer_handle);
215: usbd_status uhci_root_intr_start(usbd_xfer_handle);
216: void uhci_root_intr_abort(usbd_xfer_handle);
217: void uhci_root_intr_close(usbd_pipe_handle);
218: void uhci_root_intr_done(usbd_xfer_handle);
219:
220: usbd_status uhci_open(usbd_pipe_handle);
221: void uhci_poll(struct usbd_bus *);
222: void uhci_softintr(void *);
223:
224: usbd_status uhci_device_request(usbd_xfer_handle xfer);
225:
226: void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *);
227: void uhci_remove_intr(uhci_softc_t *, uhci_soft_qh_t *);
228: usbd_status uhci_device_setintr(uhci_softc_t *sc,
229: struct uhci_pipe *pipe, int ival);
230:
231: void uhci_device_clear_toggle(usbd_pipe_handle pipe);
232: void uhci_noop(usbd_pipe_handle pipe);
233:
234: __inline__ uhci_soft_qh_t *uhci_find_prev_qh(uhci_soft_qh_t *,
235: uhci_soft_qh_t *);
236:
237: #ifdef UHCI_DEBUG
238: void uhci_dump_all(uhci_softc_t *);
239: void uhci_dumpregs(uhci_softc_t *);
240: void uhci_dump_qhs(uhci_soft_qh_t *);
241: void uhci_dump_qh(uhci_soft_qh_t *);
242: void uhci_dump_tds(uhci_soft_td_t *);
243: void uhci_dump_td(uhci_soft_td_t *);
244: void uhci_dump_ii(uhci_intr_info_t *ii);
245: void uhci_dump(void);
246: #endif
247:
248: #define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \
249: BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
250: #define UWRITE1(sc, r, x) \
251: do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \
252: } while (/*CONSTCOND*/0)
253: #define UWRITE2(sc, r, x) \
254: do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \
255: } while (/*CONSTCOND*/0)
256: #define UWRITE4(sc, r, x) \
257: do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \
258: } while (/*CONSTCOND*/0)
259: #define UREAD1(sc, r) (UBARR(sc), bus_space_read_1((sc)->iot, (sc)->ioh, (r)))
260: #define UREAD2(sc, r) (UBARR(sc), bus_space_read_2((sc)->iot, (sc)->ioh, (r)))
261: #define UREAD4(sc, r) (UBARR(sc), bus_space_read_4((sc)->iot, (sc)->ioh, (r)))
262:
263: #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd)
264: #define UHCISTS(sc) UREAD2(sc, UHCI_STS)
265:
266: #define UHCI_RESET_TIMEOUT 100 /* ms, reset timeout */
267:
268: #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK)
269:
270: #define UHCI_INTR_ENDPT 1
271:
272: struct usbd_bus_methods uhci_bus_methods = {
273: uhci_open,
274: uhci_softintr,
275: uhci_poll,
276: uhci_allocm,
277: uhci_freem,
278: uhci_allocx,
279: uhci_freex,
280: };
281:
282: struct usbd_pipe_methods uhci_root_ctrl_methods = {
283: uhci_root_ctrl_transfer,
284: uhci_root_ctrl_start,
285: uhci_root_ctrl_abort,
286: uhci_root_ctrl_close,
287: uhci_noop,
288: uhci_root_ctrl_done,
289: };
290:
291: struct usbd_pipe_methods uhci_root_intr_methods = {
292: uhci_root_intr_transfer,
293: uhci_root_intr_start,
294: uhci_root_intr_abort,
295: uhci_root_intr_close,
296: uhci_noop,
297: uhci_root_intr_done,
298: };
299:
300: struct usbd_pipe_methods uhci_device_ctrl_methods = {
301: uhci_device_ctrl_transfer,
302: uhci_device_ctrl_start,
303: uhci_device_ctrl_abort,
304: uhci_device_ctrl_close,
305: uhci_noop,
306: uhci_device_ctrl_done,
307: };
308:
309: struct usbd_pipe_methods uhci_device_intr_methods = {
310: uhci_device_intr_transfer,
311: uhci_device_intr_start,
312: uhci_device_intr_abort,
313: uhci_device_intr_close,
314: uhci_device_clear_toggle,
315: uhci_device_intr_done,
316: };
317:
318: struct usbd_pipe_methods uhci_device_bulk_methods = {
319: uhci_device_bulk_transfer,
320: uhci_device_bulk_start,
321: uhci_device_bulk_abort,
322: uhci_device_bulk_close,
323: uhci_device_clear_toggle,
324: uhci_device_bulk_done,
325: };
326:
327: struct usbd_pipe_methods uhci_device_isoc_methods = {
328: uhci_device_isoc_transfer,
329: uhci_device_isoc_start,
330: uhci_device_isoc_abort,
331: uhci_device_isoc_close,
332: uhci_noop,
333: uhci_device_isoc_done,
334: };
335:
336: #define uhci_add_intr_info(sc, ii) \
337: LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list)
338: #define uhci_del_intr_info(ii) \
339: do { \
340: LIST_REMOVE((ii), list); \
341: (ii)->list.le_prev = NULL; \
342: } while (0)
343: #define uhci_active_intr_info(ii) ((ii)->list.le_prev != NULL)
344:
345: __inline__ uhci_soft_qh_t *
346: uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh)
347: {
348: DPRINTFN(15,("uhci_find_prev_qh: pqh=%p sqh=%p\n", pqh, sqh));
349:
350: for (; pqh->hlink != sqh; pqh = pqh->hlink) {
351: #if defined(DIAGNOSTIC) || defined(UHCI_DEBUG)
352: if (letoh32(pqh->qh.qh_hlink) & UHCI_PTR_T) {
353: printf("uhci_find_prev_qh: QH not found\n");
354: return (NULL);
355: }
356: #endif
357: }
358: return (pqh);
359: }
360:
361: void
362: uhci_globalreset(uhci_softc_t *sc)
363: {
364: UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */
365: usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */
366: UHCICMD(sc, 0); /* do nothing */
367: }
368:
369: usbd_status
370: uhci_init(uhci_softc_t *sc)
371: {
372: usbd_status err;
373: int i, j;
374: uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh;
375: uhci_soft_td_t *std;
376:
377: DPRINTFN(1,("uhci_init: start\n"));
378:
379: #ifdef UHCI_DEBUG
380: thesc = sc;
381:
382: if (uhcidebug > 2)
383: uhci_dumpregs(sc);
384: #endif
385:
386: /* Save SOF over HC reset. */
387: sc->sc_saved_sof = UREAD1(sc, UHCI_SOF);
388:
389: UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
390: uhci_globalreset(sc); /* reset the controller */
391: uhci_reset(sc);
392:
393: /* Restore saved SOF. */
394: UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof);
395:
396: /* Allocate and initialize real frame array. */
397: err = usb_allocmem(&sc->sc_bus,
398: UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
399: UHCI_FRAMELIST_ALIGN, &sc->sc_dma);
400: if (err)
401: return (err);
402: sc->sc_pframes = KERNADDR(&sc->sc_dma, 0);
403: UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */
404: UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/
405:
406: /*
407: * Allocate a TD, inactive, that hangs from the last QH.
408: * This is to avoid a bug in the PIIX that makes it run berserk
409: * otherwise.
410: */
411: std = uhci_alloc_std(sc);
412: if (std == NULL)
413: return (USBD_NOMEM);
414: std->link.std = NULL;
415: std->td.td_link = htole32(UHCI_PTR_T);
416: std->td.td_status = htole32(0); /* inactive */
417: std->td.td_token = htole32(0);
418: std->td.td_buffer = htole32(0);
419:
420: /* Allocate the dummy QH marking the end and used for looping the QHs.*/
421: lsqh = uhci_alloc_sqh(sc);
422: if (lsqh == NULL)
423: return (USBD_NOMEM);
424: lsqh->hlink = NULL;
425: lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */
426: lsqh->elink = std;
427: lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD);
428: sc->sc_last_qh = lsqh;
429:
430: /* Allocate the dummy QH where bulk traffic will be queued. */
431: bsqh = uhci_alloc_sqh(sc);
432: if (bsqh == NULL)
433: return (USBD_NOMEM);
434: bsqh->hlink = lsqh;
435: bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH);
436: bsqh->elink = NULL;
437: bsqh->qh.qh_elink = htole32(UHCI_PTR_T);
438: sc->sc_bulk_start = sc->sc_bulk_end = bsqh;
439:
440: /* Allocate dummy QH where high speed control traffic will be queued. */
441: chsqh = uhci_alloc_sqh(sc);
442: if (chsqh == NULL)
443: return (USBD_NOMEM);
444: chsqh->hlink = bsqh;
445: chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH);
446: chsqh->elink = NULL;
447: chsqh->qh.qh_elink = htole32(UHCI_PTR_T);
448: sc->sc_hctl_start = sc->sc_hctl_end = chsqh;
449:
450: /* Allocate dummy QH where control traffic will be queued. */
451: clsqh = uhci_alloc_sqh(sc);
452: if (clsqh == NULL)
453: return (USBD_NOMEM);
454: clsqh->hlink = bsqh;
455: clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH);
456: clsqh->elink = NULL;
457: clsqh->qh.qh_elink = htole32(UHCI_PTR_T);
458: sc->sc_lctl_start = sc->sc_lctl_end = clsqh;
459:
460: /*
461: * Make all (virtual) frame list pointers point to the interrupt
462: * queue heads and the interrupt queue heads at the control
463: * queue head and point the physical frame list to the virtual.
464: */
465: for(i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
466: std = uhci_alloc_std(sc);
467: sqh = uhci_alloc_sqh(sc);
468: if (std == NULL || sqh == NULL)
469: return (USBD_NOMEM);
470: std->link.sqh = sqh;
471: std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH);
472: std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
473: std->td.td_token = htole32(0);
474: std->td.td_buffer = htole32(0);
475: sqh->hlink = clsqh;
476: sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH);
477: sqh->elink = NULL;
478: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
479: sc->sc_vframes[i].htd = std;
480: sc->sc_vframes[i].etd = std;
481: sc->sc_vframes[i].hqh = sqh;
482: sc->sc_vframes[i].eqh = sqh;
483: for (j = i;
484: j < UHCI_FRAMELIST_COUNT;
485: j += UHCI_VFRAMELIST_COUNT)
486: sc->sc_pframes[j] = htole32(std->physaddr);
487: }
488:
489: LIST_INIT(&sc->sc_intrhead);
490:
491: SIMPLEQ_INIT(&sc->sc_free_xfers);
492:
493: timeout_set(&sc->sc_poll_handle, NULL, NULL);
494:
495: /* Set up the bus struct. */
496: sc->sc_bus.methods = &uhci_bus_methods;
497: sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);
498:
499: sc->sc_suspend = PWR_RESUME;
500: sc->sc_powerhook = powerhook_establish(uhci_power, sc);
501: sc->sc_shutdownhook = shutdownhook_establish(uhci_shutdown, sc);
502:
503: UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */
504:
505: DPRINTFN(1,("uhci_init: enabling\n"));
506: UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
507: UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */
508:
509: return (uhci_run(sc, 1)); /* and here we go... */
510: }
511:
512: int
513: uhci_activate(struct device *self, enum devact act)
514: {
515: struct uhci_softc *sc = (struct uhci_softc *)self;
516: int rv = 0;
517:
518: switch (act) {
519: case DVACT_ACTIVATE:
520: break;
521:
522: case DVACT_DEACTIVATE:
523: if (sc->sc_child != NULL)
524: rv = config_deactivate(sc->sc_child);
525: break;
526: }
527: return (rv);
528: }
529:
530: int
531: uhci_detach(struct uhci_softc *sc, int flags)
532: {
533: usbd_xfer_handle xfer;
534: int rv = 0;
535:
536: if (sc->sc_child != NULL)
537: rv = config_detach(sc->sc_child, flags);
538:
539: if (rv != 0)
540: return (rv);
541:
542: if (sc->sc_powerhook != NULL)
543: powerhook_disestablish(sc->sc_powerhook);
544: if (sc->sc_shutdownhook != NULL)
545: shutdownhook_disestablish(sc->sc_shutdownhook);
546:
547: /* Free all xfers associated with this HC. */
548: for (;;) {
549: xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
550: if (xfer == NULL)
551: break;
552: SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
553: free(xfer, M_USB);
554: }
555:
556: /* XXX free other data structures XXX */
557:
558: return (rv);
559: }
560:
561: usbd_status
562: uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
563: {
564: struct uhci_softc *sc = (struct uhci_softc *)bus;
565: u_int32_t n;
566:
567: /*
568: * XXX
569: * Since we are allocating a buffer we can assume that we will
570: * need TDs for it. Since we don't want to allocate those from
571: * an interrupt context, we allocate them here and free them again.
572: * This is no guarantee that we'll get the TDs next time...
573: */
574: n = size / 8;
575: if (n > 16) {
576: u_int32_t i;
577: uhci_soft_td_t **stds;
578: DPRINTF(("uhci_allocm: get %d TDs\n", n));
579: stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP,
580: M_NOWAIT);
581: if (stds == NULL)
582: panic("uhci_allocm");
583: memset(stds, 0, sizeof(uhci_soft_td_t *) * n);
584: for(i=0; i < n; i++)
585: stds[i] = uhci_alloc_std(sc);
586: for(i=0; i < n; i++)
587: if (stds[i] != NULL)
588: uhci_free_std(sc, stds[i]);
589: free(stds, M_TEMP);
590: }
591:
592: return (usb_allocmem(&sc->sc_bus, size, 0, dma));
593: }
594:
595: void
596: uhci_freem(struct usbd_bus *bus, usb_dma_t *dma)
597: {
598: usb_freemem(&((struct uhci_softc *)bus)->sc_bus, dma);
599: }
600:
601: usbd_xfer_handle
602: uhci_allocx(struct usbd_bus *bus)
603: {
604: struct uhci_softc *sc = (struct uhci_softc *)bus;
605: usbd_xfer_handle xfer;
606:
607: xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
608: if (xfer != NULL) {
609: SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
610: #ifdef DIAGNOSTIC
611: if (xfer->busy_free != XFER_FREE) {
612: printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer,
613: xfer->busy_free);
614: }
615: #endif
616: } else {
617: xfer = malloc(sizeof(struct uhci_xfer), M_USB, M_NOWAIT);
618: }
619: if (xfer != NULL) {
620: memset(xfer, 0, sizeof (struct uhci_xfer));
621: UXFER(xfer)->iinfo.sc = sc;
622: #ifdef DIAGNOSTIC
623: UXFER(xfer)->iinfo.isdone = 1;
624: xfer->busy_free = XFER_BUSY;
625: #endif
626: }
627: return (xfer);
628: }
629:
630: void
631: uhci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)
632: {
633: struct uhci_softc *sc = (struct uhci_softc *)bus;
634:
635: #ifdef DIAGNOSTIC
636: if (xfer->busy_free != XFER_BUSY) {
637: printf("uhci_freex: xfer=%p not busy, 0x%08x\n", xfer,
638: xfer->busy_free);
639: return;
640: }
641: xfer->busy_free = XFER_FREE;
642: if (!UXFER(xfer)->iinfo.isdone) {
643: printf("uhci_freex: !isdone\n");
644: return;
645: }
646: #endif
647: SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
648: }
649:
650: /*
651: * Shut down the controller when the system is going down.
652: */
653: void
654: uhci_shutdown(void *v)
655: {
656: uhci_softc_t *sc = v;
657:
658: DPRINTF(("uhci_shutdown: stopping the HC\n"));
659: uhci_run(sc, 0); /* stop the controller */
660: }
661:
662: /*
663: * Handle suspend/resume.
664: *
665: * We need to switch to polling mode here, because this routine is
666: * called from an interrupt context. This is all right since we
667: * are almost suspended anyway.
668: */
669: void
670: uhci_power(int why, void *v)
671: {
672: uhci_softc_t *sc = v;
673: int cmd;
674: int s;
675:
676: s = splhardusb();
677: cmd = UREAD2(sc, UHCI_CMD);
678:
679: DPRINTF(("uhci_power: sc=%p, why=%d (was %d), cmd=0x%x\n",
680: sc, why, sc->sc_suspend, cmd));
681:
682: switch (why) {
683: case PWR_SUSPEND:
684: case PWR_STANDBY:
685: #ifdef UHCI_DEBUG
686: if (uhcidebug > 2)
687: uhci_dumpregs(sc);
688: #endif
689: if (sc->sc_intr_xfer != NULL)
690: timeout_del(&sc->sc_poll_handle);
691: sc->sc_bus.use_polling++;
692: uhci_run(sc, 0); /* stop the controller */
693:
694: /* save some state if BIOS doesn't */
695: sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM);
696:
697: UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */
698:
699: UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter global suspend */
700: usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
701: sc->sc_suspend = why;
702: sc->sc_bus.use_polling--;
703: DPRINTF(("uhci_power: cmd=0x%x\n", UREAD2(sc, UHCI_CMD)));
704: break;
705: case PWR_RESUME:
706: #ifdef DIAGNOSTIC
707: if (sc->sc_suspend == PWR_RESUME)
708: printf("uhci_power: weird, resume without suspend.\n");
709: #endif
710: sc->sc_bus.use_polling++;
711: sc->sc_suspend = why;
712: if (cmd & UHCI_CMD_RS)
713: uhci_run(sc, 0); /* in case BIOS has started it */
714:
715: /* restore saved state */
716: UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0));
717: UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum);
718: UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof);
719:
720: UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force global resume */
721: usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
722: UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */
723: UHCICMD(sc, UHCI_CMD_MAXP);
724: UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
725: UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* re-enable intrs */
726: uhci_run(sc, 1); /* and start traffic again */
727: usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
728: sc->sc_bus.use_polling--;
729: if (sc->sc_intr_xfer != NULL) {
730: timeout_del(&sc->sc_poll_handle);
731: timeout_set(&sc->sc_poll_handle, uhci_poll_hub,
732: sc->sc_intr_xfer);
733: timeout_add(&sc->sc_poll_handle, sc->sc_ival);
734: }
735: #ifdef UHCI_DEBUG
736: if (uhcidebug > 2)
737: uhci_dumpregs(sc);
738: #endif
739: break;
740: }
741: splx(s);
742: }
743:
744: #ifdef UHCI_DEBUG
745: void
746: uhci_dumpregs(uhci_softc_t *sc)
747: {
748: DPRINTFN(-1,("%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, "
749: "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n",
750: sc->sc_bus.bdev.dv_xname,
751: UREAD2(sc, UHCI_CMD),
752: UREAD2(sc, UHCI_STS),
753: UREAD2(sc, UHCI_INTR),
754: UREAD2(sc, UHCI_FRNUM),
755: UREAD4(sc, UHCI_FLBASEADDR),
756: UREAD1(sc, UHCI_SOF),
757: UREAD2(sc, UHCI_PORTSC1),
758: UREAD2(sc, UHCI_PORTSC2)));
759: }
760:
761: void
762: uhci_dump_td(uhci_soft_td_t *p)
763: {
764: char sbuf[128], sbuf2[128];
765:
766: DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx "
767: "token=0x%08lx buffer=0x%08lx\n",
768: p, (long)p->physaddr,
769: (long)letoh32(p->td.td_link),
770: (long)letoh32(p->td.td_status),
771: (long)letoh32(p->td.td_token),
772: (long)letoh32(p->td.td_buffer)));
773:
774: bitmask_snprintf((u_int32_t)letoh32(p->td.td_link), "\20\1T\2Q\3VF",
775: sbuf, sizeof(sbuf));
776: bitmask_snprintf((u_int32_t)letoh32(p->td.td_status),
777: "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27"
778: "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD",
779: sbuf2, sizeof(sbuf2));
780:
781: DPRINTFN(-1,(" %s %s,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d,"
782: "D=%d,maxlen=%d\n", sbuf, sbuf2,
783: UHCI_TD_GET_ERRCNT(letoh32(p->td.td_status)),
784: UHCI_TD_GET_ACTLEN(letoh32(p->td.td_status)),
785: UHCI_TD_GET_PID(letoh32(p->td.td_token)),
786: UHCI_TD_GET_DEVADDR(letoh32(p->td.td_token)),
787: UHCI_TD_GET_ENDPT(letoh32(p->td.td_token)),
788: UHCI_TD_GET_DT(letoh32(p->td.td_token)),
789: UHCI_TD_GET_MAXLEN(letoh32(p->td.td_token))));
790: }
791:
792: void
793: uhci_dump_qh(uhci_soft_qh_t *sqh)
794: {
795: DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh,
796: (int)sqh->physaddr, letoh32(sqh->qh.qh_hlink),
797: letoh32(sqh->qh.qh_elink)));
798: }
799:
800:
801: void
802: uhci_dump(void)
803: {
804: uhci_dump_all(thesc);
805: }
806:
807: void
808: uhci_dump_all(uhci_softc_t *sc)
809: {
810: uhci_dumpregs(sc);
811: printf("intrs=%d\n", sc->sc_bus.no_intrs);
812: /*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/
813: uhci_dump_qh(sc->sc_lctl_start);
814: }
815:
816:
817: void
818: uhci_dump_qhs(uhci_soft_qh_t *sqh)
819: {
820: uhci_dump_qh(sqh);
821:
822: /* uhci_dump_qhs displays all the QHs and TDs from the given QH onwards
823: * Traverses sideways first, then down.
824: *
825: * QH1
826: * QH2
827: * No QH
828: * TD2.1
829: * TD2.2
830: * TD1.1
831: * etc.
832: *
833: * TD2.x being the TDs queued at QH2 and QH1 being referenced from QH1.
834: */
835:
836:
837: if (sqh->hlink != NULL && !(letoh32(sqh->qh.qh_hlink) & UHCI_PTR_T))
838: uhci_dump_qhs(sqh->hlink);
839: else
840: DPRINTF(("No QH\n"));
841:
842: if (sqh->elink != NULL && !(letoh32(sqh->qh.qh_elink) & UHCI_PTR_T))
843: uhci_dump_tds(sqh->elink);
844: else
845: DPRINTF(("No TD\n"));
846: }
847:
848: void
849: uhci_dump_tds(uhci_soft_td_t *std)
850: {
851: uhci_soft_td_t *td;
852:
853: for(td = std; td != NULL; td = td->link.std) {
854: uhci_dump_td(td);
855:
856: /* Check whether the link pointer in this TD marks
857: * the link pointer as end of queue. This avoids
858: * printing the free list in case the queue/TD has
859: * already been moved there (seatbelt).
860: */
861: if (letoh32(td->td.td_link) & UHCI_PTR_T ||
862: letoh32(td->td.td_link) == 0)
863: break;
864: }
865: }
866:
867: void
868: uhci_dump_ii(uhci_intr_info_t *ii)
869: {
870: usbd_pipe_handle pipe;
871: usb_endpoint_descriptor_t *ed;
872: usbd_device_handle dev;
873:
874: #ifdef DIAGNOSTIC
875: #define DONE ii->isdone
876: #else
877: #define DONE 0
878: #endif
879: if (ii == NULL) {
880: printf("ii NULL\n");
881: return;
882: }
883: if (ii->xfer == NULL) {
884: printf("ii %p: done=%d xfer=NULL\n",
885: ii, DONE);
886: return;
887: }
888: pipe = ii->xfer->pipe;
889: if (pipe == NULL) {
890: printf("ii %p: done=%d xfer=%p pipe=NULL\n",
891: ii, DONE, ii->xfer);
892: return;
893: }
894: if (pipe->endpoint == NULL) {
895: printf("ii %p: done=%d xfer=%p pipe=%p pipe->endpoint=NULL\n",
896: ii, DONE, ii->xfer, pipe);
897: return;
898: }
899: if (pipe->device == NULL) {
900: printf("ii %p: done=%d xfer=%p pipe=%p pipe->device=NULL\n",
901: ii, DONE, ii->xfer, pipe);
902: return;
903: }
904: ed = pipe->endpoint->edesc;
905: dev = pipe->device;
906: printf("ii %p: done=%d xfer=%p dev=%p vid=0x%04x pid=0x%04x addr=%d pipe=%p ep=0x%02x attr=0x%02x\n",
907: ii, DONE, ii->xfer, dev,
908: UGETW(dev->ddesc.idVendor),
909: UGETW(dev->ddesc.idProduct),
910: dev->address, pipe,
911: ed->bEndpointAddress, ed->bmAttributes);
912: #undef DONE
913: }
914:
915: void uhci_dump_iis(struct uhci_softc *sc);
916: void
917: uhci_dump_iis(struct uhci_softc *sc)
918: {
919: uhci_intr_info_t *ii;
920:
921: printf("intr_info list:\n");
922: for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list))
923: uhci_dump_ii(ii);
924: }
925:
926: void iidump(void);
927: void iidump(void) { uhci_dump_iis(thesc); }
928:
929: #endif
930:
931: /*
932: * This routine is executed periodically and simulates interrupts
933: * from the root controller interrupt pipe for port status change.
934: */
935: void
936: uhci_poll_hub(void *addr)
937: {
938: usbd_xfer_handle xfer = addr;
939: usbd_pipe_handle pipe = xfer->pipe;
940: uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
941: int s;
942: u_char *p;
943:
944: DPRINTFN(20, ("uhci_poll_hub\n"));
945:
946: timeout_del(&sc->sc_poll_handle);
947: timeout_set(&sc->sc_poll_handle, uhci_poll_hub, xfer);
948: timeout_add(&sc->sc_poll_handle, sc->sc_ival);
949:
950: p = KERNADDR(&xfer->dmabuf, 0);
951: p[0] = 0;
952: if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
953: p[0] |= 1<<1;
954: if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
955: p[0] |= 1<<2;
956: if (p[0] == 0)
957: /* No change, try again in a while */
958: return;
959:
960: xfer->actlen = 1;
961: xfer->status = USBD_NORMAL_COMPLETION;
962: s = splusb();
963: xfer->device->bus->intr_context++;
964: usb_transfer_complete(xfer);
965: xfer->device->bus->intr_context--;
966: splx(s);
967: }
968:
969: void
970: uhci_root_intr_done(usbd_xfer_handle xfer)
971: {
972: }
973:
974: void
975: uhci_root_ctrl_done(usbd_xfer_handle xfer)
976: {
977: }
978:
979: /*
980: * Let the last QH loop back to the high speed control transfer QH.
981: * This is what intel calls "bandwidth reclamation" and improves
982: * USB performance a lot for some devices.
983: * If we are already looping, just count it.
984: */
985: void
986: uhci_add_loop(uhci_softc_t *sc) {
987: #ifdef UHCI_DEBUG
988: if (uhcinoloop)
989: return;
990: #endif
991: if (++sc->sc_loops == 1) {
992: DPRINTFN(5,("uhci_start_loop: add\n"));
993: /* Note, we don't loop back the soft pointer. */
994: sc->sc_last_qh->qh.qh_hlink =
995: htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH);
996: }
997: }
998:
999: void
1000: uhci_rem_loop(uhci_softc_t *sc) {
1001: #ifdef UHCI_DEBUG
1002: if (uhcinoloop)
1003: return;
1004: #endif
1005: if (--sc->sc_loops == 0) {
1006: DPRINTFN(5,("uhci_end_loop: remove\n"));
1007: sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T);
1008: }
1009: }
1010:
1011: /* Add high speed control QH, called at splusb(). */
1012: void
1013: uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
1014: {
1015: uhci_soft_qh_t *eqh;
1016:
1017: SPLUSBCHECK;
1018:
1019: DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh));
1020: eqh = sc->sc_hctl_end;
1021: sqh->hlink = eqh->hlink;
1022: sqh->qh.qh_hlink = eqh->qh.qh_hlink;
1023: eqh->hlink = sqh;
1024: eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
1025: sc->sc_hctl_end = sqh;
1026: #ifdef UHCI_CTL_LOOP
1027: uhci_add_loop(sc);
1028: #endif
1029: }
1030:
1031: /* Remove high speed control QH, called at splusb(). */
1032: void
1033: uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
1034: {
1035: uhci_soft_qh_t *pqh;
1036:
1037: SPLUSBCHECK;
1038:
1039: DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh));
1040: #ifdef UHCI_CTL_LOOP
1041: uhci_rem_loop(sc);
1042: #endif
1043: /*
1044: * The T bit should be set in the elink of the QH so that the HC
1045: * doesn't follow the pointer. This condition may fail if the
1046: * the transferred packet was short so that the QH still points
1047: * at the last used TD.
1048: * In this case we set the T bit and wait a little for the HC
1049: * to stop looking at the TD.
1050: */
1051: if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
1052: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
1053: delay(UHCI_QH_REMOVE_DELAY);
1054: }
1055:
1056: pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh);
1057: pqh->hlink = sqh->hlink;
1058: pqh->qh.qh_hlink = sqh->qh.qh_hlink;
1059: delay(UHCI_QH_REMOVE_DELAY);
1060: if (sc->sc_hctl_end == sqh)
1061: sc->sc_hctl_end = pqh;
1062: }
1063:
1064: /* Add low speed control QH, called at splusb(). */
1065: void
1066: uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
1067: {
1068: uhci_soft_qh_t *eqh;
1069:
1070: SPLUSBCHECK;
1071:
1072: DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh));
1073: eqh = sc->sc_lctl_end;
1074: sqh->hlink = eqh->hlink;
1075: sqh->qh.qh_hlink = eqh->qh.qh_hlink;
1076: eqh->hlink = sqh;
1077: eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
1078: sc->sc_lctl_end = sqh;
1079: }
1080:
1081: /* Remove low speed control QH, called at splusb(). */
1082: void
1083: uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
1084: {
1085: uhci_soft_qh_t *pqh;
1086:
1087: SPLUSBCHECK;
1088:
1089: DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh));
1090: /* See comment in uhci_remove_hs_ctrl() */
1091: if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
1092: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
1093: delay(UHCI_QH_REMOVE_DELAY);
1094: }
1095: pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh);
1096: pqh->hlink = sqh->hlink;
1097: pqh->qh.qh_hlink = sqh->qh.qh_hlink;
1098: delay(UHCI_QH_REMOVE_DELAY);
1099: if (sc->sc_lctl_end == sqh)
1100: sc->sc_lctl_end = pqh;
1101: }
1102:
1103: /* Add bulk QH, called at splusb(). */
1104: void
1105: uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
1106: {
1107: uhci_soft_qh_t *eqh;
1108:
1109: SPLUSBCHECK;
1110:
1111: DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh));
1112: eqh = sc->sc_bulk_end;
1113: sqh->hlink = eqh->hlink;
1114: sqh->qh.qh_hlink = eqh->qh.qh_hlink;
1115: eqh->hlink = sqh;
1116: eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
1117: sc->sc_bulk_end = sqh;
1118: uhci_add_loop(sc);
1119: }
1120:
1121: /* Remove bulk QH, called at splusb(). */
1122: void
1123: uhci_remove_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
1124: {
1125: uhci_soft_qh_t *pqh;
1126:
1127: SPLUSBCHECK;
1128:
1129: DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh));
1130: uhci_rem_loop(sc);
1131: /* See comment in uhci_remove_hs_ctrl() */
1132: if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
1133: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
1134: delay(UHCI_QH_REMOVE_DELAY);
1135: }
1136: pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh);
1137: pqh->hlink = sqh->hlink;
1138: pqh->qh.qh_hlink = sqh->qh.qh_hlink;
1139: delay(UHCI_QH_REMOVE_DELAY);
1140: if (sc->sc_bulk_end == sqh)
1141: sc->sc_bulk_end = pqh;
1142: }
1143:
1144: int uhci_intr1(uhci_softc_t *);
1145:
1146: int
1147: uhci_intr(void *arg)
1148: {
1149: uhci_softc_t *sc = arg;
1150:
1151: if (sc->sc_dying)
1152: return (0);
1153:
1154: if (sc->sc_bus.use_polling) {
1155: #ifdef DIAGNOSTIC
1156: DPRINTFN(16, ("uhci_intr: ignored interrupt while polling\n"));
1157: #endif
1158: return (0);
1159: }
1160: return (uhci_intr1(sc));
1161: }
1162:
1163: int
1164: uhci_intr1(uhci_softc_t *sc)
1165: {
1166: int status;
1167: int ack;
1168:
1169: status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS;
1170: if (status == 0) /* The interrupt was not for us. */
1171: return (0);
1172:
1173: #ifdef UHCI_DEBUG
1174: if (uhcidebug > 15) {
1175: DPRINTF(("%s: uhci_intr1\n", sc->sc_bus.bdev.dv_xname));
1176: uhci_dumpregs(sc);
1177: }
1178: #endif
1179:
1180: if (sc->sc_suspend != PWR_RESUME) {
1181: printf("%s: interrupt while not operating ignored\n",
1182: sc->sc_bus.bdev.dv_xname);
1183: UWRITE2(sc, UHCI_STS, status); /* acknowledge the ints */
1184: return (0);
1185: }
1186:
1187: ack = 0;
1188: if (status & UHCI_STS_USBINT)
1189: ack |= UHCI_STS_USBINT;
1190: if (status & UHCI_STS_USBEI)
1191: ack |= UHCI_STS_USBEI;
1192: if (status & UHCI_STS_RD) {
1193: ack |= UHCI_STS_RD;
1194: #ifdef UHCI_DEBUG
1195: printf("%s: resume detect\n", sc->sc_bus.bdev.dv_xname);
1196: #endif
1197: }
1198: if (status & UHCI_STS_HSE) {
1199: ack |= UHCI_STS_HSE;
1200: printf("%s: host system error\n", sc->sc_bus.bdev.dv_xname);
1201: }
1202: if (status & UHCI_STS_HCPE) {
1203: ack |= UHCI_STS_HCPE;
1204: printf("%s: host controller process error\n",
1205: sc->sc_bus.bdev.dv_xname);
1206: }
1207: if (status & UHCI_STS_HCH) {
1208: /* no acknowledge needed */
1209: if (!sc->sc_dying) {
1210: printf("%s: host controller halted\n",
1211: sc->sc_bus.bdev.dv_xname);
1212: #ifdef UHCI_DEBUG
1213: uhci_dump_all(sc);
1214: #endif
1215: }
1216: sc->sc_dying = 1;
1217: }
1218:
1219: if (!ack)
1220: return (0); /* nothing to acknowledge */
1221: UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */
1222:
1223: sc->sc_bus.no_intrs++;
1224: usb_schedsoftintr(&sc->sc_bus);
1225:
1226: DPRINTFN(15, ("%s: uhci_intr: exit\n", sc->sc_bus.bdev.dv_xname));
1227:
1228: return (1);
1229: }
1230:
1231: void
1232: uhci_softintr(void *v)
1233: {
1234: uhci_softc_t *sc = v;
1235: uhci_intr_info_t *ii, *nextii;
1236:
1237: DPRINTFN(10,("%s: uhci_softintr (%d)\n", sc->sc_bus.bdev.dv_xname,
1238: sc->sc_bus.intr_context));
1239:
1240: sc->sc_bus.intr_context++;
1241:
1242: /*
1243: * Interrupts on UHCI really suck. When the host controller
1244: * interrupts because a transfer is completed there is no
1245: * way of knowing which transfer it was. You can scan down
1246: * the TDs and QHs of the previous frame to limit the search,
1247: * but that assumes that the interrupt was not delayed by more
1248: * than 1 ms, which may not always be true (e.g. after debug
1249: * output on a slow console).
1250: * We scan all interrupt descriptors to see if any have
1251: * completed.
1252: */
1253: for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = nextii) {
1254: nextii = LIST_NEXT(ii, list);
1255: uhci_check_intr(sc, ii);
1256: }
1257:
1258: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
1259: if (sc->sc_softwake) {
1260: sc->sc_softwake = 0;
1261: wakeup(&sc->sc_softwake);
1262: }
1263: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
1264:
1265: sc->sc_bus.intr_context--;
1266: }
1267:
1268: /* Check for an interrupt. */
1269: void
1270: uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii)
1271: {
1272: uhci_soft_td_t *std, *lstd;
1273: u_int32_t status;
1274:
1275: DPRINTFN(15, ("uhci_check_intr: ii=%p\n", ii));
1276: #ifdef DIAGNOSTIC
1277: if (ii == NULL) {
1278: printf("uhci_check_intr: no ii? %p\n", ii);
1279: return;
1280: }
1281: #endif
1282: if (ii->xfer->status == USBD_CANCELLED ||
1283: ii->xfer->status == USBD_TIMEOUT) {
1284: DPRINTF(("uhci_check_intr: aborted xfer=%p\n", ii->xfer));
1285: return;
1286: }
1287:
1288: if (ii->stdstart == NULL)
1289: return;
1290: lstd = ii->stdend;
1291: #ifdef DIAGNOSTIC
1292: if (lstd == NULL) {
1293: printf("uhci_check_intr: std==0\n");
1294: return;
1295: }
1296: #endif
1297: /*
1298: * If the last TD is still active we need to check whether there
1299: * is an error somewhere in the middle, or whether there was a
1300: * short packet (SPD and not ACTIVE).
1301: */
1302: if (letoh32(lstd->td.td_status) & UHCI_TD_ACTIVE) {
1303: DPRINTFN(12, ("uhci_check_intr: active ii=%p\n", ii));
1304: for (std = ii->stdstart; std != lstd; std = std->link.std) {
1305: status = letoh32(std->td.td_status);
1306: /* If there's an active TD the xfer isn't done. */
1307: if (status & UHCI_TD_ACTIVE)
1308: break;
1309: /* Any kind of error makes the xfer done. */
1310: if (status & UHCI_TD_STALLED)
1311: goto done;
1312: /* We want short packets, and it is short: it's done */
1313: if ((status & UHCI_TD_SPD) &&
1314: UHCI_TD_GET_ACTLEN(status) <
1315: UHCI_TD_GET_MAXLEN(letoh32(std->td.td_token)))
1316: goto done;
1317: }
1318: DPRINTFN(12, ("uhci_check_intr: ii=%p std=%p still active\n",
1319: ii, ii->stdstart));
1320: return;
1321: }
1322: done:
1323: DPRINTFN(12, ("uhci_check_intr: ii=%p done\n", ii));
1324: timeout_del(&ii->xfer->timeout_handle);
1325: uhci_idone(ii);
1326: }
1327:
1328: /* Called at splusb() */
1329: void
1330: uhci_idone(uhci_intr_info_t *ii)
1331: {
1332: usbd_xfer_handle xfer = ii->xfer;
1333: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
1334: uhci_soft_td_t *std;
1335: u_int32_t status = 0, nstatus;
1336: int actlen;
1337:
1338: DPRINTFN(12, ("uhci_idone: ii=%p\n", ii));
1339: #ifdef DIAGNOSTIC
1340: {
1341: int s = splhigh();
1342: if (ii->isdone) {
1343: splx(s);
1344: #ifdef UHCI_DEBUG
1345: printf("uhci_idone: ii is done!\n ");
1346: uhci_dump_ii(ii);
1347: #else
1348: printf("uhci_idone: ii=%p is done!\n", ii);
1349: #endif
1350: return;
1351: }
1352: ii->isdone = 1;
1353: splx(s);
1354: }
1355: #endif
1356:
1357: if (xfer->nframes != 0) {
1358: /* Isoc transfer, do things differently. */
1359: uhci_soft_td_t **stds = upipe->u.iso.stds;
1360: int i, n, nframes, len;
1361:
1362: DPRINTFN(5,("uhci_idone: ii=%p isoc ready\n", ii));
1363:
1364: nframes = xfer->nframes;
1365: actlen = 0;
1366: n = UXFER(xfer)->curframe;
1367: for (i = 0; i < nframes; i++) {
1368: std = stds[n];
1369: #ifdef UHCI_DEBUG
1370: if (uhcidebug > 5) {
1371: DPRINTFN(-1,("uhci_idone: isoc TD %d\n", i));
1372: uhci_dump_td(std);
1373: }
1374: #endif
1375: if (++n >= UHCI_VFRAMELIST_COUNT)
1376: n = 0;
1377: status = letoh32(std->td.td_status);
1378: len = UHCI_TD_GET_ACTLEN(status);
1379: xfer->frlengths[i] = len;
1380: actlen += len;
1381: }
1382: upipe->u.iso.inuse -= nframes;
1383: xfer->actlen = actlen;
1384: xfer->status = USBD_NORMAL_COMPLETION;
1385: goto end;
1386: }
1387:
1388: #ifdef UHCI_DEBUG
1389: DPRINTFN(10, ("uhci_idone: ii=%p, xfer=%p, pipe=%p ready\n",
1390: ii, xfer, upipe));
1391: if (uhcidebug > 10)
1392: uhci_dump_tds(ii->stdstart);
1393: #endif
1394:
1395: /* The transfer is done, compute actual length and status. */
1396: actlen = 0;
1397: for (std = ii->stdstart; std != NULL; std = std->link.std) {
1398: nstatus = letoh32(std->td.td_status);
1399: if (nstatus & UHCI_TD_ACTIVE)
1400: break;
1401:
1402: status = nstatus;
1403: if (UHCI_TD_GET_PID(letoh32(std->td.td_token)) !=
1404: UHCI_TD_PID_SETUP)
1405: actlen += UHCI_TD_GET_ACTLEN(status);
1406: else {
1407: /*
1408: * UHCI will report CRCTO in addition to a STALL or NAK
1409: * for a SETUP transaction. See section 3.2.2, "TD
1410: * CONTROL AND STATUS".
1411: */
1412: if (status & (UHCI_TD_STALLED | UHCI_TD_NAK))
1413: status &= ~UHCI_TD_CRCTO;
1414: }
1415: }
1416: /* If there are left over TDs we need to update the toggle. */
1417: if (std != NULL)
1418: upipe->nexttoggle = UHCI_TD_GET_DT(letoh32(std->td.td_token));
1419:
1420: status &= UHCI_TD_ERROR;
1421: DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n",
1422: actlen, status));
1423: xfer->actlen = actlen;
1424: if (status != 0) {
1425: #ifdef UHCI_DEBUG
1426: char sbuf[128];
1427:
1428: bitmask_snprintf((u_int32_t)status,
1429: "\20\22BITSTUFF\23CRCTO\24NAK\25"
1430: "BABBLE\26DBUFFER\27STALLED\30ACTIVE",
1431: sbuf, sizeof(sbuf));
1432:
1433: DPRINTFN((status == UHCI_TD_STALLED)*10,
1434: ("uhci_idone: error, addr=%d, endpt=0x%02x, "
1435: "status 0x%s\n",
1436: xfer->pipe->device->address,
1437: xfer->pipe->endpoint->edesc->bEndpointAddress,
1438: sbuf));
1439: #endif
1440:
1441: if (status == UHCI_TD_STALLED)
1442: xfer->status = USBD_STALLED;
1443: else
1444: xfer->status = USBD_IOERROR; /* more info XXX */
1445: } else {
1446: xfer->status = USBD_NORMAL_COMPLETION;
1447: }
1448:
1449: end:
1450: usb_transfer_complete(xfer);
1451: DPRINTFN(12, ("uhci_idone: ii=%p done\n", ii));
1452: }
1453:
1454: /*
1455: * Called when a request does not complete.
1456: */
1457: void
1458: uhci_timeout(void *addr)
1459: {
1460: uhci_intr_info_t *ii = addr;
1461: struct uhci_xfer *uxfer = UXFER(ii->xfer);
1462: struct uhci_pipe *upipe = (struct uhci_pipe *)uxfer->xfer.pipe;
1463: uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
1464:
1465: DPRINTF(("uhci_timeout: uxfer=%p\n", uxfer));
1466:
1467: if (sc->sc_dying) {
1468: uhci_abort_xfer(&uxfer->xfer, USBD_TIMEOUT);
1469: return;
1470: }
1471:
1472: /* Execute the abort in a process context. */
1473: usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer);
1474: usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task);
1475: }
1476:
1477: void
1478: uhci_timeout_task(void *addr)
1479: {
1480: usbd_xfer_handle xfer = addr;
1481: int s;
1482:
1483: DPRINTF(("uhci_timeout_task: xfer=%p\n", xfer));
1484:
1485: s = splusb();
1486: uhci_abort_xfer(xfer, USBD_TIMEOUT);
1487: splx(s);
1488: }
1489:
1490: /*
1491: * Wait here until controller claims to have an interrupt.
1492: * Then call uhci_intr and return. Use timeout to avoid waiting
1493: * too long.
1494: * Only used during boot when interrupts are not enabled yet.
1495: */
1496: void
1497: uhci_waitintr(uhci_softc_t *sc, usbd_xfer_handle xfer)
1498: {
1499: int timo = xfer->timeout;
1500: uhci_intr_info_t *ii;
1501:
1502: DPRINTFN(10,("uhci_waitintr: timeout = %dms\n", timo));
1503:
1504: xfer->status = USBD_IN_PROGRESS;
1505: for (; timo >= 0; timo--) {
1506: usb_delay_ms(&sc->sc_bus, 1);
1507: DPRINTFN(20,("uhci_waitintr: 0x%04x\n", UREAD2(sc, UHCI_STS)));
1508: if (UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS) {
1509: uhci_intr1(sc);
1510: if (xfer->status != USBD_IN_PROGRESS)
1511: return;
1512: }
1513: }
1514:
1515: /* Timeout */
1516: DPRINTF(("uhci_waitintr: timeout\n"));
1517: for (ii = LIST_FIRST(&sc->sc_intrhead);
1518: ii != NULL && ii->xfer != xfer;
1519: ii = LIST_NEXT(ii, list))
1520: ;
1521: #ifdef DIAGNOSTIC
1522: if (ii == NULL)
1523: panic("uhci_waitintr: lost intr_info");
1524: #endif
1525: uhci_idone(ii);
1526: }
1527:
1528: void
1529: uhci_poll(struct usbd_bus *bus)
1530: {
1531: uhci_softc_t *sc = (uhci_softc_t *)bus;
1532:
1533: if (UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS)
1534: uhci_intr1(sc);
1535: }
1536:
1537: void
1538: uhci_reset(uhci_softc_t *sc)
1539: {
1540: int n;
1541:
1542: UHCICMD(sc, UHCI_CMD_HCRESET);
1543: /* The reset bit goes low when the controller is done. */
1544: for (n = 0; n < UHCI_RESET_TIMEOUT &&
1545: (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++)
1546: usb_delay_ms(&sc->sc_bus, 1);
1547: if (n >= UHCI_RESET_TIMEOUT)
1548: printf("%s: controller did not reset\n",
1549: sc->sc_bus.bdev.dv_xname);
1550: }
1551:
1552: usbd_status
1553: uhci_run(uhci_softc_t *sc, int run)
1554: {
1555: int s, n, running;
1556: u_int16_t cmd;
1557:
1558: run = run != 0;
1559: s = splhardusb();
1560: DPRINTF(("uhci_run: setting run=%d\n", run));
1561: cmd = UREAD2(sc, UHCI_CMD);
1562: if (run)
1563: cmd |= UHCI_CMD_RS;
1564: else
1565: cmd &= ~UHCI_CMD_RS;
1566: UHCICMD(sc, cmd);
1567: for(n = 0; n < 10; n++) {
1568: running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH);
1569: /* return when we've entered the state we want */
1570: if (run == running) {
1571: splx(s);
1572: DPRINTF(("uhci_run: done cmd=0x%x sts=0x%x\n",
1573: UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS)));
1574: return (USBD_NORMAL_COMPLETION);
1575: }
1576: usb_delay_ms(&sc->sc_bus, 1);
1577: }
1578: splx(s);
1579: printf("%s: cannot %s\n", sc->sc_bus.bdev.dv_xname,
1580: run ? "start" : "stop");
1581: return (USBD_IOERROR);
1582: }
1583:
1584: /*
1585: * Memory management routines.
1586: * uhci_alloc_std allocates TDs
1587: * uhci_alloc_sqh allocates QHs
1588: * These two routines do their own free list management,
1589: * partly for speed, partly because allocating DMAable memory
1590: * has page size granularaity so much memory would be wasted if
1591: * only one TD/QH (32 bytes) was placed in each allocated chunk.
1592: */
1593:
1594: uhci_soft_td_t *
1595: uhci_alloc_std(uhci_softc_t *sc)
1596: {
1597: uhci_soft_td_t *std;
1598: usbd_status err;
1599: int i, offs;
1600: usb_dma_t dma;
1601:
1602: if (sc->sc_freetds == NULL) {
1603: DPRINTFN(2,("uhci_alloc_std: allocating chunk\n"));
1604: err = usb_allocmem(&sc->sc_bus, UHCI_STD_SIZE * UHCI_STD_CHUNK,
1605: UHCI_TD_ALIGN, &dma);
1606: if (err)
1607: return (0);
1608: for(i = 0; i < UHCI_STD_CHUNK; i++) {
1609: offs = i * UHCI_STD_SIZE;
1610: std = KERNADDR(&dma, offs);
1611: std->physaddr = DMAADDR(&dma, offs);
1612: std->link.std = sc->sc_freetds;
1613: sc->sc_freetds = std;
1614: }
1615: }
1616: std = sc->sc_freetds;
1617: sc->sc_freetds = std->link.std;
1618: memset(&std->td, 0, sizeof(uhci_td_t));
1619: return std;
1620: }
1621:
1622: void
1623: uhci_free_std(uhci_softc_t *sc, uhci_soft_td_t *std)
1624: {
1625: #ifdef DIAGNOSTIC
1626: #define TD_IS_FREE 0x12345678
1627: if (letoh32(std->td.td_token) == TD_IS_FREE) {
1628: printf("uhci_free_std: freeing free TD %p\n", std);
1629: return;
1630: }
1631: std->td.td_token = htole32(TD_IS_FREE);
1632: #endif
1633: std->link.std = sc->sc_freetds;
1634: sc->sc_freetds = std;
1635: }
1636:
1637: uhci_soft_qh_t *
1638: uhci_alloc_sqh(uhci_softc_t *sc)
1639: {
1640: uhci_soft_qh_t *sqh;
1641: usbd_status err;
1642: int i, offs;
1643: usb_dma_t dma;
1644:
1645: if (sc->sc_freeqhs == NULL) {
1646: DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n"));
1647: err = usb_allocmem(&sc->sc_bus, UHCI_SQH_SIZE * UHCI_SQH_CHUNK,
1648: UHCI_QH_ALIGN, &dma);
1649: if (err)
1650: return (0);
1651: for(i = 0; i < UHCI_SQH_CHUNK; i++) {
1652: offs = i * UHCI_SQH_SIZE;
1653: sqh = KERNADDR(&dma, offs);
1654: sqh->physaddr = DMAADDR(&dma, offs);
1655: sqh->hlink = sc->sc_freeqhs;
1656: sc->sc_freeqhs = sqh;
1657: }
1658: }
1659: sqh = sc->sc_freeqhs;
1660: sc->sc_freeqhs = sqh->hlink;
1661: memset(&sqh->qh, 0, sizeof(uhci_qh_t));
1662: return (sqh);
1663: }
1664:
1665: void
1666: uhci_free_sqh(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
1667: {
1668: sqh->hlink = sc->sc_freeqhs;
1669: sc->sc_freeqhs = sqh;
1670: }
1671:
1672: void
1673: uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std,
1674: uhci_soft_td_t *stdend)
1675: {
1676: uhci_soft_td_t *p;
1677:
1678: for (; std != stdend; std = p) {
1679: p = std->link.std;
1680: uhci_free_std(sc, std);
1681: }
1682: }
1683:
1684: usbd_status
1685: uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len,
1686: int rd, u_int16_t flags, usb_dma_t *dma,
1687: uhci_soft_td_t **sp, uhci_soft_td_t **ep)
1688: {
1689: uhci_soft_td_t *p, *lastp;
1690: uhci_physaddr_t lastlink;
1691: int i, ntd, l, tog, maxp;
1692: u_int32_t status;
1693: int addr = upipe->pipe.device->address;
1694: int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
1695:
1696: DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d speed=%d "
1697: "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len,
1698: upipe->pipe.device->speed, flags));
1699: maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize);
1700: if (maxp == 0) {
1701: printf("uhci_alloc_std_chain: maxp=0\n");
1702: return (USBD_INVAL);
1703: }
1704: ntd = (len + maxp - 1) / maxp;
1705: if ((flags & USBD_FORCE_SHORT_XFER) && len % maxp == 0)
1706: ntd++;
1707: DPRINTFN(10, ("uhci_alloc_std_chain: maxp=%d ntd=%d\n", maxp, ntd));
1708: if (ntd == 0) {
1709: *sp = *ep = 0;
1710: DPRINTFN(-1,("uhci_alloc_std_chain: ntd=0\n"));
1711: return (USBD_NORMAL_COMPLETION);
1712: }
1713: tog = upipe->nexttoggle;
1714: if (ntd % 2 == 0)
1715: tog ^= 1;
1716: upipe->nexttoggle = tog ^ 1;
1717: lastp = NULL;
1718: lastlink = UHCI_PTR_T;
1719: ntd--;
1720: status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
1721: if (upipe->pipe.device->speed == USB_SPEED_LOW)
1722: status |= UHCI_TD_LS;
1723: if (flags & USBD_SHORT_XFER_OK)
1724: status |= UHCI_TD_SPD;
1725: for (i = ntd; i >= 0; i--) {
1726: p = uhci_alloc_std(sc);
1727: if (p == NULL) {
1728: uhci_free_std_chain(sc, lastp, NULL);
1729: return (USBD_NOMEM);
1730: }
1731: p->link.std = lastp;
1732: p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD);
1733: lastp = p;
1734: lastlink = p->physaddr;
1735: p->td.td_status = htole32(status);
1736: if (i == ntd) {
1737: /* last TD */
1738: l = len % maxp;
1739: if (l == 0 && !(flags & USBD_FORCE_SHORT_XFER))
1740: l = maxp;
1741: *ep = p;
1742: } else
1743: l = maxp;
1744: p->td.td_token =
1745: htole32(rd ? UHCI_TD_IN (l, endpt, addr, tog) :
1746: UHCI_TD_OUT(l, endpt, addr, tog));
1747: p->td.td_buffer = htole32(DMAADDR(dma, i * maxp));
1748: tog ^= 1;
1749: }
1750: *sp = lastp;
1751: DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n",
1752: upipe->nexttoggle));
1753: return (USBD_NORMAL_COMPLETION);
1754: }
1755:
1756: void
1757: uhci_device_clear_toggle(usbd_pipe_handle pipe)
1758: {
1759: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
1760: upipe->nexttoggle = 0;
1761: }
1762:
1763: void
1764: uhci_noop(usbd_pipe_handle pipe)
1765: {
1766: }
1767:
1768: usbd_status
1769: uhci_device_bulk_transfer(usbd_xfer_handle xfer)
1770: {
1771: usbd_status err;
1772:
1773: /* Insert last in queue. */
1774: err = usb_insert_transfer(xfer);
1775: if (err)
1776: return (err);
1777:
1778: /*
1779: * Pipe isn't running (otherwise err would be USBD_INPROG),
1780: * so start it first.
1781: */
1782: return (uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
1783: }
1784:
1785: usbd_status
1786: uhci_device_bulk_start(usbd_xfer_handle xfer)
1787: {
1788: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
1789: usbd_device_handle dev = upipe->pipe.device;
1790: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
1791: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
1792: uhci_soft_td_t *data, *dataend;
1793: uhci_soft_qh_t *sqh;
1794: usbd_status err;
1795: int len, isread, endpt;
1796: int s;
1797:
1798: DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%d flags=%d ii=%p\n",
1799: xfer, xfer->length, xfer->flags, ii));
1800:
1801: if (sc->sc_dying)
1802: return (USBD_IOERROR);
1803:
1804: #ifdef DIAGNOSTIC
1805: if (xfer->rqflags & URQ_REQUEST)
1806: panic("uhci_device_bulk_transfer: a request");
1807: #endif
1808:
1809: len = xfer->length;
1810: endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
1811: isread = UE_GET_DIR(endpt) == UE_DIR_IN;
1812: sqh = upipe->u.bulk.sqh;
1813:
1814: upipe->u.bulk.isread = isread;
1815: upipe->u.bulk.length = len;
1816:
1817: err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags,
1818: &xfer->dmabuf, &data, &dataend);
1819: if (err)
1820: return (err);
1821: dataend->td.td_status |= htole32(UHCI_TD_IOC);
1822:
1823: #ifdef UHCI_DEBUG
1824: if (uhcidebug > 8) {
1825: DPRINTF(("uhci_device_bulk_transfer: data(1)\n"));
1826: uhci_dump_tds(data);
1827: }
1828: #endif
1829:
1830: /* Set up interrupt info. */
1831: ii->xfer = xfer;
1832: ii->stdstart = data;
1833: ii->stdend = dataend;
1834: #ifdef DIAGNOSTIC
1835: if (!ii->isdone) {
1836: printf("uhci_device_bulk_transfer: not done, ii=%p\n", ii);
1837: }
1838: ii->isdone = 0;
1839: #endif
1840:
1841: sqh->elink = data;
1842: sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
1843:
1844: s = splusb();
1845: uhci_add_bulk(sc, sqh);
1846: uhci_add_intr_info(sc, ii);
1847:
1848: if (xfer->timeout && !sc->sc_bus.use_polling) {
1849: timeout_del(&xfer->timeout_handle);
1850: timeout_set(&xfer->timeout_handle, uhci_timeout, ii);
1851: timeout_add(&xfer->timeout_handle, mstohz(xfer->timeout));
1852: }
1853: xfer->status = USBD_IN_PROGRESS;
1854: splx(s);
1855:
1856: #ifdef UHCI_DEBUG
1857: if (uhcidebug > 10) {
1858: DPRINTF(("uhci_device_bulk_transfer: data(2)\n"));
1859: uhci_dump_tds(data);
1860: }
1861: #endif
1862:
1863: if (sc->sc_bus.use_polling)
1864: uhci_waitintr(sc, xfer);
1865:
1866: return (USBD_IN_PROGRESS);
1867: }
1868:
1869: /* Abort a device bulk request. */
1870: void
1871: uhci_device_bulk_abort(usbd_xfer_handle xfer)
1872: {
1873: DPRINTF(("uhci_device_bulk_abort:\n"));
1874: uhci_abort_xfer(xfer, USBD_CANCELLED);
1875: }
1876:
1877: /*
1878: * Abort a device request.
1879: * If this routine is called at splusb() it guarantees that the request
1880: * will be removed from the hardware scheduling and that the callback
1881: * for it will be called with USBD_CANCELLED status.
1882: * It's impossible to guarantee that the requested transfer will not
1883: * have happened since the hardware runs concurrently.
1884: * If the transaction has already happened we rely on the ordinary
1885: * interrupt processing to process it.
1886: */
1887: void
1888: uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
1889: {
1890: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
1891: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
1892: uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
1893: uhci_soft_td_t *std;
1894: int s;
1895:
1896: DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
1897:
1898: if (sc->sc_dying) {
1899: /* If we're dying, just do the software part. */
1900: s = splusb();
1901: xfer->status = status; /* make software ignore it */
1902: timeout_del(&xfer->timeout_handle);
1903: usb_transfer_complete(xfer);
1904: splx(s);
1905: return;
1906: }
1907:
1908: if (xfer->device->bus->intr_context || !curproc)
1909: panic("uhci_abort_xfer: not in process context");
1910:
1911: /*
1912: * Step 1: Make interrupt routine and hardware ignore xfer.
1913: */
1914: s = splusb();
1915: xfer->status = status; /* make software ignore it */
1916: timeout_del(&xfer->timeout_handle);
1917: DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii));
1918: for (std = ii->stdstart; std != NULL; std = std->link.std)
1919: std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
1920: splx(s);
1921:
1922: /*
1923: * Step 2: Wait until we know hardware has finished any possible
1924: * use of the xfer. Also make sure the soft interrupt routine
1925: * has run.
1926: */
1927: usb_delay_ms(upipe->pipe.device->bus, 2); /* Hardware finishes in 1ms */
1928: s = splusb();
1929: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
1930: sc->sc_softwake = 1;
1931: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
1932: usb_schedsoftintr(&sc->sc_bus);
1933: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
1934: DPRINTFN(1,("uhci_abort_xfer: tsleep\n"));
1935: tsleep(&sc->sc_softwake, PZERO, "uhciab", 0);
1936: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
1937: splx(s);
1938:
1939: /*
1940: * Step 3: Execute callback.
1941: */
1942: DPRINTFN(1,("uhci_abort_xfer: callback\n"));
1943: s = splusb();
1944: #ifdef DIAGNOSTIC
1945: ii->isdone = 1;
1946: #endif
1947: usb_transfer_complete(xfer);
1948: splx(s);
1949: }
1950:
1951: /* Close a device bulk pipe. */
1952: void
1953: uhci_device_bulk_close(usbd_pipe_handle pipe)
1954: {
1955: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
1956: usbd_device_handle dev = upipe->pipe.device;
1957: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
1958:
1959: uhci_free_sqh(sc, upipe->u.bulk.sqh);
1960: pipe->endpoint->savedtoggle = upipe->nexttoggle;
1961: }
1962:
1963: usbd_status
1964: uhci_device_ctrl_transfer(usbd_xfer_handle xfer)
1965: {
1966: usbd_status err;
1967:
1968: /* Insert last in queue. */
1969: err = usb_insert_transfer(xfer);
1970: if (err)
1971: return (err);
1972:
1973: /*
1974: * Pipe isn't running (otherwise err would be USBD_INPROG),
1975: * so start it first.
1976: */
1977: return (uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
1978: }
1979:
1980: usbd_status
1981: uhci_device_ctrl_start(usbd_xfer_handle xfer)
1982: {
1983: uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;
1984: usbd_status err;
1985:
1986: if (sc->sc_dying)
1987: return (USBD_IOERROR);
1988:
1989: #ifdef DIAGNOSTIC
1990: if (!(xfer->rqflags & URQ_REQUEST))
1991: panic("uhci_device_ctrl_transfer: not a request");
1992: #endif
1993:
1994: err = uhci_device_request(xfer);
1995: if (err)
1996: return (err);
1997:
1998: if (sc->sc_bus.use_polling)
1999: uhci_waitintr(sc, xfer);
2000: return (USBD_IN_PROGRESS);
2001: }
2002:
2003: usbd_status
2004: uhci_device_intr_transfer(usbd_xfer_handle xfer)
2005: {
2006: usbd_status err;
2007:
2008: /* Insert last in queue. */
2009: err = usb_insert_transfer(xfer);
2010: if (err)
2011: return (err);
2012:
2013: /*
2014: * Pipe isn't running (otherwise err would be USBD_INPROG),
2015: * so start it first.
2016: */
2017: return (uhci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
2018: }
2019:
2020: usbd_status
2021: uhci_device_intr_start(usbd_xfer_handle xfer)
2022: {
2023: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
2024: usbd_device_handle dev = upipe->pipe.device;
2025: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
2026: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
2027: uhci_soft_td_t *data, *dataend;
2028: uhci_soft_qh_t *sqh;
2029: usbd_status err;
2030: int isread, endpt;
2031: int i, s;
2032:
2033: if (sc->sc_dying)
2034: return (USBD_IOERROR);
2035:
2036: DPRINTFN(3,("uhci_device_intr_transfer: xfer=%p len=%d flags=%d\n",
2037: xfer, xfer->length, xfer->flags));
2038:
2039: #ifdef DIAGNOSTIC
2040: if (xfer->rqflags & URQ_REQUEST)
2041: panic("uhci_device_intr_transfer: a request");
2042: #endif
2043:
2044: endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
2045: isread = UE_GET_DIR(endpt) == UE_DIR_IN;
2046:
2047: upipe->u.intr.isread = isread;
2048:
2049: err = uhci_alloc_std_chain(upipe, sc, xfer->length, isread,
2050: xfer->flags, &xfer->dmabuf, &data,
2051: &dataend);
2052:
2053: if (err)
2054: return (err);
2055: dataend->td.td_status |= htole32(UHCI_TD_IOC);
2056:
2057: #ifdef UHCI_DEBUG
2058: if (uhcidebug > 10) {
2059: DPRINTF(("uhci_device_intr_transfer: data(1)\n"));
2060: uhci_dump_tds(data);
2061: uhci_dump_qh(upipe->u.intr.qhs[0]);
2062: }
2063: #endif
2064:
2065: s = splusb();
2066: /* Set up interrupt info. */
2067: ii->xfer = xfer;
2068: ii->stdstart = data;
2069: ii->stdend = dataend;
2070: #ifdef DIAGNOSTIC
2071: if (!ii->isdone) {
2072: printf("uhci_device_intr_transfer: not done, ii=%p\n", ii);
2073: }
2074: ii->isdone = 0;
2075: #endif
2076:
2077: DPRINTFN(10,("uhci_device_intr_transfer: qhs[0]=%p\n",
2078: upipe->u.intr.qhs[0]));
2079: for (i = 0; i < upipe->u.intr.npoll; i++) {
2080: sqh = upipe->u.intr.qhs[i];
2081: sqh->elink = data;
2082: sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
2083: }
2084: uhci_add_intr_info(sc, ii);
2085: xfer->status = USBD_IN_PROGRESS;
2086: splx(s);
2087:
2088: #ifdef UHCI_DEBUG
2089: if (uhcidebug > 10) {
2090: DPRINTF(("uhci_device_intr_transfer: data(2)\n"));
2091: uhci_dump_tds(data);
2092: uhci_dump_qh(upipe->u.intr.qhs[0]);
2093: }
2094: #endif
2095:
2096: return (USBD_IN_PROGRESS);
2097: }
2098:
2099: /* Abort a device control request. */
2100: void
2101: uhci_device_ctrl_abort(usbd_xfer_handle xfer)
2102: {
2103: DPRINTF(("uhci_device_ctrl_abort:\n"));
2104: uhci_abort_xfer(xfer, USBD_CANCELLED);
2105: }
2106:
2107: /* Close a device control pipe. */
2108: void
2109: uhci_device_ctrl_close(usbd_pipe_handle pipe)
2110: {
2111: }
2112:
2113: /* Abort a device interrupt request. */
2114: void
2115: uhci_device_intr_abort(usbd_xfer_handle xfer)
2116: {
2117: DPRINTFN(1,("uhci_device_intr_abort: xfer=%p\n", xfer));
2118: if (xfer->pipe->intrxfer == xfer) {
2119: DPRINTFN(1,("uhci_device_intr_abort: remove\n"));
2120: xfer->pipe->intrxfer = NULL;
2121: }
2122: uhci_abort_xfer(xfer, USBD_CANCELLED);
2123: }
2124:
2125: /* Close a device interrupt pipe. */
2126: void
2127: uhci_device_intr_close(usbd_pipe_handle pipe)
2128: {
2129: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
2130: uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
2131: int i, npoll;
2132: int s;
2133:
2134: /* Unlink descriptors from controller data structures. */
2135: npoll = upipe->u.intr.npoll;
2136: s = splusb();
2137: for (i = 0; i < npoll; i++)
2138: uhci_remove_intr(sc, upipe->u.intr.qhs[i]);
2139: splx(s);
2140:
2141: /*
2142: * We now have to wait for any activity on the physical
2143: * descriptors to stop.
2144: */
2145: usb_delay_ms(&sc->sc_bus, 2);
2146:
2147: for(i = 0; i < npoll; i++)
2148: uhci_free_sqh(sc, upipe->u.intr.qhs[i]);
2149: free(upipe->u.intr.qhs, M_USBHC);
2150:
2151: /* XXX free other resources */
2152: }
2153:
2154: usbd_status
2155: uhci_device_request(usbd_xfer_handle xfer)
2156: {
2157: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
2158: usb_device_request_t *req = &xfer->request;
2159: usbd_device_handle dev = upipe->pipe.device;
2160: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
2161: int addr = dev->address;
2162: int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
2163: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
2164: uhci_soft_td_t *setup, *data, *stat, *next, *dataend;
2165: uhci_soft_qh_t *sqh;
2166: int len;
2167: u_int32_t ls;
2168: usbd_status err;
2169: int isread;
2170: int s;
2171:
2172: DPRINTFN(3,("uhci_device_control type=0x%02x, request=0x%02x, "
2173: "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n",
2174: req->bmRequestType, req->bRequest, UGETW(req->wValue),
2175: UGETW(req->wIndex), UGETW(req->wLength),
2176: addr, endpt));
2177:
2178: ls = dev->speed == USB_SPEED_LOW ? UHCI_TD_LS : 0;
2179: isread = req->bmRequestType & UT_READ;
2180: len = UGETW(req->wLength);
2181:
2182: setup = upipe->u.ctl.setup;
2183: stat = upipe->u.ctl.stat;
2184: sqh = upipe->u.ctl.sqh;
2185:
2186: /* Set up data transaction */
2187: if (len != 0) {
2188: upipe->nexttoggle = 1;
2189: err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags,
2190: &xfer->dmabuf, &data, &dataend);
2191: if (err)
2192: return (err);
2193: next = data;
2194: dataend->link.std = stat;
2195: dataend->td.td_link = htole32(stat->physaddr | UHCI_PTR_VF | UHCI_PTR_TD);
2196: } else {
2197: next = stat;
2198: }
2199: upipe->u.ctl.length = len;
2200:
2201: memcpy(KERNADDR(&upipe->u.ctl.reqdma, 0), req, sizeof *req);
2202:
2203: setup->link.std = next;
2204: setup->td.td_link = htole32(next->physaddr | UHCI_PTR_VF | UHCI_PTR_TD);
2205: setup->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
2206: UHCI_TD_ACTIVE);
2207: setup->td.td_token = htole32(UHCI_TD_SETUP(sizeof *req, endpt, addr));
2208: setup->td.td_buffer = htole32(DMAADDR(&upipe->u.ctl.reqdma, 0));
2209:
2210: stat->link.std = NULL;
2211: stat->td.td_link = htole32(UHCI_PTR_T);
2212: stat->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
2213: UHCI_TD_ACTIVE | UHCI_TD_IOC);
2214: stat->td.td_token =
2215: htole32(isread ? UHCI_TD_OUT(0, endpt, addr, 1) :
2216: UHCI_TD_IN (0, endpt, addr, 1));
2217: stat->td.td_buffer = htole32(0);
2218:
2219: #ifdef UHCI_DEBUG
2220: if (uhcidebug > 10) {
2221: DPRINTF(("uhci_device_request: before transfer\n"));
2222: uhci_dump_tds(setup);
2223: }
2224: #endif
2225:
2226: /* Set up interrupt info. */
2227: ii->xfer = xfer;
2228: ii->stdstart = setup;
2229: ii->stdend = stat;
2230: #ifdef DIAGNOSTIC
2231: if (!ii->isdone) {
2232: printf("uhci_device_request: not done, ii=%p\n", ii);
2233: }
2234: ii->isdone = 0;
2235: #endif
2236:
2237: sqh->elink = setup;
2238: sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD);
2239:
2240: s = splusb();
2241: if (dev->speed == USB_SPEED_LOW)
2242: uhci_add_ls_ctrl(sc, sqh);
2243: else
2244: uhci_add_hs_ctrl(sc, sqh);
2245: uhci_add_intr_info(sc, ii);
2246: #ifdef UHCI_DEBUG
2247: if (uhcidebug > 12) {
2248: uhci_soft_td_t *std;
2249: uhci_soft_qh_t *xqh;
2250: uhci_soft_qh_t *sxqh;
2251: int maxqh = 0;
2252: uhci_physaddr_t link;
2253: DPRINTF(("uhci_enter_ctl_q: follow from [0]\n"));
2254: for (std = sc->sc_vframes[0].htd, link = 0;
2255: (link & UHCI_PTR_QH) == 0;
2256: std = std->link.std) {
2257: link = letoh32(std->td.td_link);
2258: uhci_dump_td(std);
2259: }
2260: sxqh = (uhci_soft_qh_t *)std;
2261: uhci_dump_qh(sxqh);
2262: for (xqh = sxqh;
2263: xqh != NULL;
2264: xqh = (maxqh++ == 5 || xqh->hlink == sxqh ||
2265: xqh->hlink == xqh ? NULL : xqh->hlink)) {
2266: uhci_dump_qh(xqh);
2267: }
2268: DPRINTF(("Enqueued QH:\n"));
2269: uhci_dump_qh(sqh);
2270: uhci_dump_tds(sqh->elink);
2271: }
2272: #endif
2273: if (xfer->timeout && !sc->sc_bus.use_polling) {
2274: timeout_del(&xfer->timeout_handle);
2275: timeout_set(&xfer->timeout_handle, uhci_timeout, ii);
2276: timeout_add(&xfer->timeout_handle, mstohz(xfer->timeout));
2277: }
2278: xfer->status = USBD_IN_PROGRESS;
2279: splx(s);
2280:
2281: return (USBD_NORMAL_COMPLETION);
2282: }
2283:
2284: usbd_status
2285: uhci_device_isoc_transfer(usbd_xfer_handle xfer)
2286: {
2287: usbd_status err;
2288:
2289: DPRINTFN(5,("uhci_device_isoc_transfer: xfer=%p\n", xfer));
2290:
2291: /* Put it on our queue, */
2292: err = usb_insert_transfer(xfer);
2293:
2294: /* bail out on error, */
2295: if (err && err != USBD_IN_PROGRESS)
2296: return (err);
2297:
2298: /* XXX should check inuse here */
2299:
2300: /* insert into schedule, */
2301: uhci_device_isoc_enter(xfer);
2302:
2303: /* and start if the pipe wasn't running */
2304: if (!err)
2305: uhci_device_isoc_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
2306:
2307: return (err);
2308: }
2309:
2310: void
2311: uhci_device_isoc_enter(usbd_xfer_handle xfer)
2312: {
2313: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
2314: usbd_device_handle dev = upipe->pipe.device;
2315: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
2316: struct iso *iso = &upipe->u.iso;
2317: uhci_soft_td_t *std;
2318: u_int32_t buf, len, status;
2319: int s, i, next, nframes;
2320:
2321: DPRINTFN(5,("uhci_device_isoc_enter: used=%d next=%d xfer=%p "
2322: "nframes=%d\n",
2323: iso->inuse, iso->next, xfer, xfer->nframes));
2324:
2325: if (sc->sc_dying)
2326: return;
2327:
2328: if (xfer->status == USBD_IN_PROGRESS) {
2329: /* This request has already been entered into the frame list */
2330: printf("uhci_device_isoc_enter: xfer=%p in frame list\n", xfer);
2331: /* XXX */
2332: }
2333:
2334: #ifdef DIAGNOSTIC
2335: if (iso->inuse >= UHCI_VFRAMELIST_COUNT)
2336: printf("uhci_device_isoc_enter: overflow!\n");
2337: #endif
2338:
2339: next = iso->next;
2340: if (next == -1) {
2341: /* Not in use yet, schedule it a few frames ahead. */
2342: next = (UREAD2(sc, UHCI_FRNUM) + 3) % UHCI_VFRAMELIST_COUNT;
2343: DPRINTFN(2,("uhci_device_isoc_enter: start next=%d\n", next));
2344: }
2345:
2346: xfer->status = USBD_IN_PROGRESS;
2347: UXFER(xfer)->curframe = next;
2348:
2349: buf = DMAADDR(&xfer->dmabuf, 0);
2350: status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) |
2351: UHCI_TD_ACTIVE |
2352: UHCI_TD_IOS);
2353: nframes = xfer->nframes;
2354: s = splusb();
2355: for (i = 0; i < nframes; i++) {
2356: std = iso->stds[next];
2357: if (++next >= UHCI_VFRAMELIST_COUNT)
2358: next = 0;
2359: len = xfer->frlengths[i];
2360: std->td.td_buffer = htole32(buf);
2361: if (i == nframes - 1)
2362: status |= UHCI_TD_IOC;
2363: std->td.td_status = htole32(status);
2364: std->td.td_token &= htole32(~UHCI_TD_MAXLEN_MASK);
2365: std->td.td_token |= htole32(UHCI_TD_SET_MAXLEN(len));
2366: #ifdef UHCI_DEBUG
2367: if (uhcidebug > 5) {
2368: DPRINTFN(5,("uhci_device_isoc_enter: TD %d\n", i));
2369: uhci_dump_td(std);
2370: }
2371: #endif
2372: buf += len;
2373: }
2374: iso->next = next;
2375: iso->inuse += xfer->nframes;
2376:
2377: splx(s);
2378: }
2379:
2380: usbd_status
2381: uhci_device_isoc_start(usbd_xfer_handle xfer)
2382: {
2383: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
2384: uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
2385: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
2386: uhci_soft_td_t *end;
2387: int s, i;
2388:
2389: DPRINTFN(5,("uhci_device_isoc_start: xfer=%p\n", xfer));
2390:
2391: if (sc->sc_dying)
2392: return (USBD_IOERROR);
2393:
2394: #ifdef DIAGNOSTIC
2395: if (xfer->status != USBD_IN_PROGRESS)
2396: printf("uhci_device_isoc_start: not in progress %p\n", xfer);
2397: #endif
2398:
2399: /* Find the last TD */
2400: i = UXFER(xfer)->curframe + xfer->nframes;
2401: if (i >= UHCI_VFRAMELIST_COUNT)
2402: i -= UHCI_VFRAMELIST_COUNT;
2403: end = upipe->u.iso.stds[i];
2404:
2405: #ifdef DIAGNOSTIC
2406: if (end == NULL) {
2407: printf("uhci_device_isoc_start: end == NULL\n");
2408: return (USBD_INVAL);
2409: }
2410: #endif
2411:
2412: s = splusb();
2413:
2414: /* Set up interrupt info. */
2415: ii->xfer = xfer;
2416: ii->stdstart = end;
2417: ii->stdend = end;
2418: #ifdef DIAGNOSTIC
2419: if (!ii->isdone)
2420: printf("uhci_device_isoc_start: not done, ii=%p\n", ii);
2421: ii->isdone = 0;
2422: #endif
2423: uhci_add_intr_info(sc, ii);
2424:
2425: splx(s);
2426:
2427: return (USBD_IN_PROGRESS);
2428: }
2429:
2430: void
2431: uhci_device_isoc_abort(usbd_xfer_handle xfer)
2432: {
2433: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
2434: uhci_soft_td_t **stds = upipe->u.iso.stds;
2435: uhci_soft_td_t *std;
2436: int i, n, s, nframes, maxlen, len;
2437:
2438: s = splusb();
2439:
2440: /* Transfer is already done. */
2441: if (xfer->status != USBD_NOT_STARTED &&
2442: xfer->status != USBD_IN_PROGRESS) {
2443: splx(s);
2444: return;
2445: }
2446:
2447: /* Give xfer the requested abort code. */
2448: xfer->status = USBD_CANCELLED;
2449:
2450: /* make hardware ignore it, */
2451: nframes = xfer->nframes;
2452: n = UXFER(xfer)->curframe;
2453: maxlen = 0;
2454: for (i = 0; i < nframes; i++) {
2455: std = stds[n];
2456: std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
2457: len = UHCI_TD_GET_MAXLEN(letoh32(std->td.td_token));
2458: if (len > maxlen)
2459: maxlen = len;
2460: if (++n >= UHCI_VFRAMELIST_COUNT)
2461: n = 0;
2462: }
2463:
2464: /* and wait until we are sure the hardware has finished. */
2465: delay(maxlen);
2466:
2467: #ifdef DIAGNOSTIC
2468: UXFER(xfer)->iinfo.isdone = 1;
2469: #endif
2470: /* Run callback and remove from interrupt list. */
2471: usb_transfer_complete(xfer);
2472:
2473: splx(s);
2474: }
2475:
2476: void
2477: uhci_device_isoc_close(usbd_pipe_handle pipe)
2478: {
2479: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
2480: usbd_device_handle dev = upipe->pipe.device;
2481: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
2482: uhci_soft_td_t *std, *vstd;
2483: struct iso *iso;
2484: int i, s;
2485:
2486: /*
2487: * Make sure all TDs are marked as inactive.
2488: * Wait for completion.
2489: * Unschedule.
2490: * Deallocate.
2491: */
2492: iso = &upipe->u.iso;
2493:
2494: for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++)
2495: iso->stds[i]->td.td_status &= htole32(~UHCI_TD_ACTIVE);
2496: usb_delay_ms(&sc->sc_bus, 2); /* wait for completion */
2497:
2498: s = splusb();
2499: for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
2500: std = iso->stds[i];
2501: for (vstd = sc->sc_vframes[i].htd;
2502: vstd != NULL && vstd->link.std != std;
2503: vstd = vstd->link.std)
2504: ;
2505: if (vstd == NULL) {
2506: /*panic*/
2507: printf("uhci_device_isoc_close: %p not found\n", std);
2508: splx(s);
2509: return;
2510: }
2511: vstd->link = std->link;
2512: vstd->td.td_link = std->td.td_link;
2513: uhci_free_std(sc, std);
2514: }
2515: splx(s);
2516:
2517: free(iso->stds, M_USBHC);
2518: }
2519:
2520: usbd_status
2521: uhci_setup_isoc(usbd_pipe_handle pipe)
2522: {
2523: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
2524: usbd_device_handle dev = upipe->pipe.device;
2525: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
2526: int addr = upipe->pipe.device->address;
2527: int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
2528: int rd = UE_GET_DIR(endpt) == UE_DIR_IN;
2529: uhci_soft_td_t *std, *vstd;
2530: u_int32_t token;
2531: struct iso *iso;
2532: int i, s;
2533:
2534: iso = &upipe->u.iso;
2535: iso->stds = malloc(UHCI_VFRAMELIST_COUNT * sizeof (uhci_soft_td_t *),
2536: M_USBHC, M_WAITOK);
2537:
2538: token = rd ? UHCI_TD_IN (0, endpt, addr, 0) :
2539: UHCI_TD_OUT(0, endpt, addr, 0);
2540:
2541: /* Allocate the TDs and mark as inactive; */
2542: for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
2543: std = uhci_alloc_std(sc);
2544: if (std == 0)
2545: goto bad;
2546: std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
2547: std->td.td_token = htole32(token);
2548: iso->stds[i] = std;
2549: }
2550:
2551: /* Insert TDs into schedule. */
2552: s = splusb();
2553: for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
2554: std = iso->stds[i];
2555: vstd = sc->sc_vframes[i].htd;
2556: std->link = vstd->link;
2557: std->td.td_link = vstd->td.td_link;
2558: vstd->link.std = std;
2559: vstd->td.td_link = htole32(std->physaddr | UHCI_PTR_TD);
2560: }
2561: splx(s);
2562:
2563: iso->next = -1;
2564: iso->inuse = 0;
2565:
2566: return (USBD_NORMAL_COMPLETION);
2567:
2568: bad:
2569: while (--i >= 0)
2570: uhci_free_std(sc, iso->stds[i]);
2571: free(iso->stds, M_USBHC);
2572: return (USBD_NOMEM);
2573: }
2574:
2575: void
2576: uhci_device_isoc_done(usbd_xfer_handle xfer)
2577: {
2578: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
2579:
2580: DPRINTFN(4, ("uhci_isoc_done: length=%d\n", xfer->actlen));
2581:
2582: if (ii->xfer != xfer)
2583: /* Not on interrupt list, ignore it. */
2584: return;
2585:
2586: if (!uhci_active_intr_info(ii))
2587: return;
2588:
2589: #ifdef DIAGNOSTIC
2590: if (xfer->busy_free == XFER_FREE) {
2591: printf("uhci_device_isoc_done: xfer=%p is free\n", xfer);
2592: return;
2593: }
2594:
2595: if (ii->stdend == NULL) {
2596: printf("uhci_device_isoc_done: xfer=%p stdend==NULL\n", xfer);
2597: #ifdef UHCI_DEBUG
2598: uhci_dump_ii(ii);
2599: #endif
2600: return;
2601: }
2602: #endif
2603:
2604: /* Turn off the interrupt since it is active even if the TD is not. */
2605: ii->stdend->td.td_status &= htole32(~UHCI_TD_IOC);
2606:
2607: uhci_del_intr_info(ii); /* remove from active list */
2608: }
2609:
2610: void
2611: uhci_device_intr_done(usbd_xfer_handle xfer)
2612: {
2613: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
2614: uhci_softc_t *sc = ii->sc;
2615: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
2616: uhci_soft_qh_t *sqh;
2617: int i, npoll;
2618:
2619: DPRINTFN(5, ("uhci_device_intr_done: length=%d\n", xfer->actlen));
2620:
2621: npoll = upipe->u.intr.npoll;
2622: for(i = 0; i < npoll; i++) {
2623: sqh = upipe->u.intr.qhs[i];
2624: sqh->elink = NULL;
2625: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
2626: }
2627: uhci_free_std_chain(sc, ii->stdstart, NULL);
2628:
2629: /* XXX Wasteful. */
2630: if (xfer->pipe->repeat) {
2631: uhci_soft_td_t *data, *dataend;
2632:
2633: DPRINTFN(5,("uhci_device_intr_done: requeing\n"));
2634:
2635: /* This alloc cannot fail since we freed the chain above. */
2636: uhci_alloc_std_chain(upipe, sc, xfer->length,
2637: upipe->u.intr.isread, xfer->flags,
2638: &xfer->dmabuf, &data, &dataend);
2639: dataend->td.td_status |= htole32(UHCI_TD_IOC);
2640:
2641: #ifdef UHCI_DEBUG
2642: if (uhcidebug > 10) {
2643: DPRINTF(("uhci_device_intr_done: data(1)\n"));
2644: uhci_dump_tds(data);
2645: uhci_dump_qh(upipe->u.intr.qhs[0]);
2646: }
2647: #endif
2648:
2649: ii->stdstart = data;
2650: ii->stdend = dataend;
2651: #ifdef DIAGNOSTIC
2652: if (!ii->isdone) {
2653: printf("uhci_device_intr_done: not done, ii=%p\n", ii);
2654: }
2655: ii->isdone = 0;
2656: #endif
2657: for (i = 0; i < npoll; i++) {
2658: sqh = upipe->u.intr.qhs[i];
2659: sqh->elink = data;
2660: sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
2661: }
2662: xfer->status = USBD_IN_PROGRESS;
2663: /* The ii is already on the examined list, just leave it. */
2664: } else {
2665: DPRINTFN(5,("uhci_device_intr_done: removing\n"));
2666: if (uhci_active_intr_info(ii))
2667: uhci_del_intr_info(ii);
2668: }
2669: }
2670:
2671: /* Deallocate request data structures */
2672: void
2673: uhci_device_ctrl_done(usbd_xfer_handle xfer)
2674: {
2675: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
2676: uhci_softc_t *sc = ii->sc;
2677: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
2678:
2679: #ifdef DIAGNOSTIC
2680: if (!(xfer->rqflags & URQ_REQUEST))
2681: panic("uhci_device_ctrl_done: not a request");
2682: #endif
2683:
2684: if (!uhci_active_intr_info(ii))
2685: return;
2686:
2687: uhci_del_intr_info(ii); /* remove from active list */
2688:
2689: if (upipe->pipe.device->speed == USB_SPEED_LOW)
2690: uhci_remove_ls_ctrl(sc, upipe->u.ctl.sqh);
2691: else
2692: uhci_remove_hs_ctrl(sc, upipe->u.ctl.sqh);
2693:
2694: if (upipe->u.ctl.length != 0)
2695: uhci_free_std_chain(sc, ii->stdstart->link.std, ii->stdend);
2696:
2697: DPRINTFN(5, ("uhci_device_ctrl_done: length=%d\n", xfer->actlen));
2698: }
2699:
2700: /* Deallocate request data structures */
2701: void
2702: uhci_device_bulk_done(usbd_xfer_handle xfer)
2703: {
2704: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
2705: uhci_softc_t *sc = ii->sc;
2706: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
2707:
2708: DPRINTFN(5,("uhci_device_bulk_done: xfer=%p ii=%p sc=%p upipe=%p\n",
2709: xfer, ii, sc, upipe));
2710:
2711: if (!uhci_active_intr_info(ii))
2712: return;
2713:
2714: uhci_del_intr_info(ii); /* remove from active list */
2715:
2716: uhci_remove_bulk(sc, upipe->u.bulk.sqh);
2717:
2718: uhci_free_std_chain(sc, ii->stdstart, NULL);
2719:
2720: DPRINTFN(5, ("uhci_device_bulk_done: length=%d\n", xfer->actlen));
2721: }
2722:
2723: /* Add interrupt QH, called with vflock. */
2724: void
2725: uhci_add_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
2726: {
2727: struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
2728: uhci_soft_qh_t *eqh;
2729:
2730: DPRINTFN(4, ("uhci_add_intr: n=%d sqh=%p\n", sqh->pos, sqh));
2731:
2732: eqh = vf->eqh;
2733: sqh->hlink = eqh->hlink;
2734: sqh->qh.qh_hlink = eqh->qh.qh_hlink;
2735: eqh->hlink = sqh;
2736: eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
2737: vf->eqh = sqh;
2738: vf->bandwidth++;
2739: }
2740:
2741: /* Remove interrupt QH. */
2742: void
2743: uhci_remove_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
2744: {
2745: struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
2746: uhci_soft_qh_t *pqh;
2747:
2748: DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", sqh->pos, sqh));
2749:
2750: /* See comment in uhci_remove_ctrl() */
2751: if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
2752: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
2753: delay(UHCI_QH_REMOVE_DELAY);
2754: }
2755:
2756: pqh = uhci_find_prev_qh(vf->hqh, sqh);
2757: pqh->hlink = sqh->hlink;
2758: pqh->qh.qh_hlink = sqh->qh.qh_hlink;
2759: delay(UHCI_QH_REMOVE_DELAY);
2760: if (vf->eqh == sqh)
2761: vf->eqh = pqh;
2762: vf->bandwidth--;
2763: }
2764:
2765: usbd_status
2766: uhci_device_setintr(uhci_softc_t *sc, struct uhci_pipe *upipe, int ival)
2767: {
2768: uhci_soft_qh_t *sqh;
2769: int i, npoll, s;
2770: u_int bestbw, bw, bestoffs, offs;
2771:
2772: DPRINTFN(2, ("uhci_device_setintr: pipe=%p\n", upipe));
2773: if (ival == 0) {
2774: printf("uhci_device_setintr: 0 interval\n");
2775: return (USBD_INVAL);
2776: }
2777:
2778: if (ival > UHCI_VFRAMELIST_COUNT)
2779: ival = UHCI_VFRAMELIST_COUNT;
2780: npoll = (UHCI_VFRAMELIST_COUNT + ival - 1) / ival;
2781: DPRINTFN(2, ("uhci_device_setintr: ival=%d npoll=%d\n", ival, npoll));
2782:
2783: upipe->u.intr.npoll = npoll;
2784: upipe->u.intr.qhs =
2785: malloc(npoll * sizeof(uhci_soft_qh_t *), M_USBHC, M_WAITOK);
2786:
2787: /*
2788: * Figure out which offset in the schedule that has most
2789: * bandwidth left over.
2790: */
2791: #define MOD(i) ((i) & (UHCI_VFRAMELIST_COUNT-1))
2792: for (bestoffs = offs = 0, bestbw = ~0; offs < ival; offs++) {
2793: for (bw = i = 0; i < npoll; i++)
2794: bw += sc->sc_vframes[MOD(i * ival + offs)].bandwidth;
2795: if (bw < bestbw) {
2796: bestbw = bw;
2797: bestoffs = offs;
2798: }
2799: }
2800: DPRINTFN(1, ("uhci_device_setintr: bw=%d offs=%d\n", bestbw, bestoffs));
2801:
2802: for(i = 0; i < npoll; i++) {
2803: upipe->u.intr.qhs[i] = sqh = uhci_alloc_sqh(sc);
2804: sqh->elink = NULL;
2805: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
2806: sqh->pos = MOD(i * ival + bestoffs);
2807: }
2808: #undef MOD
2809:
2810: s = splusb();
2811: /* Enter QHs into the controller data structures. */
2812: for(i = 0; i < npoll; i++)
2813: uhci_add_intr(sc, upipe->u.intr.qhs[i]);
2814: splx(s);
2815:
2816: DPRINTFN(5, ("uhci_device_setintr: returns %p\n", upipe));
2817: return (USBD_NORMAL_COMPLETION);
2818: }
2819:
2820: /* Open a new pipe. */
2821: usbd_status
2822: uhci_open(usbd_pipe_handle pipe)
2823: {
2824: uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
2825: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
2826: usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
2827: usbd_status err;
2828: int ival;
2829:
2830: DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
2831: pipe, pipe->device->address,
2832: ed->bEndpointAddress, sc->sc_addr));
2833:
2834: upipe->aborting = 0;
2835: upipe->nexttoggle = pipe->endpoint->savedtoggle;
2836:
2837: if (pipe->device->address == sc->sc_addr) {
2838: switch (ed->bEndpointAddress) {
2839: case USB_CONTROL_ENDPOINT:
2840: pipe->methods = &uhci_root_ctrl_methods;
2841: break;
2842: case UE_DIR_IN | UHCI_INTR_ENDPT:
2843: pipe->methods = &uhci_root_intr_methods;
2844: break;
2845: default:
2846: return (USBD_INVAL);
2847: }
2848: } else {
2849: switch (ed->bmAttributes & UE_XFERTYPE) {
2850: case UE_CONTROL:
2851: pipe->methods = &uhci_device_ctrl_methods;
2852: upipe->u.ctl.sqh = uhci_alloc_sqh(sc);
2853: if (upipe->u.ctl.sqh == NULL)
2854: goto bad;
2855: upipe->u.ctl.setup = uhci_alloc_std(sc);
2856: if (upipe->u.ctl.setup == NULL) {
2857: uhci_free_sqh(sc, upipe->u.ctl.sqh);
2858: goto bad;
2859: }
2860: upipe->u.ctl.stat = uhci_alloc_std(sc);
2861: if (upipe->u.ctl.stat == NULL) {
2862: uhci_free_sqh(sc, upipe->u.ctl.sqh);
2863: uhci_free_std(sc, upipe->u.ctl.setup);
2864: goto bad;
2865: }
2866: err = usb_allocmem(&sc->sc_bus,
2867: sizeof(usb_device_request_t),
2868: 0, &upipe->u.ctl.reqdma);
2869: if (err) {
2870: uhci_free_sqh(sc, upipe->u.ctl.sqh);
2871: uhci_free_std(sc, upipe->u.ctl.setup);
2872: uhci_free_std(sc, upipe->u.ctl.stat);
2873: goto bad;
2874: }
2875: break;
2876: case UE_INTERRUPT:
2877: pipe->methods = &uhci_device_intr_methods;
2878: ival = pipe->interval;
2879: if (ival == USBD_DEFAULT_INTERVAL)
2880: ival = ed->bInterval;
2881: return (uhci_device_setintr(sc, upipe, ival));
2882: case UE_ISOCHRONOUS:
2883: pipe->methods = &uhci_device_isoc_methods;
2884: return (uhci_setup_isoc(pipe));
2885: case UE_BULK:
2886: pipe->methods = &uhci_device_bulk_methods;
2887: upipe->u.bulk.sqh = uhci_alloc_sqh(sc);
2888: if (upipe->u.bulk.sqh == NULL)
2889: goto bad;
2890: break;
2891: }
2892: }
2893: return (USBD_NORMAL_COMPLETION);
2894:
2895: bad:
2896: return (USBD_NOMEM);
2897: }
2898:
2899: /*
2900: * Data structures and routines to emulate the root hub.
2901: */
2902: usb_device_descriptor_t uhci_devd = {
2903: USB_DEVICE_DESCRIPTOR_SIZE,
2904: UDESC_DEVICE, /* type */
2905: {0x00, 0x01}, /* USB version */
2906: UDCLASS_HUB, /* class */
2907: UDSUBCLASS_HUB, /* subclass */
2908: UDPROTO_FSHUB, /* protocol */
2909: 64, /* max packet */
2910: {0},{0},{0x00,0x01}, /* device id */
2911: 1,2,0, /* string indices */
2912: 1 /* # of configurations */
2913: };
2914:
2915: usb_config_descriptor_t uhci_confd = {
2916: USB_CONFIG_DESCRIPTOR_SIZE,
2917: UDESC_CONFIG,
2918: {USB_CONFIG_DESCRIPTOR_SIZE +
2919: USB_INTERFACE_DESCRIPTOR_SIZE +
2920: USB_ENDPOINT_DESCRIPTOR_SIZE},
2921: 1,
2922: 1,
2923: 0,
2924: UC_SELF_POWERED,
2925: 0 /* max power */
2926: };
2927:
2928: usb_interface_descriptor_t uhci_ifcd = {
2929: USB_INTERFACE_DESCRIPTOR_SIZE,
2930: UDESC_INTERFACE,
2931: 0,
2932: 0,
2933: 1,
2934: UICLASS_HUB,
2935: UISUBCLASS_HUB,
2936: UIPROTO_FSHUB,
2937: 0
2938: };
2939:
2940: usb_endpoint_descriptor_t uhci_endpd = {
2941: USB_ENDPOINT_DESCRIPTOR_SIZE,
2942: UDESC_ENDPOINT,
2943: UE_DIR_IN | UHCI_INTR_ENDPT,
2944: UE_INTERRUPT,
2945: {8},
2946: 255
2947: };
2948:
2949: usb_hub_descriptor_t uhci_hubd_piix = {
2950: USB_HUB_DESCRIPTOR_SIZE,
2951: UDESC_HUB,
2952: 2,
2953: { UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL, 0 },
2954: 50, /* power on to power good */
2955: 0,
2956: { 0x00 }, /* both ports are removable */
2957: };
2958:
2959: int
2960: uhci_str(usb_string_descriptor_t *p, int l, char *s)
2961: {
2962: int i;
2963:
2964: if (l == 0)
2965: return (0);
2966: p->bLength = 2 * strlen(s) + 2;
2967: if (l == 1)
2968: return (1);
2969: p->bDescriptorType = UDESC_STRING;
2970: l -= 2;
2971: for (i = 0; s[i] && l > 1; i++, l -= 2)
2972: USETW2(p->bString[i], 0, s[i]);
2973: return (2*i+2);
2974: }
2975:
2976: /*
2977: * The USB hub protocol requires that SET_FEATURE(PORT_RESET) also
2978: * enables the port, and also states that SET_FEATURE(PORT_ENABLE)
2979: * should not be used by the USB subsystem. As we cannot issue a
2980: * SET_FEATURE(PORT_ENABLE) externally, we must ensure that the port
2981: * will be enabled as part of the reset.
2982: *
2983: * On the VT83C572, the port cannot be successfully enabled until the
2984: * outstanding "port enable change" and "connection status change"
2985: * events have been reset.
2986: */
2987: usbd_status
2988: uhci_portreset(uhci_softc_t *sc, int index)
2989: {
2990: int lim, port, x;
2991:
2992: if (index == 1)
2993: port = UHCI_PORTSC1;
2994: else if (index == 2)
2995: port = UHCI_PORTSC2;
2996: else
2997: return (USBD_IOERROR);
2998:
2999: x = URWMASK(UREAD2(sc, port));
3000: UWRITE2(sc, port, x | UHCI_PORTSC_PR);
3001:
3002: usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
3003:
3004: DPRINTFN(3,("uhci port %d reset, status0 = 0x%04x\n",
3005: index, UREAD2(sc, port)));
3006:
3007: x = URWMASK(UREAD2(sc, port));
3008: UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
3009:
3010: delay(100);
3011:
3012: DPRINTFN(3,("uhci port %d reset, status1 = 0x%04x\n",
3013: index, UREAD2(sc, port)));
3014:
3015: x = URWMASK(UREAD2(sc, port));
3016: UWRITE2(sc, port, x | UHCI_PORTSC_PE);
3017:
3018: for (lim = 10; --lim > 0;) {
3019: usb_delay_ms(&sc->sc_bus, USB_PORT_RESET_DELAY);
3020:
3021: x = UREAD2(sc, port);
3022:
3023: DPRINTFN(3,("uhci port %d iteration %u, status = 0x%04x\n",
3024: index, lim, x));
3025:
3026: if (!(x & UHCI_PORTSC_CCS)) {
3027: /*
3028: * No device is connected (or was disconnected
3029: * during reset). Consider the port reset.
3030: * The delay must be long enough to ensure on
3031: * the initial iteration that the device
3032: * connection will have been registered. 50ms
3033: * appears to be sufficient, but 20ms is not.
3034: */
3035: DPRINTFN(3,("uhci port %d loop %u, device detached\n",
3036: index, lim));
3037: break;
3038: }
3039:
3040: if (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)) {
3041: /*
3042: * Port enabled changed and/or connection
3043: * status changed were set. Reset either or
3044: * both raised flags (by writing a 1 to that
3045: * bit), and wait again for state to settle.
3046: */
3047: UWRITE2(sc, port, URWMASK(x) |
3048: (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)));
3049: continue;
3050: }
3051:
3052: if (x & UHCI_PORTSC_PE)
3053: /* Port is enabled */
3054: break;
3055:
3056: UWRITE2(sc, port, URWMASK(x) | UHCI_PORTSC_PE);
3057: }
3058:
3059: DPRINTFN(3,("uhci port %d reset, status2 = 0x%04x\n",
3060: index, UREAD2(sc, port)));
3061:
3062: if (lim <= 0) {
3063: DPRINTFN(1,("uhci port %d reset timed out\n", index));
3064: return (USBD_TIMEOUT);
3065: }
3066:
3067: sc->sc_isreset = 1;
3068: return (USBD_NORMAL_COMPLETION);
3069: }
3070:
3071: /*
3072: * Simulate a hardware hub by handling all the necessary requests.
3073: */
3074: usbd_status
3075: uhci_root_ctrl_transfer(usbd_xfer_handle xfer)
3076: {
3077: usbd_status err;
3078:
3079: /* Insert last in queue. */
3080: err = usb_insert_transfer(xfer);
3081: if (err)
3082: return (err);
3083:
3084: /*
3085: * Pipe isn't running (otherwise err would be USBD_INPROG),
3086: * so start it first.
3087: */
3088: return (uhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
3089: }
3090:
3091: usbd_status
3092: uhci_root_ctrl_start(usbd_xfer_handle xfer)
3093: {
3094: uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;
3095: usb_device_request_t *req;
3096: void *buf = NULL;
3097: int port, x;
3098: int s, len, value, index, status, change, l, totlen = 0;
3099: usb_port_status_t ps;
3100: usbd_status err;
3101:
3102: if (sc->sc_dying)
3103: return (USBD_IOERROR);
3104:
3105: #ifdef DIAGNOSTIC
3106: if (!(xfer->rqflags & URQ_REQUEST))
3107: panic("uhci_root_ctrl_transfer: not a request");
3108: #endif
3109: req = &xfer->request;
3110:
3111: DPRINTFN(2,("uhci_root_ctrl_control type=0x%02x request=%02x\n",
3112: req->bmRequestType, req->bRequest));
3113:
3114: len = UGETW(req->wLength);
3115: value = UGETW(req->wValue);
3116: index = UGETW(req->wIndex);
3117:
3118: if (len != 0)
3119: buf = KERNADDR(&xfer->dmabuf, 0);
3120:
3121: #define C(x,y) ((x) | ((y) << 8))
3122: switch(C(req->bRequest, req->bmRequestType)) {
3123: case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
3124: case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
3125: case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
3126: /*
3127: * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
3128: * for the integrated root hub.
3129: */
3130: break;
3131: case C(UR_GET_CONFIG, UT_READ_DEVICE):
3132: if (len > 0) {
3133: *(u_int8_t *)buf = sc->sc_conf;
3134: totlen = 1;
3135: }
3136: break;
3137: case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
3138: DPRINTFN(2,("uhci_root_ctrl_control wValue=0x%04x\n", value));
3139: switch(value >> 8) {
3140: case UDESC_DEVICE:
3141: if ((value & 0xff) != 0) {
3142: err = USBD_IOERROR;
3143: goto ret;
3144: }
3145: totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
3146: USETW(uhci_devd.idVendor, sc->sc_id_vendor);
3147: memcpy(buf, &uhci_devd, l);
3148: break;
3149: case UDESC_CONFIG:
3150: if ((value & 0xff) != 0) {
3151: err = USBD_IOERROR;
3152: goto ret;
3153: }
3154: totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
3155: memcpy(buf, &uhci_confd, l);
3156: buf = (char *)buf + l;
3157: len -= l;
3158: l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
3159: totlen += l;
3160: memcpy(buf, &uhci_ifcd, l);
3161: buf = (char *)buf + l;
3162: len -= l;
3163: l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
3164: totlen += l;
3165: memcpy(buf, &uhci_endpd, l);
3166: break;
3167: case UDESC_STRING:
3168: if (len == 0)
3169: break;
3170: *(u_int8_t *)buf = 0;
3171: totlen = 1;
3172: switch (value & 0xff) {
3173: case 0: /* Language table */
3174: totlen = uhci_str(buf, len, "\001");
3175: break;
3176: case 1: /* Vendor */
3177: totlen = uhci_str(buf, len, sc->sc_vendor);
3178: break;
3179: case 2: /* Product */
3180: totlen = uhci_str(buf, len, "UHCI root hub");
3181: break;
3182: }
3183: break;
3184: default:
3185: err = USBD_IOERROR;
3186: goto ret;
3187: }
3188: break;
3189: case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
3190: if (len > 0) {
3191: *(u_int8_t *)buf = 0;
3192: totlen = 1;
3193: }
3194: break;
3195: case C(UR_GET_STATUS, UT_READ_DEVICE):
3196: if (len > 1) {
3197: USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
3198: totlen = 2;
3199: }
3200: break;
3201: case C(UR_GET_STATUS, UT_READ_INTERFACE):
3202: case C(UR_GET_STATUS, UT_READ_ENDPOINT):
3203: if (len > 1) {
3204: USETW(((usb_status_t *)buf)->wStatus, 0);
3205: totlen = 2;
3206: }
3207: break;
3208: case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
3209: if (value >= USB_MAX_DEVICES) {
3210: err = USBD_IOERROR;
3211: goto ret;
3212: }
3213: sc->sc_addr = value;
3214: break;
3215: case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
3216: if (value != 0 && value != 1) {
3217: err = USBD_IOERROR;
3218: goto ret;
3219: }
3220: sc->sc_conf = value;
3221: break;
3222: case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
3223: break;
3224: case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
3225: case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
3226: case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
3227: err = USBD_IOERROR;
3228: goto ret;
3229: case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
3230: break;
3231: case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
3232: break;
3233: /* Hub requests */
3234: case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
3235: break;
3236: case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
3237: DPRINTFN(3, ("uhci_root_ctrl_control: UR_CLEAR_PORT_FEATURE "
3238: "port=%d feature=%d\n",
3239: index, value));
3240: if (index == 1)
3241: port = UHCI_PORTSC1;
3242: else if (index == 2)
3243: port = UHCI_PORTSC2;
3244: else {
3245: err = USBD_IOERROR;
3246: goto ret;
3247: }
3248: switch(value) {
3249: case UHF_PORT_ENABLE:
3250: x = URWMASK(UREAD2(sc, port));
3251: UWRITE2(sc, port, x & ~UHCI_PORTSC_PE);
3252: break;
3253: case UHF_PORT_SUSPEND:
3254: x = URWMASK(UREAD2(sc, port));
3255: UWRITE2(sc, port, x & ~UHCI_PORTSC_SUSP);
3256: break;
3257: case UHF_PORT_RESET:
3258: x = URWMASK(UREAD2(sc, port));
3259: UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
3260: break;
3261: case UHF_C_PORT_CONNECTION:
3262: x = URWMASK(UREAD2(sc, port));
3263: UWRITE2(sc, port, x | UHCI_PORTSC_CSC);
3264: break;
3265: case UHF_C_PORT_ENABLE:
3266: x = URWMASK(UREAD2(sc, port));
3267: UWRITE2(sc, port, x | UHCI_PORTSC_POEDC);
3268: break;
3269: case UHF_C_PORT_OVER_CURRENT:
3270: x = URWMASK(UREAD2(sc, port));
3271: UWRITE2(sc, port, x | UHCI_PORTSC_OCIC);
3272: break;
3273: case UHF_C_PORT_RESET:
3274: sc->sc_isreset = 0;
3275: err = USBD_NORMAL_COMPLETION;
3276: goto ret;
3277: case UHF_PORT_CONNECTION:
3278: case UHF_PORT_OVER_CURRENT:
3279: case UHF_PORT_POWER:
3280: case UHF_PORT_LOW_SPEED:
3281: case UHF_C_PORT_SUSPEND:
3282: default:
3283: err = USBD_IOERROR;
3284: goto ret;
3285: }
3286: break;
3287: case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER):
3288: if (index == 1)
3289: port = UHCI_PORTSC1;
3290: else if (index == 2)
3291: port = UHCI_PORTSC2;
3292: else {
3293: err = USBD_IOERROR;
3294: goto ret;
3295: }
3296: if (len > 0) {
3297: *(u_int8_t *)buf =
3298: (UREAD2(sc, port) & UHCI_PORTSC_LS) >>
3299: UHCI_PORTSC_LS_SHIFT;
3300: totlen = 1;
3301: }
3302: break;
3303: case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
3304: if ((value & 0xff) != 0) {
3305: err = USBD_IOERROR;
3306: goto ret;
3307: }
3308: l = min(len, USB_HUB_DESCRIPTOR_SIZE);
3309: totlen = l;
3310: memcpy(buf, &uhci_hubd_piix, l);
3311: break;
3312: case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
3313: if (len != 4) {
3314: err = USBD_IOERROR;
3315: goto ret;
3316: }
3317: memset(buf, 0, len);
3318: totlen = len;
3319: break;
3320: case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
3321: if (index == 1)
3322: port = UHCI_PORTSC1;
3323: else if (index == 2)
3324: port = UHCI_PORTSC2;
3325: else {
3326: err = USBD_IOERROR;
3327: goto ret;
3328: }
3329: if (len != 4) {
3330: err = USBD_IOERROR;
3331: goto ret;
3332: }
3333: x = UREAD2(sc, port);
3334: status = change = 0;
3335: if (x & UHCI_PORTSC_CCS)
3336: status |= UPS_CURRENT_CONNECT_STATUS;
3337: if (x & UHCI_PORTSC_CSC)
3338: change |= UPS_C_CONNECT_STATUS;
3339: if (x & UHCI_PORTSC_PE)
3340: status |= UPS_PORT_ENABLED;
3341: if (x & UHCI_PORTSC_POEDC)
3342: change |= UPS_C_PORT_ENABLED;
3343: if (x & UHCI_PORTSC_OCI)
3344: status |= UPS_OVERCURRENT_INDICATOR;
3345: if (x & UHCI_PORTSC_OCIC)
3346: change |= UPS_C_OVERCURRENT_INDICATOR;
3347: if (x & UHCI_PORTSC_SUSP)
3348: status |= UPS_SUSPEND;
3349: if (x & UHCI_PORTSC_LSDA)
3350: status |= UPS_LOW_SPEED;
3351: status |= UPS_PORT_POWER;
3352: if (sc->sc_isreset)
3353: change |= UPS_C_PORT_RESET;
3354: USETW(ps.wPortStatus, status);
3355: USETW(ps.wPortChange, change);
3356: l = min(len, sizeof ps);
3357: memcpy(buf, &ps, l);
3358: totlen = l;
3359: break;
3360: case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
3361: err = USBD_IOERROR;
3362: goto ret;
3363: case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
3364: break;
3365: case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
3366: if (index == 1)
3367: port = UHCI_PORTSC1;
3368: else if (index == 2)
3369: port = UHCI_PORTSC2;
3370: else {
3371: err = USBD_IOERROR;
3372: goto ret;
3373: }
3374: switch(value) {
3375: case UHF_PORT_ENABLE:
3376: x = URWMASK(UREAD2(sc, port));
3377: UWRITE2(sc, port, x | UHCI_PORTSC_PE);
3378: break;
3379: case UHF_PORT_SUSPEND:
3380: x = URWMASK(UREAD2(sc, port));
3381: UWRITE2(sc, port, x | UHCI_PORTSC_SUSP);
3382: break;
3383: case UHF_PORT_RESET:
3384: err = uhci_portreset(sc, index);
3385: goto ret;
3386: case UHF_PORT_POWER:
3387: /* Pretend we turned on power */
3388: err = USBD_NORMAL_COMPLETION;
3389: goto ret;
3390: case UHF_C_PORT_CONNECTION:
3391: case UHF_C_PORT_ENABLE:
3392: case UHF_C_PORT_OVER_CURRENT:
3393: case UHF_PORT_CONNECTION:
3394: case UHF_PORT_OVER_CURRENT:
3395: case UHF_PORT_LOW_SPEED:
3396: case UHF_C_PORT_SUSPEND:
3397: case UHF_C_PORT_RESET:
3398: default:
3399: err = USBD_IOERROR;
3400: goto ret;
3401: }
3402: break;
3403: default:
3404: err = USBD_IOERROR;
3405: goto ret;
3406: }
3407: xfer->actlen = totlen;
3408: err = USBD_NORMAL_COMPLETION;
3409: ret:
3410: xfer->status = err;
3411: s = splusb();
3412: usb_transfer_complete(xfer);
3413: splx(s);
3414: return (USBD_IN_PROGRESS);
3415: }
3416:
3417: /* Abort a root control request. */
3418: void
3419: uhci_root_ctrl_abort(usbd_xfer_handle xfer)
3420: {
3421: /* Nothing to do, all transfers are synchronous. */
3422: }
3423:
3424: /* Close the root pipe. */
3425: void
3426: uhci_root_ctrl_close(usbd_pipe_handle pipe)
3427: {
3428: DPRINTF(("uhci_root_ctrl_close\n"));
3429: }
3430:
3431: /* Abort a root interrupt request. */
3432: void
3433: uhci_root_intr_abort(usbd_xfer_handle xfer)
3434: {
3435: uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;
3436:
3437: timeout_del(&sc->sc_poll_handle);
3438: sc->sc_intr_xfer = NULL;
3439:
3440: if (xfer->pipe->intrxfer == xfer) {
3441: DPRINTF(("uhci_root_intr_abort: remove\n"));
3442: xfer->pipe->intrxfer = 0;
3443: }
3444: xfer->status = USBD_CANCELLED;
3445: #ifdef DIAGNOSTIC
3446: UXFER(xfer)->iinfo.isdone = 1;
3447: #endif
3448: usb_transfer_complete(xfer);
3449: }
3450:
3451: usbd_status
3452: uhci_root_intr_transfer(usbd_xfer_handle xfer)
3453: {
3454: usbd_status err;
3455:
3456: /* Insert last in queue. */
3457: err = usb_insert_transfer(xfer);
3458: if (err)
3459: return (err);
3460:
3461: /* Pipe isn't running (otherwise err would be USBD_INPROG),
3462: * start first
3463: */
3464: return (uhci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
3465: }
3466:
3467: /* Start a transfer on the root interrupt pipe */
3468: usbd_status
3469: uhci_root_intr_start(usbd_xfer_handle xfer)
3470: {
3471: usbd_pipe_handle pipe = xfer->pipe;
3472: uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
3473:
3474: DPRINTFN(3, ("uhci_root_intr_start: xfer=%p len=%d flags=%d\n",
3475: xfer, xfer->length, xfer->flags));
3476:
3477: if (sc->sc_dying)
3478: return (USBD_IOERROR);
3479:
3480: sc->sc_ival = mstohz(xfer->pipe->endpoint->edesc->bInterval);
3481: timeout_del(&sc->sc_poll_handle);
3482: timeout_set(&sc->sc_poll_handle, uhci_poll_hub, xfer);
3483: timeout_add(&sc->sc_poll_handle, sc->sc_ival);
3484: sc->sc_intr_xfer = xfer;
3485: return (USBD_IN_PROGRESS);
3486: }
3487:
3488: /* Close the root interrupt pipe. */
3489: void
3490: uhci_root_intr_close(usbd_pipe_handle pipe)
3491: {
3492: uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
3493:
3494: timeout_del(&sc->sc_poll_handle);
3495: sc->sc_intr_xfer = NULL;
3496: DPRINTF(("uhci_root_intr_close\n"));
3497: }
CVSweb