initial import
[ps3freebsd_ps3vuart.git] / ps3dm.c
blobfa6bbad98200ab54c162f3e41561238989a2c7ab
1 /*-
2 * Copyright (C) 2011, 2012 glevand <geoffrey.levand@mail.ru>
3 * All rights reserved.
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 * without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD$
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/module.h>
34 #include <sys/kernel.h>
35 #include <sys/systm.h>
36 #include <sys/conf.h>
37 #include <sys/bus.h>
38 #include <sys/malloc.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/uio.h>
42 #include <sys/resource.h>
43 #include <sys/rman.h>
45 #include <vm/vm.h>
46 #include <vm/pmap.h>
48 #include <machine/bus.h>
49 #include <machine/platform.h>
50 #include <machine/pmap.h>
51 #include <machine/resource.h>
53 #include "ps3vuart_bus.h"
54 #include "ps3vuart_port.h"
55 #include "ps3dm_msg.h"
56 #include "ps3dm.h"
58 #define PS3DM_LOCK_INIT(_sc) \
59 mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
60 "ps3dm", MTX_DEF)
61 #define PS3DM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx)
62 #define PS3DM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
63 #define PS3DM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
64 #define PS3DM_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
65 #define PS3DM_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED)
67 struct ps3dm_softc {
68 device_t sc_dev;
70 struct mtx sc_mtx;
72 int sc_irq_id;
73 struct resource *sc_irq;
74 void *sc_irq_ctx;
76 struct ps3vuart_port sc_port;
78 struct cdev *sc_cdev;
81 static void ps3dm_intr(void *arg);
83 static int ps3dm_dev_open(struct cdev *dev, int flags, int mode,
84 struct thread *td);
85 static int ps3dm_dev_close(struct cdev *dev, int flags, int mode,
86 struct thread *td);
87 static int ps3dm_dev_read(struct cdev *dev, struct uio *uio, int ioflag);
88 static int ps3dm_dev_write(struct cdev *dev, struct uio *uio, int ioflag);
89 static int ps3dm_dev_poll(struct cdev *dev, int events, struct thread *td);
91 static MALLOC_DEFINE(M_PS3DM, "ps3dm", "PS3 DM");
93 static struct cdevsw ps3dm_cdevsw = {
94 .d_version = D_VERSION,
95 .d_open = ps3dm_dev_open,
96 .d_close = ps3dm_dev_close,
97 .d_read = ps3dm_dev_read,
98 .d_write = ps3dm_dev_write,
99 .d_poll = ps3dm_dev_poll,
100 .d_name = "ps3dm",
103 static device_t ps3dm_dev = NULL;
105 static int
106 ps3dm_probe(device_t dev)
108 if (ps3vuart_bus_get_type(dev) != PS3VUART_BUS_TYPE_DM)
109 return (ENXIO);
111 device_set_desc(dev, "Playstation 3 DM");
113 return (BUS_PROBE_SPECIFIC);
116 static int
117 ps3dm_attach(device_t dev)
119 struct ps3dm_softc *sc = device_get_softc(dev);
120 int err;
122 sc->sc_dev = dev;
124 PS3DM_LOCK_INIT(sc);
126 PS3DM_LOCK(sc);
128 /* Setup IRQ */
130 sc->sc_irq_id = 0;
131 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
132 &sc->sc_irq_id, RF_ACTIVE);
133 if (!sc->sc_irq) {
134 device_printf(dev, "Could not allocate IRQ\n");
135 err = ENXIO;
136 goto destroy_lock;
139 err = bus_setup_intr(dev, sc->sc_irq,
140 INTR_TYPE_MISC | INTR_MPSAFE,
141 NULL, ps3dm_intr, sc, &sc->sc_irq_ctx);
142 if (err) {
143 device_printf(dev, "Could not setup IRQ (%d)\n", err);
144 goto release_irq;
147 /* Setup VUART port */
149 err = ps3vuart_port_init(&sc->sc_port, ps3vuart_bus_get_port(dev));
150 if (err) {
151 device_printf(dev, "Could not setup VUART port (%d)\n", err);
152 goto teardown_irq;
155 /* Create char device */
157 sc->sc_cdev = make_dev(&ps3dm_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
158 "%s", "ps3dm");
159 if (!sc->sc_cdev) {
160 device_printf(dev, "Could not create char device\n");
161 err = ENOMEM;
162 goto fini_vuart_port;
165 sc->sc_cdev->si_drv1 = sc;
167 ps3dm_dev = dev;
169 PS3DM_UNLOCK(sc);
171 return (0);
173 fini_vuart_port:
175 ps3vuart_port_fini(&sc->sc_port);
177 teardown_irq:
179 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irq_ctx);
181 release_irq:
183 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_id, sc->sc_irq);
185 destroy_lock:
187 PS3DM_UNLOCK(sc);
189 PS3DM_LOCK_DESTROY(sc);
191 return (err);
194 static int
195 ps3dm_detach(device_t dev)
197 struct ps3dm_softc *sc = device_get_softc(dev);
199 PS3DM_LOCK(sc);
201 ps3dm_dev = NULL;
203 /* Destroy char device */
205 destroy_dev(sc->sc_cdev);
207 /* Free IRQ */
209 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irq_ctx);
210 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_id, sc->sc_irq);
212 /* Destroy VUART port */
214 ps3vuart_port_fini(&sc->sc_port);
216 PS3DM_UNLOCK(sc);
218 PS3DM_LOCK_DESTROY(sc);
220 return (0);
223 static void
224 ps3dm_intr(void *arg)
226 struct ps3dm_softc *sc = arg;
228 PS3DM_LOCK(sc);
230 ps3vuart_port_intr(&sc->sc_port);
232 PS3DM_UNLOCK(sc);
235 static int
236 ps3dm_dev_open(struct cdev *dev, int flags, int mode,
237 struct thread *td)
239 struct ps3dm_softc *sc = dev->si_drv1;
241 PS3DM_LOCK(sc);
243 PS3DM_UNLOCK(sc);
245 return (0);
248 static int
249 ps3dm_dev_close(struct cdev *dev, int flags, int mode,
250 struct thread *td)
252 struct ps3dm_softc *sc = dev->si_drv1;
254 PS3DM_LOCK(sc);
256 PS3DM_UNLOCK(sc);
258 return (0);
261 static int
262 ps3dm_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
264 #define BUFSZ 4096
266 struct ps3dm_softc *sc = dev->si_drv1;
267 unsigned char *buf;
268 int read;
269 int err = 0;
271 PS3DM_LOCK(sc);
273 if (!uio->uio_resid)
274 goto out;
276 buf = malloc(BUFSZ, M_PS3DM, M_WAITOK);
277 if (!buf) {
278 err = ENOMEM;
279 goto out;
282 while (uio->uio_resid) {
283 err = ps3vuart_port_read(&sc->sc_port, buf,
284 min(uio->uio_resid, BUFSZ), &read);
285 if (err || !read)
286 break;
288 err = uiomove(buf, read, uio);
289 if (!err)
290 break;
293 free(buf, M_PS3DM);
295 out:
297 PS3DM_UNLOCK(sc);
299 return (err);
301 #undef BUFSZ
304 static int
305 ps3dm_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
307 #define BUFSZ 4096
309 struct ps3dm_softc *sc = dev->si_drv1;
310 unsigned char *buf;
311 int bytes, written;
312 int err = 0;
314 PS3DM_LOCK(sc);
316 if (!uio->uio_resid)
317 goto out;
319 buf = malloc(BUFSZ, M_PS3DM, M_WAITOK);
320 if (!buf) {
321 err = ENOMEM;
322 goto out;
325 while (uio->uio_resid) {
326 bytes = min(uio->uio_resid, BUFSZ);
328 err = uiomove(buf, bytes, uio);
329 if (err)
330 break;
332 err = ps3vuart_port_write(&sc->sc_port, buf, bytes, &written);
333 if (err || !written)
334 break;
337 free(buf, M_PS3DM);
339 out:
341 PS3DM_UNLOCK(sc);
343 return (err);
345 #undef BUFSZ
348 static int
349 ps3dm_dev_poll(struct cdev *dev, int events, struct thread *td)
351 struct ps3dm_softc *sc = dev->si_drv1;
353 PS3DM_LOCK(sc);
355 /* XXX: implement */
357 PS3DM_UNLOCK(sc);
359 return (0);
362 static device_method_t ps3dm_methods[] = {
363 /* Device interface */
364 DEVMETHOD(device_probe, ps3dm_probe),
365 DEVMETHOD(device_attach, ps3dm_attach),
366 DEVMETHOD(device_detach, ps3dm_detach),
368 { 0, 0 }
371 static driver_t ps3dm_driver = {
372 "ps3dm",
373 ps3dm_methods,
374 sizeof(struct ps3dm_softc)
377 static devclass_t ps3dm_devclass;
379 DRIVER_MODULE(ps3dm, ps3vuart_bus, ps3dm_driver, ps3dm_devclass, 0, 0);
380 MODULE_DEPEND(ps3dm, ps3vuart_port, 1, 1, 1);
381 MODULE_VERSION(ps3dm, 1);