uss820dci_atmelarm.c revision 184824
1#include <sys/cdefs.h>
2__FBSDID("$FreeBSD: head/sys/dev/usb2/controller/uss820dci_atmelarm.c 184824 2008-11-10 20:54:31Z thompsa $");
3
4/*-
5 * Copyright (c) 2008 Hans Petter Selasky <hselasky@freebsd.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <dev/usb2/include/usb2_mfunc.h>
31#include <dev/usb2/include/usb2_defs.h>
32#include <dev/usb2/include/usb2_standard.h>
33
34#include <dev/usb2/core/usb2_core.h>
35#include <dev/usb2/core/usb2_busdma.h>
36#include <dev/usb2/core/usb2_process.h>
37#include <dev/usb2/core/usb2_config_td.h>
38#include <dev/usb2/core/usb2_sw_transfer.h>
39#include <dev/usb2/core/usb2_util.h>
40
41#include <dev/usb2/controller/usb2_controller.h>
42#include <dev/usb2/controller/usb2_bus.h>
43#include <dev/usb2/controller/uss820dci.h>
44
45#include <sys/rman.h>
46
47static device_probe_t uss820_atmelarm_probe;
48static device_attach_t uss820_atmelarm_attach;
49static device_detach_t uss820_atmelarm_detach;
50static device_suspend_t uss820_atmelarm_suspend;
51static device_resume_t uss820_atmelarm_resume;
52static device_shutdown_t uss820_atmelarm_shutdown;
53
54static device_method_t uss820dci_methods[] = {
55	/* Device interface */
56	DEVMETHOD(device_probe, uss820_atmelarm_probe),
57	DEVMETHOD(device_attach, uss820_atmelarm_attach),
58	DEVMETHOD(device_detach, uss820_atmelarm_detach),
59	DEVMETHOD(device_suspend, uss820_atmelarm_suspend),
60	DEVMETHOD(device_resume, uss820_atmelarm_resume),
61	DEVMETHOD(device_shutdown, uss820_atmelarm_shutdown),
62
63	/* Bus interface */
64	DEVMETHOD(bus_print_child, bus_generic_print_child),
65
66	{0, 0}
67};
68
69static driver_t uss820dci_driver = {
70	.name = "uss820",
71	.methods = uss820dci_methods,
72	.size = sizeof(struct uss820dci_softc),
73};
74
75static devclass_t uss820dci_devclass;
76
77DRIVER_MODULE(uss820, atmelarm, uss820dci_driver, uss820dci_devclass, 0, 0);
78MODULE_DEPEND(uss820, usb2_controller, 1, 1, 1);
79MODULE_DEPEND(uss820, usb2_core, 1, 1, 1);
80
81static const char *const uss820_desc = "USS820 USB Device Controller";
82
83static int
84uss820_atmelarm_suspend(device_t dev)
85{
86	struct uss820dci_softc *sc = device_get_softc(dev);
87	int err;
88
89	err = bus_generic_suspend(dev);
90	if (err == 0) {
91		uss820dci_suspend(sc);
92	}
93	return (err);
94}
95
96static int
97uss820_atmelarm_resume(device_t dev)
98{
99	struct uss820dci_softc *sc = device_get_softc(dev);
100	int err;
101
102	uss820dci_resume(sc);
103
104	err = bus_generic_resume(dev);
105
106	return (err);
107}
108
109static int
110uss820_atmelarm_shutdown(device_t dev)
111{
112	struct uss820dci_softc *sc = device_get_softc(dev);
113	int err;
114
115	err = bus_generic_shutdown(dev);
116	if (err)
117		return (err);
118
119	uss820dci_uninit(sc);
120
121	return (0);
122}
123
124static int
125uss820_atmelarm_probe(device_t dev)
126{
127	device_set_desc(dev, uss820_desc);
128	return (0);			/* success */
129}
130
131static int
132uss820_atmelarm_attach(device_t dev)
133{
134	struct uss820dci_softc *sc = device_get_softc(dev);
135	int err;
136	int rid;
137
138	if (sc == NULL) {
139		return (ENXIO);
140	}
141	/* get all DMA memory */
142
143	if (usb2_bus_mem_alloc_all(&sc->sc_bus,
144	    USB_GET_DMA_TAG(dev), NULL)) {
145		return (ENOMEM);
146	}
147	rid = 0;
148	sc->sc_io_res =
149	    bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
150
151	if (!sc->sc_io_res) {
152		goto error;
153	}
154	sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
155	sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
156	sc->sc_io_size = rman_get_size(sc->sc_io_res);
157
158	/* multiply all addresses by 4 */
159	sc->sc_reg_shift = 2;
160
161	rid = 0;
162	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
163	    RF_SHAREABLE | RF_ACTIVE);
164	if (sc->sc_irq_res == NULL) {
165		goto error;
166	}
167	sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
168	if (!(sc->sc_bus.bdev)) {
169		goto error;
170	}
171	device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
172
173	err = usb2_config_td_setup(&sc->sc_config_td, sc,
174	    &sc->sc_bus.bus_mtx, NULL, 0, 4);
175	if (err) {
176		device_printf(dev, "could not setup config thread!\n");
177		goto error;
178	}
179#if (__FreeBSD_version >= 700031)
180	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
181	    NULL, (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
182#else
183	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
184	    (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
185#endif
186	if (err) {
187		sc->sc_intr_hdl = NULL;
188		goto error;
189	}
190	err = uss820dci_init(sc);
191	if (err) {
192		device_printf(dev, "Init failed\n");
193		goto error;
194	}
195	err = device_probe_and_attach(sc->sc_bus.bdev);
196	if (err) {
197		device_printf(dev, "USB probe and attach failed\n");
198		goto error;
199	}
200	return (0);
201
202error:
203	uss820_atmelarm_detach(dev);
204	return (ENXIO);
205}
206
207static int
208uss820_atmelarm_detach(device_t dev)
209{
210	struct uss820dci_softc *sc = device_get_softc(dev);
211	device_t bdev;
212	int err;
213
214	if (sc->sc_bus.bdev) {
215		bdev = sc->sc_bus.bdev;
216		device_detach(bdev);
217		device_delete_child(dev, bdev);
218	}
219	/* during module unload there are lots of children leftover */
220	device_delete_all_children(dev);
221
222	if (sc->sc_irq_res && sc->sc_intr_hdl) {
223		/*
224		 * only call at91_udp_uninit() after at91_udp_init()
225		 */
226		uss820dci_uninit(sc);
227
228		err = bus_teardown_intr(dev, sc->sc_irq_res,
229		    sc->sc_intr_hdl);
230		sc->sc_intr_hdl = NULL;
231	}
232	if (sc->sc_irq_res) {
233		bus_release_resource(dev, SYS_RES_IRQ, 0,
234		    sc->sc_irq_res);
235		sc->sc_irq_res = NULL;
236	}
237	if (sc->sc_io_res) {
238		bus_release_resource(dev, SYS_RES_IOPORT, 0,
239		    sc->sc_io_res);
240		sc->sc_io_res = NULL;
241	}
242	usb2_config_td_unsetup(&sc->sc_config_td);
243
244	usb2_bus_mem_free_all(&sc->sc_bus, NULL);
245
246	return (0);
247}
248