basekernel/kernel/kobject.c

415 lines
8.9 KiB
C

/*
* Copyright (C) 2016-2019 The University of Notre Dame This software is
* distributed under the GNU General Public License. See the file LICENSE
* for details.
*/
#include "console.h"
#include "kobject.h"
#include "kmalloc.h"
#include "string.h"
#include "device.h"
#include "fs.h"
#include "window.h"
#include "console.h"
#include "pipe.h"
#include "kernel/error.h"
static struct kobject *kobject_create()
{
struct kobject *k = kmalloc(sizeof(*k));
k->refcount = 1;
k->offset = 0;
k->tag = 0;
k->data.file = 0;
return k;
}
struct kobject *kobject_create_file(struct fs_dirent *f)
{
struct kobject *k = kobject_create();
k->type = KOBJECT_FILE;
k->data.file = f;
return k;
}
struct kobject *kobject_create_dir( struct fs_dirent *d )
{
struct kobject *k = kobject_create();
k->type = KOBJECT_DIR;
k->data.dir = d;
return k;
}
struct kobject *kobject_create_device(struct device *d)
{
struct kobject *k = kobject_create();
k->type = KOBJECT_DEVICE;
k->data.device = d;
return k;
}
struct kobject *kobject_create_window(struct window *g)
{
struct kobject *k = kobject_create();
k->type = KOBJECT_WINDOW;
k->data.window = g;
return k;
}
struct kobject *kobject_create_console(struct console *c)
{
struct kobject *k = kobject_create();
k->type = KOBJECT_CONSOLE;
k->data.console = c;
return k;
}
struct kobject *kobject_create_pipe(struct pipe *p)
{
struct kobject *k = kobject_create();
k->type = KOBJECT_PIPE;
k->data.pipe = p;
return k;
}
struct kobject *kobject_addref(struct kobject *k)
{
k->refcount++;
return k;
}
struct kobject * kobject_copy( struct kobject *ksrc )
{
struct kobject *kdst = kobject_create();
kdst->data = ksrc->data;
kdst->type = ksrc->type;
kdst->offset = ksrc->offset;
kdst->refcount = 1;
if(ksrc->tag) {
kdst->tag = strdup(ksrc->tag);
} else {
kdst->tag = 0;
}
switch (ksrc->type) {
case KOBJECT_WINDOW:
window_addref(ksrc->data.window);
break;
case KOBJECT_CONSOLE:
console_addref(ksrc->data.console);
break;
case KOBJECT_FILE:
fs_dirent_addref(ksrc->data.file);
break;
case KOBJECT_DIR:
fs_dirent_addref(ksrc->data.dir);
break;
case KOBJECT_DEVICE:
device_addref(ksrc->data.device);
break;
case KOBJECT_PIPE:
pipe_addref(ksrc->data.pipe);
break;
}
return kdst;
}
struct kobject *kobject_create_window_from_window( struct kobject *k, int x, int y, int width, int height )
{
if(k->type!=KOBJECT_WINDOW) return 0;
struct window *w = window_create(k->data.window,x,y,width,height);
if(w) {
return kobject_create_window(w);
} else {
return 0;
}
}
struct kobject *kobject_create_console_from_window( struct kobject *k )
{
if(k->type!=KOBJECT_WINDOW) return 0;
struct console *c = console_create(k->data.window);
if(!c) return 0;
return kobject_create_console(c);
}
struct kobject * kobject_create_file_from_dir( struct kobject *kobject, const char *name )
{
if(kobject->type==KOBJECT_DIR) {
struct fs_dirent *d = fs_dirent_mkfile(kobject->data.dir,name);
if(d) {
return kobject_create_file(d);
} else {
return 0;
}
} else {
return 0;
// XXX KERROR_NOT_IMPLEMENTED;
}
return 0;
}
struct kobject * kobject_create_dir_from_dir( struct kobject *kobject, const char *name )
{
if(kobject->type==KOBJECT_DIR) {
struct fs_dirent *d = fs_dirent_mkdir(kobject->data.dir,name);
if(d) {
return kobject_create_dir(d);
} else {
return 0;
}
} else {
return 0;
// XXX KERROR_NOT_IMPLEMENTED;
}
return 0;
}
int kobject_read(struct kobject *kobject, void *buffer, int size, kernel_io_flags_t flags )
{
int actual = 0;
switch (kobject->type) {
case KOBJECT_FILE:
actual = fs_dirent_read(kobject->data.file, (char *) buffer, (uint32_t) size, kobject->offset);
break;
case KOBJECT_DIR:
return KERROR_INVALID_REQUEST;
break;
case KOBJECT_DEVICE:
if(flags&KERNEL_IO_NONBLOCK) {
actual = device_read_nonblock(kobject->data.device, buffer, size / device_block_size(kobject->data.device), 0);
} else {
actual = device_read(kobject->data.device, buffer, size / device_block_size(kobject->data.device), 0);
}
break;
case KOBJECT_PIPE:
if(flags&KERNEL_IO_NONBLOCK) {
actual = pipe_read_nonblock(kobject->data.pipe, buffer, size);
} else {
actual = pipe_read(kobject->data.pipe, buffer, size);
}
break;
case KOBJECT_WINDOW:
if(flags&KERNEL_IO_NONBLOCK) {
actual = window_read_events_nonblock(kobject->data.window, buffer, size);
} else {
actual = window_read_events(kobject->data.window, buffer, size);
}
break;
case KOBJECT_CONSOLE:
if(flags&KERNEL_IO_NONBLOCK) {
actual = console_read_nonblock(kobject->data.console,buffer,size);
} else {
actual = console_read(kobject->data.console,buffer,size);
}
break;
default:
actual = 0;
break;
}
if(actual > 0) kobject->offset += actual;
return actual;
}
int kobject_write(struct kobject *kobject, void *buffer, int size, kernel_io_flags_t flags )
{
switch (kobject->type) {
case KOBJECT_WINDOW:
if(flags&KERNEL_IO_POST) {
return window_post_events(kobject->data.window,buffer,size);
} else {
return window_write_graphics(kobject->data.window,buffer,size);
}
break;
case KOBJECT_CONSOLE:
if(flags&KERNEL_IO_POST) {
return console_post(kobject->data.console,buffer,size);
} else {
return console_write(kobject->data.console, buffer, size );
}
break;
case KOBJECT_FILE:{
int actual = fs_dirent_write(kobject->data.file, (char *) buffer, (uint32_t) size, kobject->offset);
if(actual > 0)
kobject->offset += actual;
return actual;
}
case KOBJECT_DEVICE:
return device_write(kobject->data.device, buffer, size / device_block_size(kobject->data.device), 0);
case KOBJECT_PIPE:
if(flags&KERNEL_IO_NONBLOCK) {
return pipe_write_nonblock(kobject->data.pipe, buffer, size);
} else {
return pipe_write(kobject->data.pipe, buffer, size);
}
default:
return 0;
}
return 0;
}
int kobject_list(struct kobject *kobject, void *buffer, int size)
{
if(kobject->type==KOBJECT_DIR) {
return fs_dirent_list(kobject->data.dir,buffer,size);
} else {
return KERROR_NOT_A_DIRECTORY;
}
}
int kobject_lookup( struct kobject *kobject, const char *name, struct kobject **newobj )
{
if(kobject->type==KOBJECT_DIR) {
struct fs_dirent *d;
d = fs_dirent_traverse(kobject->data.dir,name);
if(d) {
if(fs_dirent_isdir(d)) {
*newobj = kobject_create_dir(d);
} else {
*newobj = kobject_create_file(d);
}
return 0;
} else {
return KERROR_NOT_FOUND;
}
} else {
return KERROR_NOT_IMPLEMENTED;
}
return 0;
}
int kobject_remove( struct kobject *kobject, const char *name )
{
if(kobject->type==KOBJECT_DIR) {
return fs_dirent_remove(kobject->data.dir,name);
} else {
return KERROR_NOT_IMPLEMENTED;
}
return 0;
}
int kobject_close(struct kobject *kobject)
{
kobject->refcount--;
if(kobject->refcount==0) {
switch (kobject->type) {
case KOBJECT_WINDOW:
window_delete(kobject->data.window);
break;
case KOBJECT_CONSOLE:
console_delete(kobject->data.console);
break;
case KOBJECT_FILE:
fs_dirent_close(kobject->data.file);
break;
case KOBJECT_DIR:
fs_dirent_close(kobject->data.dir);
break;
case KOBJECT_DEVICE:
device_close(kobject->data.device);
break;
case KOBJECT_PIPE:
pipe_delete(kobject->data.pipe);
break;
default:
break;
}
if (kobject->tag)
kfree(kobject->tag);
kfree(kobject);
return 0;
} else if(kobject->refcount>1 ) {
if(kobject->type==KOBJECT_PIPE) {
pipe_flush(kobject->data.pipe);
}
}
return 0;
}
int kobject_size(struct kobject *kobject, int *dims, int n)
{
switch (kobject->type) {
case KOBJECT_WINDOW:
if(n==2) {
dims[0] = window_width(kobject->data.window);
dims[1] = window_height(kobject->data.window);
return 0;
} else {
return KERROR_INVALID_REQUEST;
}
case KOBJECT_CONSOLE:
if(n==2) {
console_size(kobject->data.console,&dims[0],&dims[1]);
return 0;
} else {
return KERROR_INVALID_REQUEST;
}
case KOBJECT_FILE:
if(n==1) {
dims[0] = fs_dirent_size(kobject->data.file);
return 0;
} else {
return KERROR_INVALID_REQUEST;
}
case KOBJECT_DIR:
if(n==1) {
dims[0] = fs_dirent_size(kobject->data.dir);
return 0;
} else {
return KERROR_INVALID_REQUEST;
}
case KOBJECT_DEVICE:
if(n==2) {
dims[0] = device_nblocks(kobject->data.device);
dims[1] = device_block_size(kobject->data.device);
return 0;
} else {
return KERROR_INVALID_REQUEST;
}
case KOBJECT_PIPE:
if(n==1) {
dims[0] = pipe_size(kobject->data.pipe);
return 0;
} else {
return KERROR_INVALID_REQUEST;
}
}
return KERROR_INVALID_REQUEST;
}
int kobject_get_type(struct kobject *kobject)
{
return kobject->type;
}
int kobject_set_tag(struct kobject *kobject, char *new_tag)
{
if(kobject->tag != 0) {
kfree(kobject->tag);
}
kobject->tag = kmalloc(strlen(new_tag) * sizeof(char));
strcpy(kobject->tag, new_tag);
return 1;
}
int kobject_get_tag(struct kobject *kobject, char *buffer, int buffer_size)
{
if(kobject->tag != 0) {
strcpy(buffer, kobject->tag);
return 1;
}
return 0;
}