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;
 | |
| }
 |