diff --git a/kernel/kobject.c b/kernel/kobject.c new file mode 100644 index 0000000..255cad7 --- /dev/null +++ b/kernel/kobject.c @@ -0,0 +1,414 @@ +/* + * 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; +}