diff -Naur -X exclude-files ac_cur/arch/um/drivers/mconsole_kern.c ac/arch/um/drivers/mconsole_kern.c
--- ac_cur/arch/um/drivers/mconsole_kern.c	Sun Jul 15 21:26:31 2001
+++ ac/arch/um/drivers/mconsole_kern.c	Sun Jul 15 22:03:32 2001
@@ -10,11 +10,13 @@
 #include "linux/reboot.h"
 #include "linux/utsname.h"
 #include "linux/ctype.h"
+#include "linux/interrupt.h"
 #include "asm/irq.h"
 #include "user_util.h"
 #include "kern_util.h"
 #include "kern.h"
 #include "mconsole.h"
+#include "mconsole_kern.h"
 
 extern int create_listening_socket(void);
 extern int get_request(int fd, struct mconsole_request *req);
@@ -33,16 +35,45 @@
 	return(unlink_socket());
 }
 
+LIST_HEAD(mc_requests);
+
+void mc_tasklet(unsigned long unused)
+{
+	struct mconsole_entry *req;
+	unsigned long flags;
+	int done;
+
+	do {
+		save_flags(flags);
+		req = list_entry(mc_requests.next, struct mconsole_entry, 
+				 list);
+		list_del(&req->list);
+		done = list_empty(&mc_requests);
+		handle_request(&req->request);
+		kfree(req);
+		restore_flags(flags);
+	} while(!done);
+}
+
+DECLARE_TASKLET(mconsole_tasklet, mc_tasklet, 0);
+
 void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	int fd;
+	struct mconsole_entry *new;
 	struct mconsole_request req;
 
 	fd = (int) dev_id;
 	while (get_request(fd, &req)) {
-		handle_request(&req);
+		new = kmalloc(sizeof(req), GFP_ATOMIC);
+		if(new == NULL)
+			mconsole_reply(&req, "ERR Out of memory");
+		else {
+			new->request = req;
+			list_add(&new->list, &mc_requests);
+		}
 	}
-
+	tasklet_schedule(&mconsole_tasklet);
 	reactivate_fd(fd);
 }
 
@@ -58,72 +89,72 @@
 
 void mconsole_halt(struct mconsole_request *req)
 {
-	static struct tq_struct halt = {
-		routine:	(void (*)(void *))machine_halt,
-	};
-
 	mconsole_reply(req, "OK");
-	schedule_task(&halt);
+	machine_halt();
 }
 
 void mconsole_reboot(struct mconsole_request *req)
 {
-	static struct tq_struct reboot = {
-		routine:	(void (*)(void *))machine_restart,
-	};
-
 	mconsole_reply(req, "OK");
-	schedule_task(&reboot);
+	machine_restart(NULL);
 }
 
