ebus resource allocation error?
Joerg Wunsch
j at ida.interface-business.de
Sun May 9 12:27:06 PDT 2004
I'm currently investigating the chances of writing a driver for the
SUNW,envctrl device of my E450. Supposedly, this is an I²C bus, so
it's my hope to eventually setup the driver as a glue interface
between the Sun hardware and iicbus/smbus.
This hardware has the curious (for me at least) situation that it
gets two IRQs assigned:
SUNW,envctrl0: <EBus SUNW,envctrl> addr 0x1400600000-0x1400600003 irq 2021,2024 on ebus0
However, when trying to bus_alloc_resource the second IRQ, I always
get a resource allocation error. Since the code used for resource
allocation is basically the same as I've successfully been using to
allocate multiple IO port ranges in my auxio driver, I rather suspect
a problem in the ebus code itself.
Below are the current probe messages, attached is the source code.
(Please do not redistribute by now, it's really only a stub driver.)
SUNW,envctrl0: <EBus SUNW,envctrl> addr 0x1400600000-0x1400600003 irq 2021,2024 on ebus0
SUNW,envctrl0: Got IRQ rid 0, start 0x7e8, count 0x1
SUNW,envctrl0: Got IRQ rid 1, start 0x7e5, count 0x1
SUNW,envctrl0: could not allocate resources: 2nd IRQ
device_probe_and_attach: SUNW,envctrl0 attach returned 6
--
J"org Wunsch Unix support engineer
joerg_wunsch at interface-systems.de http://www.interface-systems.de/~j/
-------------- next part --------------
/*
* Copyright 2004, Joerg Wunsch
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/resource.h>
#include <sys/uio.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/rman.h>
#include <dev/ofw/openfirm.h>
#include <sparc64/ebus/ebusvar.h>
static int envctrl_probe(device_t);
static int envctrl_attach(device_t);
static int envctrl_detach(device_t);
static device_method_t envctrl_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, envctrl_probe),
DEVMETHOD(device_attach, envctrl_attach),
DEVMETHOD(device_detach, envctrl_detach),
{ 0, 0 }
};
struct envctrl_softc {
struct resource *iores;
struct resource *intres[2];
dev_t devfs_cookie;
device_t dev;
void *intr_cookie[2];
};
static devclass_t envctrl_devclass;
static driver_t envctrl_driver = {
"SUNW,envctrl",
envctrl_methods,
sizeof(struct envctrl_softc),
};
DRIVER_MODULE(envctrl, ebus, envctrl_driver, envctrl_devclass, 0, 0);
static d_open_t envctrl_open;
static d_close_t envctrl_close;
static d_read_t envctrl_read;
static d_write_t envctrl_write;
static d_ioctl_t envctrl_ioctl;
static driver_intr_t envctrl_intr1;
static driver_intr_t envctrl_intr2;
static struct cdevsw envctrl_cdevsw = {
.d_version = D_VERSION,
.d_open = envctrl_open,
.d_close = envctrl_close,
.d_read = envctrl_read,
.d_write = envctrl_write,
.d_ioctl = envctrl_ioctl,
.d_name = "SUNW,envctrl",
};
static int
envctrl_probe(device_t dev)
{
if (strcmp("SUNW,envctrl", ebus_get_name(dev)) == 0) {
device_set_desc(dev, "EBus SUNW,envctrl");
return (0);
}
return (ENXIO);
}
static int
envctrl_attach(device_t dev)
{
struct envctrl_softc *sc;
struct resource *res;
const char *errmsg;
int rid, rv, i;
u_long start, count;
sc = device_get_softc(dev);
rid = 0;
res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
if (res == NULL) {
errmsg = "IO port";
goto allocfail;
}
sc->iores = res;
for (i = 0; i < 2; i++) {
if (bus_get_resource(dev, SYS_RES_IRQ, i, &start, &count) != 0)
continue;
rid = i;
if (bootverbose)
device_printf(dev,
"Got IRQ rid %d, start %#lx, count %#lx\n",
i, start, count);
res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
start, start + count - 1,
count, RF_ACTIVE);
if (res == NULL) {
errmsg = i == 0? "1st IRQ": "2nd IRQ";
goto allocfail;
}
sc->intres[i] = res;
}
rv = BUS_SETUP_INTR(device_get_parent(dev), dev, sc->intres[0],
INTR_TYPE_MISC /* | INTR_ENTROPY */,
envctrl_intr1, sc, sc->intr_cookie + 0);
if (rv) {
errmsg = "1st IRQ";
goto irqfail;
}
rv = BUS_SETUP_INTR(device_get_parent(dev), dev, sc->intres[1],
INTR_TYPE_MISC /* | INTR_ENTROPY */,
envctrl_intr2, sc, sc->intr_cookie + 1);
if (rv) {
errmsg = "1st IRQ";
goto irqfail;
}
sc->devfs_cookie = make_dev(&envctrl_cdevsw, 0, UID_ROOT, GID_WHEEL,
0600, "envctrl");
sc->dev = dev;
return (0);
allocfail:
device_printf(dev, "could not allocate resources: %s\n", errmsg);
return (ENXIO);
irqfail:
device_printf(dev, "could not setup %s\n", errmsg);
return (ENXIO);
}
static int
envctrl_detach(device_t dev)
{
struct envctrl_softc *sc;
sc = device_get_softc(dev);
BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->intres[0],
sc->intr_cookie[0]);
BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->intres[1],
sc->intr_cookie[1]);
bus_deactivate_resource(dev, SYS_RES_IRQ, 0, sc->intres[0]);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->intres[0]);
bus_deactivate_resource(dev, SYS_RES_IRQ, 1, sc->intres[1]);
bus_release_resource(dev, SYS_RES_IRQ, 1, sc->intres[1]);
bus_deactivate_resource(dev, SYS_RES_IOPORT, 0, sc->iores);
bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iores);
destroy_dev(sc->devfs_cookie);
return (0);
}
static int
envctrl_open(dev_t dev, int oflags, int devtype, struct thread *td)
{
return (0);
}
static int
envctrl_close(dev_t dev, int fflag, int devtype, struct thread *td)
{
return (0);
}
static int
envctrl_read(dev_t dev, struct uio *uio, int ioflag)
{
struct envctrl_softc *sc;
uint32_t buf;
int rv;
if (uio->uio_offset != 0)
return (0);
if (uio->uio_resid < sizeof(uint32_t))
return (EINVAL);
sc = devclass_get_softc(envctrl_devclass, 0);
buf = bus_space_read_4(sc->iores->r_bustag, sc->iores->r_bushandle, 0);
rv = uiomove(&buf, sizeof(uint32_t), uio);
return (rv);
}
static int
envctrl_write(dev_t dev, struct uio *uio, int ioflag)
{
struct envctrl_softc *sc;
uint32_t buf;
int rv;
if (uio->uio_offset != 0)
return (0);
if (uio->uio_resid < sizeof(uint32_t))
return (EINVAL);
sc = devclass_get_softc(envctrl_devclass, 0);
if ((rv = uiomove(&buf, sizeof(uint32_t), uio)) != 0)
return (rv);
bus_space_write_4(sc->iores->r_bustag, sc->iores->r_bushandle, 0, buf);
return (0);
}
static int
envctrl_ioctl(dev_t dev, u_long cmd, caddr_t data,
int fflag, struct thread *td)
{
return (ENXIO);
}
static void
envctrl_intr1(void *arg)
{
struct envctrl_softc *sc = (struct envctrl_softc *)arg;
device_printf(sc->dev, "1st IRQ triggered\n");
}
static void
envctrl_intr2(void *arg)
{
struct envctrl_softc *sc = (struct envctrl_softc *)arg;
device_printf(sc->dev, "2nd IRQ triggered\n");
}
More information about the freebsd-sparc64
mailing list