mirror of https://github.com/dzavalishin/oskit/
310 lines
6.3 KiB
C
Executable File
310 lines
6.3 KiB
C
Executable File
/*
|
|
* Copyright (c) 1997-2000 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 implementation of buffer routines.
|
|
* Besides providing a useful service,
|
|
* this module serves as an example of how to implement bufio objects.
|
|
*/
|
|
|
|
#include <oskit/io/bufio.h>
|
|
#include <oskit/c/string.h>
|
|
#include <oskit/c/stdlib.h>
|
|
#include <oskit/c/assert.h>
|
|
#include <oskit/dev/osenv.h>
|
|
#include <oskit/dev/osenv_mem.h>
|
|
|
|
struct mybufio {
|
|
oskit_bufio_t ioi; /* COM I/O Interface */
|
|
unsigned count; /* reference count */
|
|
oskit_size_t size; /* size of buffer */
|
|
/* the buffer itself follows... */
|
|
};
|
|
typedef struct mybufio mybufio_t;
|
|
|
|
#ifdef INDIRECT_OSENV
|
|
static oskit_osenv_mem_t *bufio_mem;
|
|
#endif
|
|
|
|
/*
|
|
* Query a buffer I/O object for it's interfaces.
|
|
*
|
|
*/
|
|
static OSKIT_COMDECL
|
|
bufio_query(oskit_bufio_t *io, const oskit_iid_t *iid, void **out_ihandle)
|
|
{
|
|
struct mybufio *b;
|
|
|
|
b = (mybufio_t *)io;
|
|
assert(b != NULL);
|
|
assert(b->count != 0);
|
|
|
|
if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 ||
|
|
memcmp(iid, &oskit_bufio_iid, sizeof(*iid)) == 0) {
|
|
*out_ihandle = &b->ioi;
|
|
++b->count;
|
|
|
|
return 0;
|
|
}
|
|
|
|
*out_ihandle = NULL;
|
|
return OSKIT_E_NOINTERFACE;
|
|
}
|
|
|
|
/*
|
|
* Clone a reference to a device's block I/O interface.
|
|
*/
|
|
static OSKIT_COMDECL_U
|
|
bufio_addref(oskit_bufio_t *io)
|
|
{
|
|
struct mybufio *b;
|
|
|
|
b = (struct mybufio *)io;
|
|
assert(b != NULL);
|
|
assert(b->count != 0);
|
|
|
|
return ++b->count;
|
|
}
|
|
|
|
static OSKIT_COMDECL_U
|
|
bufio_release(oskit_bufio_t *io)
|
|
{
|
|
struct mybufio *b;
|
|
unsigned newcount;
|
|
|
|
b = (struct mybufio *)io;
|
|
|
|
assert(b != NULL);
|
|
assert(b->count != 0);
|
|
|
|
if ((newcount = --b->count) == 0) {
|
|
#ifndef INDIRECT_OSENV
|
|
osenv_mem_free(b, OSENV_PHYS_WIRED | OSENV_AUTO_SIZE, 0);
|
|
#else
|
|
assert(bufio_mem != 0);
|
|
|
|
oskit_osenv_mem_free(bufio_mem,
|
|
b, OSENV_PHYS_WIRED | OSENV_AUTO_SIZE, 0);
|
|
#endif
|
|
}
|
|
|
|
return newcount;
|
|
}
|
|
|
|
/*
|
|
* Return the block size of this blkio object - always 1.
|
|
*/
|
|
static OSKIT_COMDECL_U
|
|
bufio_getblocksize(oskit_bufio_t *io)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Copy data from a user buffer into kernel's address space.
|
|
*/
|
|
static OSKIT_COMDECL
|
|
bufio_read(oskit_bufio_t *io, void *dest, oskit_off_t offset, oskit_size_t count,
|
|
oskit_size_t *out_actual)
|
|
{
|
|
struct mybufio *b;
|
|
|
|
b = (struct mybufio *)io;
|
|
|
|
assert(b != NULL);
|
|
assert(b->count != 0);
|
|
|
|
if (offset >= b->size)
|
|
return OSKIT_EINVAL;
|
|
if (offset + count > b->size)
|
|
count = b->size - offset;
|
|
|
|
memcpy(dest, (void *)(b+1) + offset, count);
|
|
|
|
*out_actual = count;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Copy data from kernel address space to a user buffer.
|
|
*/
|
|
static OSKIT_COMDECL
|
|
bufio_write(oskit_bufio_t *io, const void *src, oskit_off_t offset,
|
|
oskit_size_t count, oskit_size_t *out_actual)
|
|
{
|
|
struct mybufio *b;
|
|
|
|
b = (struct mybufio *)io;
|
|
|
|
assert(b != NULL);
|
|
assert(b->count != 0);
|
|
|
|
if (offset >= b->size)
|
|
return OSKIT_EINVAL;
|
|
if (offset + count > b->size)
|
|
count = b->size - offset;
|
|
|
|
memcpy((void *)(b+1) + offset, src, count);
|
|
|
|
*out_actual = count;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Return the size of this buffer.
|
|
*/
|
|
static OSKIT_COMDECL
|
|
bufio_getsize(oskit_bufio_t *io, oskit_off_t *out_size)
|
|
{
|
|
struct mybufio *b;
|
|
|
|
b = (struct mybufio *)io;
|
|
assert(b != NULL);
|
|
assert(b->count != 0);
|
|
|
|
*out_size = b->size;
|
|
return 0;
|
|
}
|
|
|
|
static OSKIT_COMDECL
|
|
bufio_setsize(oskit_bufio_t *io, oskit_off_t size)
|
|
{
|
|
struct mybufio *b;
|
|
|
|
b = (struct mybufio *)io;
|
|
|
|
assert(b != NULL);
|
|
assert(b->count != 0);
|
|
|
|
return OSKIT_E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static OSKIT_COMDECL
|
|
bufio_map(oskit_bufio_t *io, void **out_addr,
|
|
oskit_off_t offset, oskit_size_t count)
|
|
{
|
|
struct mybufio *b;
|
|
|
|
b = (struct mybufio *)io;
|
|
|
|
assert(b != NULL);
|
|
assert(b->count != 0);
|
|
|
|
if (offset + count > b->size)
|
|
return OSKIT_EINVAL;
|
|
|
|
*out_addr = (void*)(b+1) + offset;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* XXX These should probably do checking on their inputs so we could
|
|
* catch bugs in the code that calls them.
|
|
*/
|
|
|
|
static OSKIT_COMDECL
|
|
bufio_unmap(oskit_bufio_t *io, void *addr, oskit_off_t offset,
|
|
oskit_size_t count)
|
|
{
|
|
struct mybufio *b;
|
|
|
|
b = (struct mybufio *)io;
|
|
|
|
assert(b != NULL);
|
|
assert(b->count != 0);
|
|
|
|
if (offset + count > b->size)
|
|
return OSKIT_EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static OSKIT_COMDECL
|
|
bufio_wire(oskit_bufio_t *io, oskit_addr_t *out_physaddr,
|
|
oskit_off_t offset, oskit_size_t count)
|
|
{
|
|
return OSKIT_E_NOTIMPL;
|
|
}
|
|
|
|
static OSKIT_COMDECL
|
|
bufio_unwire(oskit_bufio_t *io, oskit_addr_t phys_addr,
|
|
oskit_off_t offset, oskit_size_t count)
|
|
{
|
|
return OSKIT_E_NOTIMPL;
|
|
}
|
|
|
|
static OSKIT_COMDECL
|
|
bufio_copy(oskit_bufio_t *io, oskit_off_t offset, oskit_size_t count,
|
|
oskit_bufio_t **out_io)
|
|
{
|
|
return OSKIT_E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static struct oskit_bufio_ops bio_ops = {
|
|
bufio_query, bufio_addref, bufio_release,
|
|
bufio_getblocksize,
|
|
bufio_read, bufio_write,
|
|
bufio_getsize, bufio_setsize,
|
|
bufio_map, bufio_unmap,
|
|
bufio_wire, bufio_unwire,
|
|
bufio_copy
|
|
};
|
|
|
|
|
|
oskit_bufio_t *
|
|
oskit_bufio_create(oskit_size_t size)
|
|
{
|
|
mybufio_t *b;
|
|
|
|
/* XXX: must be wired memory for DMA drivers */
|
|
|
|
#ifndef INDIRECT_OSENV
|
|
b = (struct mybufio *)osenv_mem_alloc(
|
|
sizeof(*b) + size,
|
|
OSENV_PHYS_WIRED | OSENV_AUTO_SIZE, 0);
|
|
#else
|
|
/*
|
|
* If this is the first call,
|
|
* find the osenv, and then the osenv_mem interface.
|
|
*/
|
|
if (bufio_mem == 0) {
|
|
oskit_osenv_t *osenv;
|
|
|
|
oskit_lookup_first(&oskit_osenv_iid, (void **)&osenv);
|
|
assert(osenv);
|
|
oskit_osenv_lookup(osenv, &oskit_osenv_mem_iid,
|
|
(void **)&bufio_mem);
|
|
assert(bufio_mem);
|
|
oskit_osenv_release(osenv);
|
|
}
|
|
b = (struct mybufio *)oskit_osenv_mem_alloc(bufio_mem,
|
|
sizeof(*b) + size,
|
|
OSENV_PHYS_WIRED | OSENV_AUTO_SIZE, 0);
|
|
#endif
|
|
if (b == NULL)
|
|
return NULL;
|
|
|
|
b->ioi.ops = &bio_ops;
|
|
b->count = 1;
|
|
b->size = size;
|
|
|
|
return &b->ioi;
|
|
}
|