oskit/oskit-20020317/dev/membus.c

369 lines
7.7 KiB
C
Raw Permalink Normal View History

2016-02-19 15:02:31 +03:00
/*
* Copyright (c) 1996-1998 University of Utah and the Flux Group.
* All rights reserved.
*
* This file is part of the Flux OSKit. The OSKit is free software, also known
* as "open source;" you can redistribute it and/or modify it under the terms
* of the GNU General Public License (GPL), version 2, as published by the Free
* Software Foundation (FSF). To explore alternate licensing terms, contact
* the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
*
* The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
* received a copy of the GPL along with the OSKit; see the file COPYING. If
* not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
*/
/*
* Default memory bus "device driver",
* representing the local processor bus on which we are running.
*/
#include <stdio.h>
#include <oskit/debug.h>
#include <oskit/boolean.h>
#include <oskit/com.h>
#include <oskit/dev/dev.h>
#include <oskit/dev/device.h>
#include <oskit/dev/bus.h>
#include <oskit/dev/membus.h>
#include <oskit/c/string.h>
/* List of child devices attached to this bus, in no particular order */
static struct busnode {
struct busnode *next;
oskit_addr_t addr;
oskit_device_t *dev;
} *nodes;
#if 0
/* List of address ranges allocated, in no particular order */
static struct arange {
struct arange *next;
oskit_addr_t start, end;
oskit_device_t *dev;
} *ports;
#endif /* 0 */
static OSKIT_COMDECL
query(oskit_membus_t *bus, const oskit_iid_t *iid, void **out_ihandle)
{
if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 ||
memcmp(iid, &oskit_driver_iid, sizeof(*iid)) == 0 ||
memcmp(iid, &oskit_device_iid, sizeof(*iid)) == 0 ||
memcmp(iid, &oskit_bus_iid, sizeof(*iid)) == 0 ||
memcmp(iid, &oskit_membus_iid, sizeof(*iid)) == 0) {
*out_ihandle = bus;
return 0;
}
return OSKIT_E_NOINTERFACE;
}
static OSKIT_COMDECL_U
addref(oskit_membus_t *bus)
{
return 1;
}
static OSKIT_COMDECL_U
release(oskit_membus_t *bus)
{
return 1;
}
static OSKIT_COMDECL
getinfo(oskit_membus_t *bus, oskit_devinfo_t *out_info)
{
out_info->name = "mem";
out_info->description = "Generic Memory Bus";
out_info->vendor = NULL;
out_info->author = "Flux Project, University of Utah";
out_info->version = NULL; /* OSKIT_VERSION or somesuch? */
return 0;
}
static OSKIT_COMDECL
getdriver(oskit_membus_t *dev, oskit_driver_t **out_driver)
{
/*
* Our driver node happens to be the same COM object
* as our device node, making this really easy...
*/
*out_driver = (oskit_driver_t*)dev;
return 0;
}
static OSKIT_COMDECL
probe(oskit_membus_t *bus)
{
/* No probe support at this point */
return OSKIT_E_NOTIMPL;
}
static OSKIT_COMDECL
getchildaddr(oskit_membus_t *bus, oskit_u32_t idx, oskit_device_t **out_fdev,
oskit_addr_t *out_addr)
{
struct busnode *n;
/* Find the node with this index number */
for (n = nodes; ; n = n->next) {
if (n == NULL)
return OSKIT_E_DEV_NOMORE_CHILDREN;
if (idx == 0)
break;
idx--;
}
/* Return a reference to the device attached here */
*out_fdev = n->dev;
oskit_device_addref(n->dev);
*out_addr = n->addr;
return 0;
}
static OSKIT_COMDECL
getchild(oskit_membus_t *bus, oskit_u32_t idx, oskit_device_t **out_fdev,
char *out_pos)
{
oskit_error_t err;
oskit_addr_t addr;
err = getchildaddr(bus, idx, out_fdev, &addr);
if (err)
return err;
if (sizeof(addr) == 4)
sprintf(out_pos, "0x%08x", addr);
else
sprintf(out_pos, "0x%16x", addr);
return 0;
}
#if 0 /* XXX mem_bus_io interface not fully implemented yet */
/*** Bus device registration ***/
static oskit_error_t
add_child(oskit_membus_t *bus, oskit_addr_t addr, oskit_device_t *dev)
{
struct busnode *n;
/* XXX sanity check params */
/* XXX check for addr collisions */
/* Create a new device node */
n = osenv_mem_alloc(sizeof(*n), OSENV_PHYS_WIRED, 0);
if (n == NULL)
return OSKIT_E_OUTOFMEMORY;
n->next = nodes; nodes = n;
n->dev = dev; oskit_device_addref(dev);
n->addr = addr;
return 0;
}
static oskit_error_t
remove_child(oskit_membus_t *bus, oskit_addr_t addr)
{
struct busnode **np, *n;
for (np = &nodes; (n = *np) != NULL; np = &n->next) {
if (n->addr == addr) {
*np = n->next;
oskit_device_release(n->dev);
osenv_mem_free(n, OSENV_PHYS_WIRED, sizeof(*n));
return 0;
}
}
return OSKIT_E_DEV_NOSUCH_CHILD;
}
/*** Address space allocation ***/
static oskit_bool_t addr_avail(oskit_membus_t *bus,
oskit_addr_t start, oskit_size_t size)
{
struct arange *r;
oskit_addr_t end = start + size;
for (r = ports; r; r = r->next) {
if (start < r->end && end > r->start)
return 0;
}
return 1;
}
static oskit_error_t addr_alloc(oskit_membus_t *bus,
oskit_addr_t start, oskit_size_t size,
oskit_device_t *owner)
{
struct arange *r;
oskit_addr_t end = start + size;
if (!addr_avail(bus, start, size))
return OSKIT_E_DEV_SPACE_INUSE;
r = osenv_mem_alloc(sizeof(*r), OSENV_PHYS_WIRED, 0);
if (r == NULL)
return OSKIT_E_OUTOFMEMORY;
r->next = ports; ports = r;
r->dev = owner; oskit_device_addref(owner);
r->start = start;
r->end = end;
return 0;
}
static oskit_error_t addr_free(oskit_membus_t *bus,
oskit_addr_t start, oskit_size_t size)
{
struct arange **rp, *r;
oskit_addr_t end = start + size;
for (rp = &ports; (r = *rp) != NULL; rp = &r->next) {
if (r->start == start && r->end == end) {
*rp = r->next;
oskit_device_release(r->dev);
osenv_mem_free(r, OSENV_PHYS_WIRED, sizeof(*r));
return 0;
}
}
return OSKIT_E_DEV_SPACE_UNASSIGNED;
}
static oskit_error_t addr_scan(oskit_membus_t *bus,
oskit_addr_t *inout_addr, oskit_size_t *out_size,
oskit_device_t **out_owner)
{
struct arange *r, *f = NULL;
oskit_addr_t addr = *inout_addr;
/* Find the first range starting from the specified start address */
for (r = ports; r; r = r->next) {
if (r->end > addr &&
(f == NULL || r->start < f->start))
f = r;
}
/* If no such port was found, return an indication */
if (f == NULL) {
*out_owner = NULL;
return OSKIT_S_FALSE;
}
*inout_addr = f->start;
*out_size = f->end - f->start;
*out_owner = f->dev; oskit_device_addref(f->dev);
return OSKIT_S_TRUE;
}
/*** Physical Memory Access ***/
static oskit_u8_t
read8(oskit_membus_t *bus, oskit_addr_t addr)
{
otsan();
}
static oskit_u16_t
read16(oskit_membus_t *bus, oskit_addr_t addr)
{
otsan();
}
static oskit_u32_t
read32(oskit_membus_t *bus, oskit_addr_t addr)
{
otsan();
}
static oskit_u64_t
read64(oskit_membus_t *bus, oskit_addr_t addr)
{
otsan();
}
static void
write8(oskit_membus_t *bus, oskit_addr_t addr, oskit_u8_t val)
{
otsan();
}
static void
write16(oskit_membus_t *bus, oskit_addr_t addr, oskit_u16_t val)
{
otsan();
}
static void
write32(oskit_membus_t *bus, oskit_addr_t addr, oskit_u32_t val)
{
otsan();
}
static void
write64(oskit_membus_t *bus, oskit_addr_t addr, oskit_u64_t val)
{
otsan();
}
/*** Physical Memory Mapping ***/
static oskit_error_t
map(oskit_membus_t *bus, oskit_addr_t physaddr, oskit_size_t size,
oskit_u32_t flags, void **out_virtaddr)
{
otsan();
}
static oskit_error_t
unmap(oskit_membus_t *bus, void *virtaddr, oskit_size_t size)
{
otsan();
}
#endif /* 0 */
/*** Operation table for the memory bus device */
static struct oskit_membus_ops ops = {
query,
addref,
release,
getinfo,
getdriver,
getchild,
probe,
getchildaddr
};
static oskit_membus_t bus = { &ops };
oskit_error_t
osenv_membus_init(void)
{
static oskit_bool_t initialized = FALSE;
oskit_error_t err;
if (initialized)
return 0;
err = osenv_rootbus_addchild((oskit_device_t*)&bus);
if (err)
return err;
initialized = TRUE;
return 0;
}
oskit_membus_t *osenv_membus_getbus(void)
{
return &bus;
}