initial import
[ps3freebsd_ps3vuart.git] / ps3av.c
blob773301607544e53f37bd38e6d2b200ae75758737
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 "ps3av_msg.h"
56 #include "ps3av.h"
58 #define PS3AV_LOCK_INIT(_sc) \
59 mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
60 "ps3av", MTX_DEF)
61 #define PS3AV_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx)
62 #define PS3AV_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
63 #define PS3AV_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
64 #define PS3AV_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
65 #define PS3AV_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED)
67 struct ps3av_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 ps3av_intr(void *arg);
82 static int ps3av_init(struct ps3av_softc *sc);
83 static int ps3av_fini(struct ps3av_softc *sc);
85 static int ps3av_dev_open(struct cdev *dev, int flags, int mode,
86 struct thread *td);
87 static int ps3av_dev_close(struct cdev *dev, int flags, int mode,
88 struct thread *td);
89 static int ps3av_dev_read(struct cdev *dev, struct uio *uio, int ioflag);
90 static int ps3av_dev_write(struct cdev *dev, struct uio *uio, int ioflag);
91 static int ps3av_dev_poll(struct cdev *dev, int events, struct thread *td);
93 static MALLOC_DEFINE(M_PS3AV, "ps3av", "PS3 AV");
95 static struct cdevsw ps3av_cdevsw = {
96 .d_version = D_VERSION,
97 .d_open = ps3av_dev_open,
98 .d_close = ps3av_dev_close,
99 .d_read = ps3av_dev_read,
100 .d_write = ps3av_dev_write,
101 .d_poll = ps3av_dev_poll,
102 .d_name = "ps3av",
105 static device_t ps3av_dev = NULL;
107 static int
108 ps3av_probe(device_t dev)
110 if (ps3vuart_bus_get_type(dev) != PS3VUART_BUS_TYPE_AV)
111 return (ENXIO);
113 device_set_desc(dev, "Playstation 3 AV");
115 return (BUS_PROBE_SPECIFIC);
118 static int
119 ps3av_attach(device_t dev)
121 struct ps3av_softc *sc = device_get_softc(dev);
122 int err;
124 sc->sc_dev = dev;
126 PS3AV_LOCK_INIT(sc);
128 PS3AV_LOCK(sc);
130 /* Setup IRQ */
132 sc->sc_irq_id = 0;
133 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
134 &sc->sc_irq_id, RF_ACTIVE);
135 if (!sc->sc_irq) {
136 device_printf(dev, "Could not allocate IRQ\n");
137 err = ENXIO;
138 goto destroy_lock;
141 err = bus_setup_intr(dev, sc->sc_irq,
142 INTR_TYPE_MISC | INTR_MPSAFE,
143 NULL, ps3av_intr, sc, &sc->sc_irq_ctx);
144 if (err) {
145 device_printf(dev, "Could not setup IRQ (%d)\n", err);
146 goto release_irq;
149 /* Setup VUART port */
151 err = ps3vuart_port_init(&sc->sc_port, ps3vuart_bus_get_port(dev));
152 if (err) {
153 device_printf(dev, "Could not setup VUART port (%d)\n", err);
154 goto teardown_irq;
157 /* Setup AV */
159 err = ps3av_init(sc);
160 if (err) {
161 device_printf(dev, "Could not setup AV (%d)\n", err);
162 goto fini_vuart_port;
165 /* Create char device */
167 sc->sc_cdev = make_dev(&ps3av_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
168 "%s", "ps3av");
169 if (!sc->sc_cdev) {
170 device_printf(dev, "Could not create char device\n");
171 err = ENOMEM;
172 goto fini_av;
175 sc->sc_cdev->si_drv1 = sc;
177 ps3av_dev = dev;
179 PS3AV_UNLOCK(sc);
181 return (0);
183 fini_av:
185 ps3av_fini(sc);
187 fini_vuart_port:
189 ps3vuart_port_fini(&sc->sc_port);
191 teardown_irq:
193 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irq_ctx);
195 release_irq:
197 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_id, sc->sc_irq);
199 destroy_lock:
201 PS3AV_UNLOCK(sc);
203 PS3AV_LOCK_DESTROY(sc);
205 return (err);
208 static int
209 ps3av_detach(device_t dev)
211 struct ps3av_softc *sc = device_get_softc(dev);
213 PS3AV_LOCK(sc);
215 ps3av_dev = NULL;
217 /* Destroy char device */
219 destroy_dev(sc->sc_cdev);
221 /* Shutdown AV */
223 ps3av_fini(sc);
225 /* Free IRQ */
227 bus_teardown_intr(dev, sc->sc_irq, sc->sc_irq_ctx);
228 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_id, sc->sc_irq);
230 /* Destroy VUART port */
232 ps3vuart_port_fini(&sc->sc_port);
234 PS3AV_UNLOCK(sc);
236 PS3AV_LOCK_DESTROY(sc);
238 return (0);
241 static void
242 ps3av_intr(void *arg)
244 struct ps3av_softc *sc = arg;
246 PS3AV_LOCK(sc);
248 ps3vuart_port_intr(&sc->sc_port);
250 PS3AV_UNLOCK(sc);
253 static int
254 ps3av_init(struct ps3av_softc *sc)
256 PS3AV_ASSERT_LOCKED(sc);
258 return (0);
261 static int
262 ps3av_fini(struct ps3av_softc *sc)
264 PS3AV_ASSERT_LOCKED(sc);
266 return (0);
270 ps3av_set_video_mode(int mode)
272 struct ps3av_softc *sc;
274 if (!ps3av_dev)
275 return (ENODEV);
277 sc = device_get_softc(ps3av_dev);
279 PS3AV_LOCK(sc);
281 PS3AV_UNLOCK(sc);
283 return (ENODEV);
286 static int
287 ps3av_dev_open(struct cdev *dev, int flags, int mode,
288 struct thread *td)
290 struct ps3av_softc *sc = dev->si_drv1;
292 PS3AV_LOCK(sc);
294 PS3AV_UNLOCK(sc);
296 return (0);
299 static int
300 ps3av_dev_close(struct cdev *dev, int flags, int mode,
301 struct thread *td)
303 struct ps3av_softc *sc = dev->si_drv1;
305 PS3AV_LOCK(sc);
307 PS3AV_UNLOCK(sc);
309 return (0);
312 static int
313 ps3av_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
315 #define BUFSZ 4096
317 struct ps3av_softc *sc = dev->si_drv1;
318 unsigned char *buf;
319 int read;
320 int err = 0;
322 PS3AV_LOCK(sc);
324 if (!uio->uio_resid)
325 goto out;
327 buf = malloc(BUFSZ, M_PS3AV, M_WAITOK);
328 if (!buf) {
329 err = ENOMEM;
330 goto out;
333 while (uio->uio_resid) {
334 err = ps3vuart_port_read(&sc->sc_port, buf,
335 min(uio->uio_resid, BUFSZ), &read);
336 if (err || !read)
337 break;
339 err = uiomove(buf, read, uio);
340 if (!err)
341 break;
344 free(buf, M_PS3AV);
346 out:
348 PS3AV_UNLOCK(sc);
350 return (err);
352 #undef BUFSZ
355 static int
356 ps3av_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
358 #define BUFSZ 4096
360 struct ps3av_softc *sc = dev->si_drv1;
361 unsigned char *buf;
362 int bytes, written;
363 int err = 0;
365 PS3AV_LOCK(sc);
367 if (!uio->uio_resid)
368 goto out;
370 buf = malloc(BUFSZ, M_PS3AV, M_WAITOK);
371 if (!buf) {
372 err = ENOMEM;
373 goto out;
376 while (uio->uio_resid) {
377 bytes = min(uio->uio_resid, BUFSZ);
379 err = uiomove(buf, bytes, uio);
380 if (err)
381 break;
383 err = ps3vuart_port_write(&sc->sc_port, buf, bytes, &written);
384 if (err || !written)
385 break;
388 free(buf, M_PS3AV);
390 out:
392 PS3AV_UNLOCK(sc);
394 return (err);
396 #undef BUFSZ
399 static int
400 ps3av_dev_poll(struct cdev *dev, int events, struct thread *td)
402 struct ps3av_softc *sc = dev->si_drv1;
404 PS3AV_LOCK(sc);
406 /* XXX: implement */
408 PS3AV_UNLOCK(sc);
410 return (0);
413 static device_method_t ps3av_methods[] = {
414 /* Device interface */
415 DEVMETHOD(device_probe, ps3av_probe),
416 DEVMETHOD(device_attach, ps3av_attach),
417 DEVMETHOD(device_detach, ps3av_detach),
419 { 0, 0 }
422 static driver_t ps3av_driver = {
423 "ps3av",
424 ps3av_methods,
425 sizeof(struct ps3av_softc)
428 static devclass_t ps3av_devclass;
430 DRIVER_MODULE(ps3av, ps3vuart_bus, ps3av_driver, ps3av_devclass, 0, 0);
431 MODULE_DEPEND(ps3av, ps3vuart_port, 1, 1, 1);
432 MODULE_VERSION(ps3av, 1);