-static struct config_command configs[] = {
-	{ "gdb=", config_gdb },
-};
+LIST_HEAD(mconsole_devices);
+
+void mconsole_register_dev(struct mc_device *new)
+{
+	list_add(&new->list, &mconsole_devices);
+}
+
+static struct mc_device *mconsole_find_dev(char *name)
+{
+	struct list_head *ele;
+	struct mc_device *dev;
+
+	list_for_each(ele, &mconsole_devices){
+		dev = list_entry(ele, struct mc_device, list);
+		if(!strncmp(name, dev->name, strlen(dev->name)))
+			return(dev);
+	}
+	return(NULL);
+}
 
 void mconsole_config(struct mconsole_request *req)
 {
-	struct config_command *c;
+	struct mc_device *dev;
 	char *ptr = req->buf, *ok;
-	int i, err;
+	int err;
 
 	ptr += strlen("config");
 	while(isspace(*ptr)) ptr++;
-	for(i=0;i<sizeof(configs)/sizeof(configs[0]);i++){
-		c = &configs[i];
-		if(!strncmp(ptr, c->command, strlen(c->command))){
-			err = c->handler(&ptr[strlen(c->command)]);
-			if(err) ok = "ERR";
-			else ok = "OK";
-			mconsole_reply(req, ok);
-			return;
-		}
+	dev = mconsole_find_dev(ptr);
+	if(dev == NULL){
+		mconsole_reply(req, "ERR Bad configuration option");
+		return;
 	}
-	mconsole_reply(req, "ERR Bad configuration option");	
+	err = (*dev->config)(&ptr[strlen(dev->name)]);
+	if(err) ok = "ERR";
+	else ok = "OK";
+	mconsole_reply(req, ok);
 }
 
-static struct remove_command removes[] = {
-	{ "gdb", remove_gdb },
-};
-
 void mconsole_remove(struct mconsole_request *req)
 {
-	struct remove_command *r;
+	struct mc_device *dev;	
 	char *ptr = req->buf, *ok;
-	int i, err;
+	int err;
 
 	ptr += strlen("remove");
 	while(isspace(*ptr)) ptr++;
-	for(i=0;i<sizeof(removes)/sizeof(removes[0]);i++){
-		r = &removes[i];
-		if(!strncmp(ptr, r->command, strlen(r->command))){
-			err = r->handler();
-			if(err) ok = "ERR";
-			else ok = "OK";
-			mconsole_reply(req, ok);
-			return;
-		}
+	dev = mconsole_find_dev(ptr);
+	if(dev == NULL){
+		mconsole_reply(req, "ERR Bad remove option");
+		return;
 	}
-	mconsole_reply(req, "ERR Bad remove option");	
+	err = (*dev->remove)(&ptr[strlen(dev->name)]);
+	if(err) ok = "ERR";
+	else ok = "OK";
+	mconsole_reply(req, ok);
 }
 
 int mconsole_init(void)
diff -Naur -X exclude-files ac_cur/arch/um/drivers/ubd.c ac/arch/um/drivers/ubd.c
--- ac_cur/arch/um/drivers/ubd.c	Sun Jul 15 21:30:40 2001
+++ ac/arch/um/drivers/ubd.c	Sun Jul 15 22:03:32 2001
@@ -13,12 +13,15 @@
 #include "linux/devfs_fs_kernel.h"
 #include "linux/cdrom.h"
 #include "linux/proc_fs.h"
+#include "linux/ctype.h"
+#include "linux/capability.h"
 #include "asm/segment.h"
 #include "asm/uaccess.h"
 #include "asm/irq.h"
 #include "user_util.h"
 #include "kern_util.h"
 #include "kern.h"
+#include "mconsole_kern.h"
 
 static int ubd_open(struct inode * inode, struct file * filp);
 static int ubd_release(struct inode * inode, struct file * file);
@@ -76,7 +79,19 @@
 #define OPEN_FLAGS O_RDWR
 #endif
 
-struct {
+#define DEFAULT_UBD { \
+	file: 		NULL, \
+	is_dir:		0, \
+	count:		0, \
+	fd:		-1, \
+	size:		-1, \
+	boot_openflags:	OPEN_FLAGS, \
+	openflags:	OPEN_FLAGS, \
+	real:		NULL, \
+	fake:		NULL, \
+}
+
+struct ubd {
 	char *file;
 	int is_dir;
 	int count;
@@ -84,9 +99,22 @@
 	__u64 size;
 	int boot_openflags;
 	int openflags;
-} ubd_dev[MAX_DEV] = { { "root_fs", 0, 0, -1, 0, OPEN_FLAGS, OPEN_FLAGS }, 
-		       [ 1 ... MAX_DEV - 1 ] = 
-		       { NULL, 0, 0, -1, -1, OPEN_FLAGS, OPEN_FLAGS } };
+	devfs_handle_t real;
+	devfs_handle_t fake;
+} ubd_dev[MAX_DEV] = { 
+{ 
+	file: 		"root_fs",
+	is_dir:		0, 
+	count:		0, 
+	fd:		-1, 
+	size:		0, 
+	boot_openflags:	OPEN_FLAGS, 
+	openflags:	OPEN_FLAGS,
+	real:		NULL,
+	fake:		NULL,
+}, 
+[ 1 ... MAX_DEV - 1 ] = DEFAULT_UBD
+};
 
 static struct hd_driveid ubd_id = {
         cyls:		0,
@@ -148,11 +176,12 @@
 
 __setup("fake_ide", fake_ide_setup);
 
-static int ubd_setup(char *str)
+static int ubd_setup_common(char *str, int *index_out, int copy_name)
 {
 	int n;
 	int sync, perm = O_RDWR;
 
+	if(index_out) *index_out = -1;
 	n = *str++;
 	if(n == '='){
 		char *end;
@@ -181,6 +210,7 @@
 		printk("ubd_setup : index out of range\n");
 		return(1);
 	}
+	if(index_out) *index_out = n;
 	sync = ubd_dev[n].boot_openflags & O_SYNC;
 	if (*str == 'r') {
 		perm = O_RDONLY;
@@ -194,11 +224,21 @@
 		printk("ubd_setup : Expected '='\n");
 		return(1);
 	}
-	ubd_dev[n].file = str;
+	if(copy_name){
+		ubd_dev[n].file = kmalloc(strlen(str) + 1, GFP_ATOMIC);
+		if(ubd_dev[n].file == NULL) return(0);
+		strcpy(ubd_dev[n].file, str);
+	}
+	else ubd_dev[n].file = str;
 	ubd_dev[n].boot_openflags = perm | sync;
 	return(1);
 }
 
+static int ubd_setup(char *str)
+{
+	return(ubd_setup_common(str, NULL, 0));
+}
+
 __setup("ubd", ubd_setup);
 
 static int fakehd(char *str)
@@ -270,15 +310,80 @@
 
 int sync = 0;
 
+devfs_handle_t ubd_dir_handle;
+
+static int ubd_add(int n)
+{
+	char name[sizeof("nnnnnn\0")], dev_name[sizeof("ubd0x")];
+
+	if(ubd_dev[n].file == NULL) return(-1);
+	sprintf(name, "%d", n);
+	ubd_dev[n].real = devfs_register (ubd_dir_handle, name, 
+					  DEVFS_FL_DEFAULT, MAJOR_NR, n,
+					  S_IFBLK | S_IRUSR | S_IWUSR | 
+					  S_IRGRP |S_IWGRP,
+					  &ubd_blops, NULL);
+	if(fake_major != 0){
+		ubd_dev[n].fake = devfs_register (ubd_dir_handle, name, 
+						  DEVFS_FL_DEFAULT, fake_major,
+						  n, S_IFBLK | S_IRUSR | 
+						  S_IWUSR | S_IRGRP | S_IWGRP,
+						  &ubd_blops, NULL);
+	}
+	if(!strcmp(ubd_gendisk.major_name, "ubd")){
+		sprintf(dev_name, "%s%d", ubd_gendisk.major_name, n);
+	}
+	else sprintf(dev_name, "%s%c", ubd_gendisk.major_name, 
+		     n + 'a');
+	make_ide_entries(dev_name);
+	return(0);
+}
+
+static int ubd_config(char *str)
+{
+	int n, err;
+
+	err = ubd_setup_common(str, &n, 1);
+	if(err != 1) return(-1);
+	if(n != -1) ubd_add(n);
+	return(0);
+}
+
+static int ubd_remove(char *str)
+{
+	int n;
+
+	if(!isdigit(*str)) return(-1);
+	n = *str - '0';
+	if(ubd_dev[n].file == NULL) return(0);
+	if(ubd_dev[n].count > 0) return(-1);
+	if(ubd_dev[n].real != NULL) devfs_unregister(ubd_dev[n].real);
+	if(ubd_dev[n].fake != NULL) devfs_unregister(ubd_dev[n].fake);
+	ubd_dev[n] = ((struct ubd) DEFAULT_UBD);
+	return(0);
+}
+
+static struct mc_device ubd_mc = {
+	name:		"ubd",
+	config:		ubd_config,
+	remove:		ubd_remove,
+};
+
+int ubd_mc_init(void)
+{
+	mconsole_register_dev(&ubd_mc);
+	return(0);
+}
+
+__initcall(ubd_mc_init);
+
 int ubd_init(void)
 {
 	unsigned long stack;
         int i, err;
-	char name[6], dev_name[sizeof("ubd0x")];
-	devfs_handle_t devfs_handle;
 	request_queue_t *q;
 
-	devfs_handle = devfs_mk_dir (NULL, "ubd", NULL);
+	ubd_dir_handle = devfs_mk_dir (NULL, "ubd", NULL);
 	if (devfs_register_blkdev(MAJOR_NR, "ubd", &ubd_blops)) {
 		printk("ubd: unable to get major %d\n", MAJOR_NR);
 		return -1;
@@ -304,28 +409,7 @@
 		fake_gendisk.next = gendisk_head;
 		gendisk_head = &fake_gendisk;	
 	}
-	for(i=0;i<MAX_DEV;i++){
-  	        if(ubd_dev[i].file == NULL) continue;
-		sprintf(name, "%d", i);
-		devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, 
-				MAJOR_NR, i,
-				S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP,
-				&ubd_blops, NULL);
-		if(fake_major != 0){
-			devfs_register (devfs_handle, name, 
-					DEVFS_FL_DEFAULT, fake_major, i,
-					S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |
-					S_IWGRP, &ubd_blops, NULL);
-		}
-		if(!strcmp(ubd_gendisk.major_name, "ubd")){
-			sprintf(dev_name, "%s%d", ubd_gendisk.major_name, i);
-		}
-		else {
-			sprintf(dev_name, "%s%c", ubd_gendisk.major_name, 
-				i + 'a');
-		}
-		make_ide_entries(dev_name);
-	}
+	for(i=0;i<MAX_DEV;i++) ubd_add(i);
 	if(sync){
 		printk("ubd : Synchronous mode\n");
 		return(0);
diff -Naur -X exclude-files ac_cur/arch/um/include/mconsole_kern.h ac/arch/um/include/mconsole_kern.h
--- ac_cur/arch/um/include/mconsole_kern.h	Wed Dec 31 19:00:00 1969
+++ ac/arch/um/include/mconsole_kern.h	Sun Jul 15 22:03:32 2001
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MCONSOLE_KERN_H__
+#define __MCONSOLE_KERN_H__
+
+#include "linux/list.h"
+#include "mconsole.h"
+
+struct mconsole_entry {
+	struct list_head list;
+	struct mconsole_request request;
+};
+
+struct mc_device {
+	struct list_head list;
+	char *name;
+	int (*config)(char *);
+	int (*remove)(char *);
+};
+
+extern void mconsole_register_dev(struct mc_device *new);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Naur -X exclude-files ac_cur/arch/um/kernel/trap_kern.c ac/arch/um/kernel/trap_kern.c
--- ac_cur/arch/um/kernel/trap_kern.c	Sun Jul 15 21:26:31 2001
+++ ac/arch/um/kernel/trap_kern.c	Sun Jul 15 22:03:32 2001
@@ -18,6 +18,7 @@
 #include "kern.h"
 #include "chan.h"
 #include "debug.h"
+#include "mconsole_kern.h"
 
 extern int nsyscalls;
 
@@ -218,10 +219,11 @@
 	init_proxy(debugger_pid, 0, 0);
 }
 
-int config_gdb(char *str)
+int gdb_config(char *str)
 {
 	struct gdb_data data;
 
+	if(*str++ != '=') return(-1);
 	data.str = str;
 	tracing_cb(config_gdb_cb, &data);
 	return(data.err);
@@ -232,11 +234,25 @@
 	exit_debugger_cb(NULL);
 }
 
-int remove_gdb(void)
+int gdb_remove(char *unused)
 {
 	tracing_cb(remove_gdb_cb, NULL);
 	return(0);
 }
+
+static struct mc_device gdb_mc = {
+	name:		"gdb",
+	config:		gdb_config,
+	remove:		gdb_remove,
+};
+
+int gdb_mc_init(void)
+{
+	mconsole_register_dev(&gdb_mc);
+	return(0);
+}
+
+__initcall(gdb_mc_init);
 
 void signal_usr1(int sig)
 {