415 lines
8.9 KiB
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;
|
||
|
}
|