2 * Copyright (C) 2011, 2012 glevand <geoffrey.levand@mail.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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>
38 #include <sys/malloc.h>
40 #include <sys/mutex.h>
42 #include <sys/resource.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"
58 #define PS3DM_LOCK_INIT(_sc) \
59 mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
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)
73 struct resource
*sc_irq
;
76 struct ps3vuart_port sc_port
;
81 static void ps3dm_intr(void *arg
);
83 static int ps3dm_dev_open(struct cdev
*dev
, int flags
, int mode
,
85 static int ps3dm_dev_close(struct cdev
*dev
, int flags
, int mode
,
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
,
103 static device_t ps3dm_dev
= NULL
;
106 ps3dm_probe(device_t dev
)
108 if (ps3vuart_bus_get_type(dev
) != PS3VUART_BUS_TYPE_DM
)
111 device_set_desc(dev
, "Playstation 3 DM");
113 return (BUS_PROBE_SPECIFIC
);
117 ps3dm_attach(device_t dev
)
119 struct ps3dm_softc
*sc
= device_get_softc(dev
);
131 sc
->sc_irq
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
,
132 &sc
->sc_irq_id
, RF_ACTIVE
);
134 device_printf(dev
, "Could not allocate IRQ\n");
139 err
= bus_setup_intr(dev
, sc
->sc_irq
,
140 INTR_TYPE_MISC
| INTR_MPSAFE
,
141 NULL
, ps3dm_intr
, sc
, &sc
->sc_irq_ctx
);
143 device_printf(dev
, "Could not setup IRQ (%d)\n", err
);
147 /* Setup VUART port */
149 err
= ps3vuart_port_init(&sc
->sc_port
, ps3vuart_bus_get_port(dev
));
151 device_printf(dev
, "Could not setup VUART port (%d)\n", err
);
155 /* Create char device */
157 sc
->sc_cdev
= make_dev(&ps3dm_cdevsw
, 0, UID_ROOT
, GID_WHEEL
, 0600,
160 device_printf(dev
, "Could not create char device\n");
162 goto fini_vuart_port
;
165 sc
->sc_cdev
->si_drv1
= sc
;
175 ps3vuart_port_fini(&sc
->sc_port
);
179 bus_teardown_intr(dev
, sc
->sc_irq
, sc
->sc_irq_ctx
);
183 bus_release_resource(dev
, SYS_RES_IRQ
, sc
->sc_irq_id
, sc
->sc_irq
);
189 PS3DM_LOCK_DESTROY(sc
);
195 ps3dm_detach(device_t dev
)
197 struct ps3dm_softc
*sc
= device_get_softc(dev
);
203 /* Destroy char device */
205 destroy_dev(sc
->sc_cdev
);
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
);
218 PS3DM_LOCK_DESTROY(sc
);
224 ps3dm_intr(void *arg
)
226 struct ps3dm_softc
*sc
= arg
;
230 ps3vuart_port_intr(&sc
->sc_port
);
236 ps3dm_dev_open(struct cdev
*dev
, int flags
, int mode
,
239 struct ps3dm_softc
*sc
= dev
->si_drv1
;
249 ps3dm_dev_close(struct cdev
*dev
, int flags
, int mode
,
252 struct ps3dm_softc
*sc
= dev
->si_drv1
;
262 ps3dm_dev_read(struct cdev
*dev
, struct uio
*uio
, int ioflag
)
266 struct ps3dm_softc
*sc
= dev
->si_drv1
;
276 buf
= malloc(BUFSZ
, M_PS3DM
, M_WAITOK
);
282 while (uio
->uio_resid
) {
283 err
= ps3vuart_port_read(&sc
->sc_port
, buf
,
284 min(uio
->uio_resid
, BUFSZ
), &read
);
288 err
= uiomove(buf
, read
, uio
);
305 ps3dm_dev_write(struct cdev
*dev
, struct uio
*uio
, int ioflag
)
309 struct ps3dm_softc
*sc
= dev
->si_drv1
;
319 buf
= malloc(BUFSZ
, M_PS3DM
, M_WAITOK
);
325 while (uio
->uio_resid
) {
326 bytes
= min(uio
->uio_resid
, BUFSZ
);
328 err
= uiomove(buf
, bytes
, uio
);
332 err
= ps3vuart_port_write(&sc
->sc_port
, buf
, bytes
, &written
);
349 ps3dm_dev_poll(struct cdev
*dev
, int events
, struct thread
*td
)
351 struct ps3dm_softc
*sc
= dev
->si_drv1
;
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
),
371 static driver_t ps3dm_driver
= {
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);