1 /*        $NetBSD: ohci_cardbus.c,v 1.47 2025/03/31 14:46:42 riastradh Exp $    */
2 
3 /*
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Lennart Augustsson (lennart@augustsson.net) at
9  * Carlstedt Research & Technology.
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  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * USB Open Host Controller driver.
35  *
36  * OHCI spec: http://www.intel.com/design/usb/ohci11d.pdf
37  * USB spec: http://www.teleport.com/cgi-bin/mailmerge.cgi/~usb/cgiform.tpl
38  */
39 
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: ohci_cardbus.c,v 1.47 2025/03/31 14:46:42 riastradh Exp $");
42 
43 #include "ehci_cardbus.h"
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/device.h>
49 #include <sys/proc.h>
50 
51 #include <sys/bus.h>
52 
53 #if defined pciinc
54 #include <dev/pci/pcidevs.h>
55 #endif
56 
57 #include <dev/cardbus/cardbusvar.h>
58 #include <dev/pci/pcidevs.h>
59 
60 #include <dev/cardbus/usb_cardbus.h>
61 
62 #include <dev/usb/usb.h>
63 #include <dev/usb/usbdi.h>
64 #include <dev/usb/usbdivar.h>
65 #include <dev/usb/usb_mem.h>
66 
67 #include <dev/usb/ohcireg.h>
68 #include <dev/usb/ohcivar.h>
69 
70 int       ohci_cardbus_match(device_t, cfdata_t, void *);
71 void      ohci_cardbus_attach(device_t, device_t, void *);
72 int       ohci_cardbus_detach(device_t, int);
73 
74 struct ohci_cardbus_softc {
75           ohci_softc_t                  sc;
76 #if NEHCI_CARDBUS > 0
77           struct usb_cardbus  sc_cardbus;
78 #endif
79           cardbus_chipset_tag_t         sc_cc;
80           cardbus_function_tag_t        sc_cf;
81           cardbus_devfunc_t   sc_ct;
82           void                          *sc_ih;             /* interrupt vectoring */
83 };
84 
85 CFATTACH_DECL_NEW(ohci_cardbus, sizeof(struct ohci_cardbus_softc),
86     ohci_cardbus_match, ohci_cardbus_attach, ohci_cardbus_detach,
87     ohci_activate);
88 
89 int
ohci_cardbus_match(device_t parent,cfdata_t match,void * aux)90 ohci_cardbus_match(device_t parent, cfdata_t match, void *aux)
91 {
92           struct cardbus_attach_args *ca = (struct cardbus_attach_args *)aux;
93 
94           if (PCI_CLASS(ca->ca_class) == PCI_CLASS_SERIALBUS &&
95               PCI_SUBCLASS(ca->ca_class) == PCI_SUBCLASS_SERIALBUS_USB &&
96               PCI_INTERFACE(ca->ca_class) == PCI_INTERFACE_OHCI)
97                     return 1;
98 
99           return 0;
100 }
101 
102 void
ohci_cardbus_attach(device_t parent,device_t self,void * aux)103 ohci_cardbus_attach(device_t parent, device_t self, void *aux)
104 {
105           struct ohci_cardbus_softc *sc = device_private(self);
106           struct cardbus_attach_args *ca = aux;
107           cardbus_devfunc_t ct = ca->ca_ct;
108           cardbus_chipset_tag_t cc = ct->ct_cc;
109           cardbus_function_tag_t cf = ct->ct_cf;
110           pcireg_t csr;
111           char devinfo[256];
112           const char *devname = device_xname(self);
113 
114           sc->sc.sc_dev = self;
115           sc->sc.sc_bus.ub_hcpriv = sc;
116 
117           pci_devinfo(ca->ca_id, ca->ca_class, 0, devinfo, sizeof(devinfo));
118           printf(": %s (rev. 0x%02x)\n", devinfo,
119                  PCI_REVISION(ca->ca_class));
120 
121           /* Map I/O registers */
122           if (Cardbus_mapreg_map(ct, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
123                                  &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) {
124                     aprint_error("%s: can't map mem space\n", devname);
125                     return;
126           }
127 
128           sc->sc_cc = cc;
129           sc->sc_cf = cf;
130           sc->sc_ct = ct;
131           sc->sc.sc_bus.ub_dmatag = ca->ca_dmat;
132 
133           /* Enable the device. */
134           csr = Cardbus_conf_read(ct, ca->ca_tag, PCI_COMMAND_STATUS_REG);
135           Cardbus_conf_write(ct, ca->ca_tag, PCI_COMMAND_STATUS_REG,
136                            csr | PCI_COMMAND_MASTER_ENABLE
137                                  | PCI_COMMAND_MEM_ENABLE);
138 
139           /* Disable interrupts, so we don't can any spurious ones. */
140           bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE,
141                                 OHCI_ALL_INTRS);
142 
143           sc->sc_ih = Cardbus_intr_establish(ct, IPL_USB, ohci_intr, sc);
144           if (sc->sc_ih == NULL) {
145                     aprint_error("%s: couldn't establish interrupt\n", devname);
146                     return;
147           }
148 
149           int err = ohci_init(&sc->sc);
150           if (err) {
151                     aprint_error("%s: init failed, error=%d\n", devname, err);
152 
153                     /* Avoid spurious interrupts. */
154                     Cardbus_intr_disestablish(ct, sc->sc_ih);
155                     sc->sc_ih = 0;
156 
157                     return;
158           }
159 
160 #if NEHCI_CARDBUS > 0
161           usb_cardbus_add(&sc->sc_cardbus, ca, self);
162 #endif
163 
164           if (!pmf_device_register1(self, ohci_suspend, ohci_resume,
165                                     ohci_shutdown))
166                     aprint_error_dev(self, "couldn't establish power handler\n");
167 
168           /* Attach usb device. */
169           sc->sc.sc_child = config_found(self, &sc->sc.sc_bus, usbctlprint,
170               CFARGS_NONE);
171 }
172 
173 int
ohci_cardbus_detach(device_t self,int flags)174 ohci_cardbus_detach(device_t self, int flags)
175 {
176           struct ohci_cardbus_softc *sc = device_private(self);
177           struct cardbus_devfunc *ct = sc->sc_ct;
178           int error;
179 
180           /*
181            * Detach the USB child first.  Disconnects all USB devices and
182            * prevents connecting new ones.
183            */
184           error = config_detach_children(self, flags);
185           if (error)
186                     return error;
187 
188           /*
189            * Stop listing this as a possible companion controller for
190            * ehci(4).
191            */
192 #if NEHCI_CARDBUS > 0
193           usb_cardbus_rem(&sc->sc_cardbus);
194 #endif
195 
196           /*
197            * Shut down the controller and block interrupts at the device
198            * level.  Once we have shut down the controller, the shutdown
199            * handler no longer needed -- deregister it from PMF.
200            * (Harmless to call ohci_shutdown more than once, so no
201            * synchronization needed.)
202            */
203           ohci_shutdown(self, 0);
204           pmf_device_deregister(self);
205 
206           /*
207            * Interrupts are blocked at the device level by ohci_shutdown.
208            * Disestablish the interrupt handler.  This waits for it to
209            * complete on all CPUs.
210            */
211           if (sc->sc_ih != NULL) {
212                     Cardbus_intr_disestablish(ct, sc->sc_ih);
213                     sc->sc_ih = NULL;
214           }
215 
216           /*
217            * Free the bus-independent ohci(4) state now that the
218            * interrupt handler has ceased to run on all CPUs.
219            */
220           ohci_detach(&sc->sc);
221 
222           /*
223            * Unmap the registers now that we're all done with them.
224            */
225           if (sc->sc.sc_size) {
226                     Cardbus_mapreg_unmap(ct, PCI_CBMEM, sc->sc.iot,
227                         sc->sc.ioh, sc->sc.sc_size);
228                     sc->sc.sc_size = 0;
229           }
230 
231           return 0;
232 }
233