1#include <sys/cdefs.h>
2__FBSDID("$FreeBSD: head/sys/dev/usb/controller/uss820dci_atmelarm.c 190174 2009-03-20 19:04: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/usb/usb_mfunc.h>
31#include <dev/usb/usb.h>
32
33#include <dev/usb/usb_core.h>
34#include <dev/usb/usb_busdma.h>
35#include <dev/usb/usb_process.h>
36#include <dev/usb/usb_sw_transfer.h>
37#include <dev/usb/usb_util.h>
38
39#include <dev/usb/usb_controller.h>
40#include <dev/usb/usb_bus.h>
41#include <dev/usb/controller/uss820dci.h>
42
43#include <sys/rman.h>
44
45static device_probe_t uss820_atmelarm_probe;
46static device_attach_t uss820_atmelarm_attach;
47static device_detach_t uss820_atmelarm_detach;
48static device_suspend_t uss820_atmelarm_suspend;
49static device_resume_t uss820_atmelarm_resume;
50static device_shutdown_t uss820_atmelarm_shutdown;
51
52static device_method_t uss820dci_methods[] = {
53 /* Device interface */
54 DEVMETHOD(device_probe, uss820_atmelarm_probe),
55 DEVMETHOD(device_attach, uss820_atmelarm_attach),
56 DEVMETHOD(device_detach, uss820_atmelarm_detach),
57 DEVMETHOD(device_suspend, uss820_atmelarm_suspend),
58 DEVMETHOD(device_resume, uss820_atmelarm_resume),
59 DEVMETHOD(device_shutdown, uss820_atmelarm_shutdown),
60
61 /* Bus interface */
62 DEVMETHOD(bus_print_child, bus_generic_print_child),
63
64 {0, 0}
65};
66
67static driver_t uss820dci_driver = {
68 .name = "uss820",
69 .methods = uss820dci_methods,
70 .size = sizeof(struct uss820dci_softc),
71};
72
73static devclass_t uss820dci_devclass;
74
75DRIVER_MODULE(uss820, atmelarm, uss820dci_driver, uss820dci_devclass, 0, 0);
76MODULE_DEPEND(uss820, usb, 1, 1, 1);
77
78static const char *const uss820_desc = "USS820 USB Device Controller";
79
80static int
81uss820_atmelarm_suspend(device_t dev)
82{
83 struct uss820dci_softc *sc = device_get_softc(dev);
84 int err;
85
86 err = bus_generic_suspend(dev);
87 if (err == 0) {
88 uss820dci_suspend(sc);
89 }
90 return (err);
91}
92
93static int
94uss820_atmelarm_resume(device_t dev)
95{
96 struct uss820dci_softc *sc = device_get_softc(dev);
97 int err;
98
99 uss820dci_resume(sc);
100
101 err = bus_generic_resume(dev);
102
103 return (err);
104}
105
106static int
107uss820_atmelarm_shutdown(device_t dev)
108{
109 struct uss820dci_softc *sc = device_get_softc(dev);
110 int err;
111
112 err = bus_generic_shutdown(dev);
113 if (err)
114 return (err);
115
116 uss820dci_uninit(sc);
117
118 return (0);
119}
120
121static int
122uss820_atmelarm_probe(device_t dev)
123{
124 device_set_desc(dev, uss820_desc);
125 return (0); /* success */
126}
127
128static int
129uss820_atmelarm_attach(device_t dev)
130{
131 struct uss820dci_softc *sc = device_get_softc(dev);
132 int err;
133 int rid;
134
135 /* initialise some bus fields */
136 sc->sc_bus.parent = dev;
137 sc->sc_bus.devices = sc->sc_devices;
138 sc->sc_bus.devices_max = USS820_MAX_DEVICES;
139
140 /* get all DMA memory */
141 if (usb2_bus_mem_alloc_all(&sc->sc_bus,
142 USB_GET_DMA_TAG(dev), NULL)) {
143 return (ENOMEM);
144 }
145 rid = 0;
146 sc->sc_io_res =
147 bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
148
149 if (!sc->sc_io_res) {
150 goto error;
151 }
152 sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
153 sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
154 sc->sc_io_size = rman_get_size(sc->sc_io_res);
155
156 /* multiply all addresses by 4 */
157 sc->sc_reg_shift = 2;
158
159 rid = 0;
160 sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
161 RF_SHAREABLE | RF_ACTIVE);
162 if (sc->sc_irq_res == NULL) {
163 goto error;
164 }
165 sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
166 if (!(sc->sc_bus.bdev)) {
167 goto error;
168 }
169 device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
170
171#if (__FreeBSD_version >= 700031)
172 err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
173 NULL, (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
174#else
175 err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
176 (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
177#endif
178 if (err) {
179 sc->sc_intr_hdl = NULL;
180 goto error;
181 }
182 err = uss820dci_init(sc);
183 if (err) {
184 device_printf(dev, "Init failed\n");
185 goto error;
186 }
187 err = device_probe_and_attach(sc->sc_bus.bdev);
188 if (err) {
189 device_printf(dev, "USB probe and attach failed\n");
190 goto error;
191 }
192 return (0);
193
194error:
195 uss820_atmelarm_detach(dev);
196 return (ENXIO);
197}
198
199static int
200uss820_atmelarm_detach(device_t dev)
201{
202 struct uss820dci_softc *sc = device_get_softc(dev);
203 device_t bdev;
204 int err;
205
206 if (sc->sc_bus.bdev) {
207 bdev = sc->sc_bus.bdev;
208 device_detach(bdev);
209 device_delete_child(dev, bdev);
210 }
211 /* during module unload there are lots of children leftover */
212 device_delete_all_children(dev);
213
214 if (sc->sc_irq_res && sc->sc_intr_hdl) {
215 /*
216 * only call at91_udp_uninit() after at91_udp_init()
217 */
218 uss820dci_uninit(sc);
219
220 err = bus_teardown_intr(dev, sc->sc_irq_res,
221 sc->sc_intr_hdl);
222 sc->sc_intr_hdl = NULL;
223 }
224 if (sc->sc_irq_res) {
225 bus_release_resource(dev, SYS_RES_IRQ, 0,
226 sc->sc_irq_res);
227 sc->sc_irq_res = NULL;
228 }
229 if (sc->sc_io_res) {
230 bus_release_resource(dev, SYS_RES_IOPORT, 0,
231 sc->sc_io_res);
232 sc->sc_io_res = NULL;
233 }
234 usb2_bus_mem_free_all(&sc->sc_bus, NULL);
235
236 return (0);
237}
2__FBSDID("$FreeBSD: head/sys/dev/usb/controller/uss820dci_atmelarm.c 190174 2009-03-20 19:04: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/usb/usb_mfunc.h>
31#include <dev/usb/usb.h>
32
33#include <dev/usb/usb_core.h>
34#include <dev/usb/usb_busdma.h>
35#include <dev/usb/usb_process.h>
36#include <dev/usb/usb_sw_transfer.h>
37#include <dev/usb/usb_util.h>
38
39#include <dev/usb/usb_controller.h>
40#include <dev/usb/usb_bus.h>
41#include <dev/usb/controller/uss820dci.h>
42
43#include <sys/rman.h>
44
45static device_probe_t uss820_atmelarm_probe;
46static device_attach_t uss820_atmelarm_attach;
47static device_detach_t uss820_atmelarm_detach;
48static device_suspend_t uss820_atmelarm_suspend;
49static device_resume_t uss820_atmelarm_resume;
50static device_shutdown_t uss820_atmelarm_shutdown;
51
52static device_method_t uss820dci_methods[] = {
53 /* Device interface */
54 DEVMETHOD(device_probe, uss820_atmelarm_probe),
55 DEVMETHOD(device_attach, uss820_atmelarm_attach),
56 DEVMETHOD(device_detach, uss820_atmelarm_detach),
57 DEVMETHOD(device_suspend, uss820_atmelarm_suspend),
58 DEVMETHOD(device_resume, uss820_atmelarm_resume),
59 DEVMETHOD(device_shutdown, uss820_atmelarm_shutdown),
60
61 /* Bus interface */
62 DEVMETHOD(bus_print_child, bus_generic_print_child),
63
64 {0, 0}
65};
66
67static driver_t uss820dci_driver = {
68 .name = "uss820",
69 .methods = uss820dci_methods,
70 .size = sizeof(struct uss820dci_softc),
71};
72
73static devclass_t uss820dci_devclass;
74
75DRIVER_MODULE(uss820, atmelarm, uss820dci_driver, uss820dci_devclass, 0, 0);
76MODULE_DEPEND(uss820, usb, 1, 1, 1);
77
78static const char *const uss820_desc = "USS820 USB Device Controller";
79
80static int
81uss820_atmelarm_suspend(device_t dev)
82{
83 struct uss820dci_softc *sc = device_get_softc(dev);
84 int err;
85
86 err = bus_generic_suspend(dev);
87 if (err == 0) {
88 uss820dci_suspend(sc);
89 }
90 return (err);
91}
92
93static int
94uss820_atmelarm_resume(device_t dev)
95{
96 struct uss820dci_softc *sc = device_get_softc(dev);
97 int err;
98
99 uss820dci_resume(sc);
100
101 err = bus_generic_resume(dev);
102
103 return (err);
104}
105
106static int
107uss820_atmelarm_shutdown(device_t dev)
108{
109 struct uss820dci_softc *sc = device_get_softc(dev);
110 int err;
111
112 err = bus_generic_shutdown(dev);
113 if (err)
114 return (err);
115
116 uss820dci_uninit(sc);
117
118 return (0);
119}
120
121static int
122uss820_atmelarm_probe(device_t dev)
123{
124 device_set_desc(dev, uss820_desc);
125 return (0); /* success */
126}
127
128static int
129uss820_atmelarm_attach(device_t dev)
130{
131 struct uss820dci_softc *sc = device_get_softc(dev);
132 int err;
133 int rid;
134
135 /* initialise some bus fields */
136 sc->sc_bus.parent = dev;
137 sc->sc_bus.devices = sc->sc_devices;
138 sc->sc_bus.devices_max = USS820_MAX_DEVICES;
139
140 /* get all DMA memory */
141 if (usb2_bus_mem_alloc_all(&sc->sc_bus,
142 USB_GET_DMA_TAG(dev), NULL)) {
143 return (ENOMEM);
144 }
145 rid = 0;
146 sc->sc_io_res =
147 bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
148
149 if (!sc->sc_io_res) {
150 goto error;
151 }
152 sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
153 sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
154 sc->sc_io_size = rman_get_size(sc->sc_io_res);
155
156 /* multiply all addresses by 4 */
157 sc->sc_reg_shift = 2;
158
159 rid = 0;
160 sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
161 RF_SHAREABLE | RF_ACTIVE);
162 if (sc->sc_irq_res == NULL) {
163 goto error;
164 }
165 sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
166 if (!(sc->sc_bus.bdev)) {
167 goto error;
168 }
169 device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
170
171#if (__FreeBSD_version >= 700031)
172 err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
173 NULL, (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
174#else
175 err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
176 (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl);
177#endif
178 if (err) {
179 sc->sc_intr_hdl = NULL;
180 goto error;
181 }
182 err = uss820dci_init(sc);
183 if (err) {
184 device_printf(dev, "Init failed\n");
185 goto error;
186 }
187 err = device_probe_and_attach(sc->sc_bus.bdev);
188 if (err) {
189 device_printf(dev, "USB probe and attach failed\n");
190 goto error;
191 }
192 return (0);
193
194error:
195 uss820_atmelarm_detach(dev);
196 return (ENXIO);
197}
198
199static int
200uss820_atmelarm_detach(device_t dev)
201{
202 struct uss820dci_softc *sc = device_get_softc(dev);
203 device_t bdev;
204 int err;
205
206 if (sc->sc_bus.bdev) {
207 bdev = sc->sc_bus.bdev;
208 device_detach(bdev);
209 device_delete_child(dev, bdev);
210 }
211 /* during module unload there are lots of children leftover */
212 device_delete_all_children(dev);
213
214 if (sc->sc_irq_res && sc->sc_intr_hdl) {
215 /*
216 * only call at91_udp_uninit() after at91_udp_init()
217 */
218 uss820dci_uninit(sc);
219
220 err = bus_teardown_intr(dev, sc->sc_irq_res,
221 sc->sc_intr_hdl);
222 sc->sc_intr_hdl = NULL;
223 }
224 if (sc->sc_irq_res) {
225 bus_release_resource(dev, SYS_RES_IRQ, 0,
226 sc->sc_irq_res);
227 sc->sc_irq_res = NULL;
228 }
229 if (sc->sc_io_res) {
230 bus_release_resource(dev, SYS_RES_IOPORT, 0,
231 sc->sc_io_res);
232 sc->sc_io_res = NULL;
233 }
234 usb2_bus_mem_free_all(&sc->sc_bus, NULL);
235
236 return (0);
237}