FreeBSD kernel usb device Code
generic_ohci.c
Go to the documentation of this file.
1/*-
2 * Copyright (c) 2016 Emmanuel Vadot <manu@freebsd.org> All rights reserved.
3 * Copyright (c) 2006 M. Warner Losh <imp@FreeBSD.org>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * Generic OHCI driver based on AT91 OHCI
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/bus.h>
37#include <sys/rman.h>
38#include <sys/condvar.h>
39#include <sys/kernel.h>
40#include <sys/module.h>
41
42#include <machine/bus.h>
43#include <dev/ofw/ofw_bus.h>
44#include <dev/ofw/ofw_bus_subr.h>
45
46#include <dev/usb/usb.h>
47#include <dev/usb/usbdi.h>
48
49#include <dev/usb/usb_core.h>
50#include <dev/usb/usb_busdma.h>
51#include <dev/usb/usb_process.h>
52#include <dev/usb/usb_util.h>
53
55#include <dev/usb/usb_bus.h>
58
59#include <dev/extres/clk/clk.h>
60#include <dev/extres/hwreset/hwreset.h>
61#include <dev/extres/phy/phy.h>
62#include <dev/extres/phy/phy_usb.h>
63
64#include "generic_usb_if.h"
65
66struct clk_list {
67 TAILQ_ENTRY(clk_list) next;
68 clk_t clk;
69};
70struct phy_list {
71 TAILQ_ENTRY(phy_list) next;
72 phy_t phy;
73};
74struct hwrst_list {
75 TAILQ_ENTRY(hwrst_list) next;
76 hwreset_t rst;
77};
78
81
84 TAILQ_HEAD(, hwrst_list) rst_list;
85};
86
87static int generic_ohci_detach(device_t);
88
89static int
90generic_ohci_probe(device_t dev)
91{
92
93 if (!ofw_bus_status_okay(dev))
94 return (ENXIO);
95
96 if (!ofw_bus_is_compatible(dev, "generic-ohci"))
97 return (ENXIO);
98
99 device_set_desc(dev, "Generic OHCI Controller");
100
101 return (BUS_PROBE_DEFAULT);
102}
103
104static int
106{
107 struct generic_ohci_softc *sc = device_get_softc(dev);
108 int err, rid;
109 int off;
110 struct clk_list *clkp;
111 struct phy_list *phyp;
112 struct hwrst_list *rstp;
113 clk_t clk;
114 phy_t phy;
115 hwreset_t rst;
116
117 sc->ohci_sc.sc_bus.parent = dev;
120 sc->ohci_sc.sc_bus.dma_bits = 32;
121
122 /* get all DMA memory */
125 return (ENOMEM);
126 }
127
128 rid = 0;
129 sc->ohci_sc.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
130 &rid, RF_ACTIVE);
131 if (sc->ohci_sc.sc_io_res == 0) {
132 err = ENOMEM;
133 goto error;
134 }
135
136 sc->ohci_sc.sc_io_tag = rman_get_bustag(sc->ohci_sc.sc_io_res);
137 sc->ohci_sc.sc_io_hdl = rman_get_bushandle(sc->ohci_sc.sc_io_res);
138 sc->ohci_sc.sc_io_size = rman_get_size(sc->ohci_sc.sc_io_res);
139
140 rid = 0;
141 sc->ohci_sc.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
142 RF_ACTIVE);
143 if (sc->ohci_sc.sc_irq_res == 0) {
144 err = ENXIO;
145 goto error;
146 }
147 sc->ohci_sc.sc_bus.bdev = device_add_child(dev, "usbus", -1);
148 if (sc->ohci_sc.sc_bus.bdev == 0) {
149 err = ENXIO;
150 goto error;
151 }
152 device_set_ivars(sc->ohci_sc.sc_bus.bdev, &sc->ohci_sc.sc_bus);
153
154 strlcpy(sc->ohci_sc.sc_vendor, "Generic",
155 sizeof(sc->ohci_sc.sc_vendor));
156
157 err = bus_setup_intr(dev, sc->ohci_sc.sc_irq_res,
158 INTR_TYPE_BIO | INTR_MPSAFE, NULL,
159 (driver_intr_t *)ohci_interrupt, sc, &sc->ohci_sc.sc_intr_hdl);
160 if (err) {
161 sc->ohci_sc.sc_intr_hdl = NULL;
162 goto error;
163 }
164
165 TAILQ_INIT(&sc->clk_list);
166 /* Enable clock */
167 for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) {
168 err = clk_enable(clk);
169 if (err != 0) {
170 device_printf(dev, "Could not enable clock %s\n",
171 clk_get_name(clk));
172 goto error;
173 }
174 clkp = malloc(sizeof(*clkp), M_DEVBUF, M_WAITOK | M_ZERO);
175 clkp->clk = clk;
176 TAILQ_INSERT_TAIL(&sc->clk_list, clkp, next);
177 }
178
179 /* De-assert reset */
180 TAILQ_INIT(&sc->rst_list);
181 for (off = 0; hwreset_get_by_ofw_idx(dev, 0, off, &rst) == 0; off++) {
182 err = hwreset_deassert(rst);
183 if (err != 0) {
184 device_printf(dev, "Could not de-assert reset\n");
185 goto error;
186 }
187 rstp = malloc(sizeof(*rstp), M_DEVBUF, M_WAITOK | M_ZERO);
188 rstp->rst = rst;
189 TAILQ_INSERT_TAIL(&sc->rst_list, rstp, next);
190 }
191
192 /* Enable phy */
193 TAILQ_INIT(&sc->phy_list);
194 for (off = 0; phy_get_by_ofw_idx(dev, 0, off, &phy) == 0; off++) {
195 err = phy_usb_set_mode(phy, PHY_USB_MODE_HOST);
196 if (err != 0) {
197 device_printf(dev, "Could not set phy to host mode\n");
198 goto error;
199 }
200 err = phy_enable(phy);
201 if (err != 0) {
202 device_printf(dev, "Could not enable phy\n");
203 goto error;
204 }
205 phyp = malloc(sizeof(*phyp), M_DEVBUF, M_WAITOK | M_ZERO);
206 phyp->phy = phy;
207 TAILQ_INSERT_TAIL(&sc->phy_list, phyp, next);
208 }
209
210 if (GENERIC_USB_INIT(dev) != 0) {
211 err = ENXIO;
212 goto error;
213 }
214
215 err = ohci_init(&sc->ohci_sc);
216 if (err == 0)
217 err = device_probe_and_attach(sc->ohci_sc.sc_bus.bdev);
218 if (err)
219 goto error;
220
221 return (0);
222error:
224 return (err);
225}
226
227static int
229{
230 struct generic_ohci_softc *sc = device_get_softc(dev);
231 int err;
232 struct clk_list *clk, *clk_tmp;
233 struct phy_list *phy, *phy_tmp;
234 struct hwrst_list *rst, *rst_tmp;
235
236 /* during module unload there are lots of children leftover */
237 device_delete_children(dev);
238
239 /*
240 * Put the controller into reset, then disable clocks and do
241 * the MI tear down. We have to disable the clocks/hardware
242 * after we do the rest of the teardown. We also disable the
243 * clocks in the opposite order we acquire them, but that
244 * doesn't seem to be absolutely necessary. We free up the
245 * clocks after we disable them, so the system could, in
246 * theory, reuse them.
247 */
248 bus_space_write_4(sc->ohci_sc.sc_io_tag, sc->ohci_sc.sc_io_hdl,
249 OHCI_CONTROL, 0);
250
251 if (sc->ohci_sc.sc_irq_res && sc->ohci_sc.sc_intr_hdl) {
252 /*
253 * only call ohci_detach() after ohci_init()
254 */
255 ohci_detach(&sc->ohci_sc);
256
257 err = bus_teardown_intr(dev, sc->ohci_sc.sc_irq_res,
258 sc->ohci_sc.sc_intr_hdl);
259 sc->ohci_sc.sc_intr_hdl = NULL;
260 }
261 if (sc->ohci_sc.sc_irq_res) {
262 bus_release_resource(dev, SYS_RES_IRQ, 0,
263 sc->ohci_sc.sc_irq_res);
264 sc->ohci_sc.sc_irq_res = NULL;
265 }
266 if (sc->ohci_sc.sc_io_res) {
267 bus_release_resource(dev, SYS_RES_MEMORY, 0,
268 sc->ohci_sc.sc_io_res);
269 sc->ohci_sc.sc_io_res = NULL;
270 }
272
273 /* Disable phy */
274 TAILQ_FOREACH_SAFE(phy, &sc->phy_list, next, phy_tmp) {
275 err = phy_disable(phy->phy);
276 if (err != 0)
277 device_printf(dev, "Could not disable phy\n");
278 phy_release(phy->phy);
279 TAILQ_REMOVE(&sc->phy_list, phy, next);
280 free(phy, M_DEVBUF);
281 }
282
283 /* Assert reset */
284 TAILQ_FOREACH_SAFE(rst, &sc->rst_list, next, rst_tmp) {
285 hwreset_assert(rst->rst);
286 hwreset_release(rst->rst);
287 TAILQ_REMOVE(&sc->rst_list, rst, next);
288 free(rst, M_DEVBUF);
289 }
290
291 /* Disable clock */
292 TAILQ_FOREACH_SAFE(clk, &sc->clk_list, next, clk_tmp) {
293 err = clk_disable(clk->clk);
294 if (err != 0)
295 device_printf(dev, "Could not disable clock %s\n",
296 clk_get_name(clk->clk));
297 err = clk_release(clk->clk);
298 if (err != 0)
299 device_printf(dev, "Could not release clock %s\n",
300 clk_get_name(clk->clk));
301 TAILQ_REMOVE(&sc->clk_list, clk, next);
302 free(clk, M_DEVBUF);
303 }
304
305 if (GENERIC_USB_DEINIT(dev) != 0)
306 return (ENXIO);
307
308 return (0);
309}
310
311static device_method_t generic_ohci_methods[] = {
312 /* Device interface */
313 DEVMETHOD(device_probe, generic_ohci_probe),
314 DEVMETHOD(device_attach, generic_ohci_attach),
315 DEVMETHOD(device_detach, generic_ohci_detach),
316
317 DEVMETHOD(device_suspend, bus_generic_suspend),
318 DEVMETHOD(device_resume, bus_generic_resume),
319 DEVMETHOD(device_shutdown, bus_generic_shutdown),
320
321 DEVMETHOD_END
322};
323
325 .name = "ohci",
326 .methods = generic_ohci_methods,
327 .size = sizeof(struct generic_ohci_softc),
328};
329
330static devclass_t generic_ohci_devclass;
331
334MODULE_DEPEND(ohci, usb, 1, 1, 1);
struct ehci_itd * next
Definition: ehci.h:29
static device_method_t generic_ohci_methods[]
Definition: generic_ohci.c:311
MODULE_DEPEND(ohci, usb, 1, 1, 1)
static devclass_t generic_ohci_devclass
Definition: generic_ohci.c:330
driver_t generic_ohci_driver
Definition: generic_ohci.c:324
static int generic_ohci_detach(device_t)
Definition: generic_ohci.c:228
__FBSDID("$FreeBSD$")
DRIVER_MODULE(ohci, simplebus, generic_ohci_driver, generic_ohci_devclass, 0, 0)
static int generic_ohci_probe(device_t dev)
Definition: generic_ohci.c:90
static int generic_ohci_attach(device_t dev)
Definition: generic_ohci.c:105
struct @109 error
void ohci_interrupt(ohci_softc_t *sc)
Definition: ohci.c:1106
void ohci_detach(struct ohci_softc *sc)
Definition: ohci.c:437
usb_error_t ohci_init(ohci_softc_t *sc)
Definition: ohci.c:323
#define OHCI_MAX_DEVICES
Definition: ohci.h:37
usb_bus_mem_cb_t ohci_iterate_hw_softc
Definition: ohci.h:259
#define OHCI_CONTROL
Definition: ohcireg.h:46
uint16_t rid
device_t dev
ohci_softc_t ohci_sc
Definition: generic_ohci.c:80
bus_space_tag_t sc_io_tag
Definition: ohci.h:242
struct usb_bus sc_bus
Definition: ohci.h:227
struct usb_device * sc_devices[OHCI_MAX_DEVICES]
Definition: ohci.h:231
struct resource * sc_irq_res
Definition: ohci.h:233
bus_size_t sc_io_size
Definition: ohci.h:241
struct resource * sc_io_res
Definition: ohci.h:232
char sc_vendor[16]
Definition: ohci.h:255
bus_space_handle_t sc_io_hdl
Definition: ohci.h:243
void * sc_intr_hdl
Definition: ohci.h:239
device_t bdev
Definition: usb_bus.h:101
device_t parent
Definition: usb_bus.h:100
struct usb_device ** devices
Definition: usb_bus.h:108
uint8_t devices_max
Definition: usb_bus.h:121
uint8_t dma_bits
Definition: usb_bus.h:124
#define USB_GET_DMA_TAG(dev)
Definition: usb_busdma.h:46
void usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb)
uint8_t usb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat, usb_bus_mem_cb_t *cb)
TAILQ_HEAD(, urb) bsd_urb_list
INTERFACE usb
Definition: usb_if.m:35