Annotation of sys/dev/pci/ehci_pci.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ehci_pci.c,v 1.12 2007/06/10 14:49:01 mbalmer Exp $ */
2: /* $NetBSD: ehci_pci.c,v 1.15 2004/04/23 21:13:06 itojun Exp $ */
3:
4: /*
5: * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Lennart Augustsson (lennart@augustsson.net).
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/kernel.h>
43: #include <sys/rwlock.h>
44: #include <sys/device.h>
45: #include <sys/proc.h>
46: #include <sys/queue.h>
47:
48: #include <machine/bus.h>
49:
50: #include <dev/pci/pcidevs.h>
51: #include <dev/pci/pcivar.h>
52:
53: #include <dev/usb/usb.h>
54: #include <dev/usb/usbdi.h>
55: #include <dev/usb/usbdivar.h>
56: #include <dev/usb/usb_mem.h>
57:
58: #include <dev/usb/ehcireg.h>
59: #include <dev/usb/ehcivar.h>
60:
61: #ifdef EHCI_DEBUG
62: #define DPRINTF(x) if (ehcidebug) printf x
63: extern int ehcidebug;
64: #else
65: #define DPRINTF(x)
66: #endif
67:
68: struct ehci_pci_softc {
69: ehci_softc_t sc;
70: pci_chipset_tag_t sc_pc;
71: pcitag_t sc_tag;
72: void *sc_ih; /* interrupt vectoring */
73: };
74:
75: int ehci_pci_match(struct device *, void *, void *);
76: void ehci_pci_attach(struct device *, struct device *, void *);
77: int ehci_pci_detach(struct device *, int);
78: void ehci_pci_givecontroller(struct ehci_pci_softc *);
79: void ehci_pci_takecontroller(struct ehci_pci_softc *);
80: void ehci_pci_shutdown(void *);
81:
82: struct cfattach ehci_pci_ca = {
83: sizeof(struct ehci_pci_softc), ehci_pci_match, ehci_pci_attach,
84: ehci_pci_detach, ehci_activate
85: };
86:
87:
88: int
89: ehci_pci_match(struct device *parent, void *match, void *aux)
90: {
91: struct pci_attach_args *pa = (struct pci_attach_args *) aux;
92:
93: if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS &&
94: PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB &&
95: PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI)
96: return (1);
97:
98: return (0);
99: }
100:
101: void
102: ehci_pci_attach(struct device *parent, struct device *self, void *aux)
103: {
104: struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self;
105: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
106: pci_chipset_tag_t pc = pa->pa_pc;
107: pcitag_t tag = pa->pa_tag;
108: char const *intrstr;
109: pci_intr_handle_t ih;
110: const char *vendor;
111: char *devname = sc->sc.sc_bus.bdev.dv_xname;
112: usbd_status r;
113: int s;
114:
115: /* Map I/O registers */
116: if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
117: &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size, 0)) {
118: printf(": can't map memory space\n");
119: return;
120: }
121:
122: sc->sc_pc = pc;
123: sc->sc_tag = tag;
124: sc->sc.sc_bus.dmatag = pa->pa_dmat;
125:
126: /* Disable interrupts, so we don't get any spurious ones. */
127: s = splhardusb();
128: sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
129: DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs));
130: EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
131:
132: /* Map and establish the interrupt. */
133: if (pci_intr_map(pa, &ih)) {
134: printf(": couldn't map interrupt\n");
135: goto unmap_ret;
136: }
137: intrstr = pci_intr_string(pc, ih);
138: sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB, ehci_intr, sc, devname);
139: if (sc->sc_ih == NULL) {
140: printf(": couldn't establish interrupt");
141: if (intrstr != NULL)
142: printf(" at %s", intrstr);
143: printf("\n");
144: goto unmap_ret;
145: }
146: printf(": %s\n", intrstr);
147:
148: switch(pci_conf_read(pc, tag, PCI_USBREV) & PCI_USBREV_MASK) {
149: case PCI_USBREV_PRE_1_0:
150: case PCI_USBREV_1_0:
151: case PCI_USBREV_1_1:
152: sc->sc.sc_bus.usbrev = USBREV_UNKNOWN;
153: printf("%s: pre-2.0 USB rev\n", devname);
154: goto unmap_ret;
155: case PCI_USBREV_2_0:
156: sc->sc.sc_bus.usbrev = USBREV_2_0;
157: break;
158: default:
159: sc->sc.sc_bus.usbrev = USBREV_UNKNOWN;
160: break;
161: }
162:
163: /* Figure out vendor for root hub descriptor. */
164: vendor = pci_findvendor(pa->pa_id);
165: sc->sc.sc_id_vendor = PCI_VENDOR(pa->pa_id);
166: if (vendor)
167: strlcpy(sc->sc.sc_vendor, vendor, sizeof(sc->sc.sc_vendor));
168: else
169: snprintf(sc->sc.sc_vendor, sizeof(sc->sc.sc_vendor),
170: "vendor 0x%04x", PCI_VENDOR(pa->pa_id));
171:
172: /* Enable workaround for dropped interrupts as required */
173: if (sc->sc.sc_id_vendor == PCI_VENDOR_VIATECH)
174: sc->sc.sc_flags |= EHCIF_DROPPED_INTR_WORKAROUND;
175:
176: ehci_pci_takecontroller(sc);
177: r = ehci_init(&sc->sc);
178: if (r != USBD_NORMAL_COMPLETION) {
179: printf("%s: init failed, error=%d\n", devname, r);
180: goto unmap_ret;
181: }
182:
183: sc->sc.sc_shutdownhook = shutdownhook_establish(ehci_pci_shutdown, sc);
184: splx(s);
185:
186: /* Attach usb device. */
187: sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus,
188: usbctlprint);
189:
190: return;
191:
192: unmap_ret:
193: bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
194: splx(s);
195: }
196:
197: int
198: ehci_pci_detach(struct device *self, int flags)
199: {
200: struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self;
201: int rv;
202:
203: rv = ehci_detach(&sc->sc, flags);
204: if (rv)
205: return (rv);
206: if (sc->sc_ih != NULL) {
207: pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
208: sc->sc_ih = NULL;
209: }
210: if (sc->sc.sc_size) {
211: bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
212: sc->sc.sc_size = 0;
213: }
214: return (0);
215: }
216:
217: void
218: ehci_pci_givecontroller(struct ehci_pci_softc *sc)
219: {
220: u_int32_t cparams, eec, legsup;
221: int eecp;
222:
223: cparams = EREAD4(&sc->sc, EHCI_HCCPARAMS);
224: for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
225: eecp = EHCI_EECP_NEXT(eec)) {
226: eec = pci_conf_read(sc->sc_pc, sc->sc_tag, eecp);
227: if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
228: continue;
229: legsup = eec;
230: pci_conf_write(sc->sc_pc, sc->sc_tag, eecp,
231: legsup & ~EHCI_LEGSUP_OSOWNED);
232: }
233: }
234:
235: void
236: ehci_pci_takecontroller(struct ehci_pci_softc *sc)
237: {
238: u_int32_t cparams, eec, legsup;
239: int eecp, i;
240:
241: cparams = EREAD4(&sc->sc, EHCI_HCCPARAMS);
242: /* Synchronise with the BIOS if it owns the controller. */
243: for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
244: eecp = EHCI_EECP_NEXT(eec)) {
245: eec = pci_conf_read(sc->sc_pc, sc->sc_tag, eecp);
246: if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
247: continue;
248: legsup = eec;
249: pci_conf_write(sc->sc_pc, sc->sc_tag, eecp,
250: legsup | EHCI_LEGSUP_OSOWNED);
251: if (legsup & EHCI_LEGSUP_BIOSOWNED) {
252: DPRINTF(("%s: waiting for BIOS to give up control\n",
253: sc->sc.sc_bus.bdev.dv_xname));
254: for (i = 0; i < 5000; i++) {
255: legsup = pci_conf_read(sc->sc_pc, sc->sc_tag,
256: eecp);
257: if ((legsup & EHCI_LEGSUP_BIOSOWNED) == 0)
258: break;
259: DELAY(1000);
260: }
261: if (legsup & EHCI_LEGSUP_BIOSOWNED)
262: printf("%s: timed out waiting for BIOS\n",
263: sc->sc.sc_bus.bdev.dv_xname);
264: }
265: }
266: }
267:
268: void
269: ehci_pci_shutdown(void *v)
270: {
271: struct ehci_pci_softc *sc = (struct ehci_pci_softc *)v;
272:
273: ehci_shutdown(&sc->sc);
274: ehci_pci_givecontroller(sc);
275: }
CVSweb