From: Ben Gras Date: Thu, 12 May 2005 16:06:37 +0000 (+0000) Subject: . added rm_irq_handler which un-links an irq handler from the linked X-Git-Tag: v3.1.0~851 X-Git-Url: http://zhaoyanbai.com/repos/man.isc-hmac-fixup.html?a=commitdiff_plain;h=d0c3e8f81844e2a005618dc658504fd84e622ca9;p=minix.git . added rm_irq_handler which un-links an irq handler from the linked list of handlers, callable by irqctl system call . workaround for hanging keyboard bug after shutdown.. if key is pressed during or after shutdown procedure, keyboard stops working. It looks like irq 1 gets stuck high if no keyboard reading is done (e.g. because the irq is masked or tty driver has exited). Workaround is to leave irqs enabled until the last second, and call shutdown() immediately after the last driver has stopped (tty task). This way the chance of an unserviced interrupt occuring is negligible. --- diff --git a/kernel/i8259.c b/kernel/i8259.c index 51bada0ae..9a82d55db 100755 --- a/kernel/i8259.c +++ b/kernel/i8259.c @@ -1,5 +1,6 @@ /* This file contains routines for initializing the 8259 interrupt controller: * put_irq_handler: register an interrupt handler + * rm_irq_handler: deregister an interrupt handler * intr_handle: handle a hardware interrupt * intr_init: initialize the interrupt controller(s) */ @@ -94,7 +95,7 @@ irq_handler_t handler; int id; irq_hook_t **line; - if ((unsigned) irq >= NR_IRQ_VECTORS) + if (irq < 0 || irq >= NR_IRQ_VECTORS) panic("invalid call to put_irq_handler", irq); line = &irq_handlers[irq]; @@ -115,6 +116,34 @@ irq_handler_t handler; irq_use |= 1 << irq; } +/*=========================================================================* + * rm_irq_handler * + *=========================================================================*/ +PUBLIC int rm_irq_handler(irq, id) +int irq; +int id; +{ +/* Unregister an interrupt handler. */ + irq_hook_t **line; + + if (irq < 0 || irq >= NR_IRQ_VECTORS) { + return EINVAL; + } + + line = &irq_handlers[irq]; + while (*line != NULL) { + if((*line)->id == id) { + (*line) = (*line)->next; + if(!irq_handlers[irq]) + irq_use &= ~(1 << irq); + return OK; + } + line = &(*line)->next; + } + + return ENOENT; +} + /*==========================================================================* * intr_handle * *==========================================================================*/ diff --git a/kernel/main.c b/kernel/main.c index 08ea09a35..1b956b3d0 100755 --- a/kernel/main.c +++ b/kernel/main.c @@ -29,7 +29,7 @@ /* Prototype declarations for PRIVATE functions. */ FORWARD _PROTOTYPE( void announce, (void)); -FORWARD _PROTOTYPE( void shutdown, (struct timer *tp)); +FORWARD _PROTOTYPE( void shutdown, (int how)); #define STOP_TICKS (5*HZ) /* time allowed to stop */ @@ -243,7 +243,7 @@ int how; /* 0 = halt, 1 = reboot, 2 = panic!, ... */ tmr_arg(&shutdown_timer)->ta_int = how; /* pass how in timer */ if (skip_stop_sequence) { /* set in exception() */ kprintf("\nAn exception occured; skipping stop sequence.\n", NO_ARG); - shutdown(&shutdown_timer); /* TTY isn't scheduled */ + shutdown(how); /* TTY isn't scheduled */ } else { kprintf("\nNotifying system services about MINIX shutdown.\n", NO_ARG); kprintf("Known bug: hitting a key before done will hang the monitor.\n", NO_ARG); @@ -268,7 +268,7 @@ timer_t *tp; static struct proc *p = NIL_PROC; /* next process to stop */ static char *types[] = {"task","system","driver","server","user"}; - /* See if the last process' shutdown was successfull. Else, force exit. */ + /* See if the last process' shutdown was successful. Else, force exit. */ if (p != NIL_PROC) { kprintf("[%s]\n", isalivep(p) ? karg("FAILED") : karg("OK")); if (isalivep(p)) @@ -285,6 +285,7 @@ timer_t *tp; if (p == NIL_PROC) p = BEG_PROC_ADDR; while (TRUE) { if (isalivep(p) && p->p_type == level) { /* found a process */ + int w; kprintf("- Stopping %s ", karg(p->p_name)); kprintf("%s ... ", karg(types[p->p_type])); shutdown_process = p; /* directly continue if exited */ @@ -297,8 +298,9 @@ timer_t *tp; p = BEG_PROC_ADDR; level = level - 1; if (level == P_TASK) { /* done; tasks must remain alive */ - set_timer(tp, get_uptime()+HZ, shutdown); /* shutdown MINIX */ - return; /* user can inspect output */ + shutdown(tmr_arg(tp)->ta_int); + /* no return */ + return; } } } @@ -307,15 +309,13 @@ timer_t *tp; /*==========================================================================* * shutdown * *==========================================================================*/ -PRIVATE void shutdown(tp) -timer_t *tp; +PRIVATE void shutdown(int how) { /* This function is called from prepare_shutdown or stop_sequence to bring * down MINIX. How to shutdown is in the argument: RBT_REBOOT, RBT_HALT, * RBT_RESET. */ static u16_t magic = STOP_MEM_CHECK; - int how = tmr_arg(tp)->ta_int; /* Now mask all interrupts, including the clock, and stop the clock. */ outb(INT_CTLMASK, ~0); diff --git a/kernel/proto.h b/kernel/proto.h index ceb6b6a20..a36489720 100755 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -37,7 +37,7 @@ _PROTOTYPE( void kprintf, (const char *fmt, karg_t arg) ); /* main.c */ _PROTOTYPE( void main, (void) ); -_PROTOTYPE( void prepare_shutdown, (int how) ); +_PROTOTYPE( void prepare_shutdown, (int) ); _PROTOTYPE( void stop_sequence, (struct timer *tp) ); /* misc.c */ @@ -83,6 +83,7 @@ _PROTOTYPE( void intr_init, (int mine) ); _PROTOTYPE( void intr_handle, (irq_hook_t *hook) ); _PROTOTYPE( void put_irq_handler, (irq_hook_t *hook, int irq, irq_handler_t handler) ); +_PROTOTYPE( int rm_irq_handler, (int irq, int id) ); /* klib*.s */ _PROTOTYPE( void int86, (void) ); _PROTOTYPE( void cp_mess, (int src,phys_clicks src_clicks,vir_bytes src_offset, diff --git a/kernel/system.c b/kernel/system.c index 58b293b1d..6a43bbf26 100755 --- a/kernel/system.c +++ b/kernel/system.c @@ -236,7 +236,7 @@ int proc_nr; /* slot of process to clean up */ PUBLIC int generic_handler(hook) irq_hook_t *hook; { -/* This function handles hardware interrupt in a simpel and generic way. All +/* This function handles hardware interrupt in a simple and generic way. All * interrupts are transformed into messages to a driver. The IRQ line will be * reenabled if the policy says so. */ diff --git a/kernel/system/irqctl.c b/kernel/system/irqctl.c index 81261363b..3cf2edb14 100644 --- a/kernel/system/irqctl.c +++ b/kernel/system/irqctl.c @@ -24,15 +24,18 @@ register message *m_ptr; /* pointer to request message */ int irq_vec; int irq_hook_id; int proc_nr; + int r = OK; irq_hook_t *hook_ptr; + irq_hook_id = (unsigned) m_ptr->IRQ_HOOK_ID; + irq_vec = (unsigned) m_ptr->IRQ_VECTOR; + /* See what is requested and take needed actions. */ switch(m_ptr->IRQ_REQUEST) { /* Enable or disable IRQs. This is straightforward. */ case IRQ_ENABLE: case IRQ_DISABLE: - irq_hook_id = (unsigned) m_ptr->IRQ_HOOK_ID; if (irq_hook_id >= NR_IRQ_HOOKS) return(EINVAL); if (irq_hooks[irq_hook_id].proc_nr != m_ptr->m_source) return(EPERM); if (m_ptr->IRQ_REQUEST == IRQ_ENABLE) @@ -48,8 +51,7 @@ register message *m_ptr; /* pointer to request message */ case IRQ_SETPOLICY: /* Check if IRQ line is acceptable. */ - irq_vec = (unsigned) m_ptr->IRQ_VECTOR; - if ((unsigned) irq_vec >= NR_IRQ_VECTORS) { + if (irq_vec < 0 || irq_vec >= NR_IRQ_VECTORS) { kprintf("ST: irq line %d is not acceptable!\n", irq_vec); return(EINVAL); } @@ -73,9 +75,22 @@ register message *m_ptr; /* pointer to request message */ m_ptr->IRQ_HOOK_ID = irq_hook_id; break; + case IRQ_RMPOLICY: + if(irq_hook_id < 0 || irq_hook_id >= NR_IRQ_HOOKS || + irq_hooks[irq_hook_id].proc_nr == NONE) { + r = EINVAL; + } else { + if(m_ptr->m_source != irq_hooks[irq_hook_id].proc_nr) { + r = EPERM; + } else { + r = rm_irq_handler(irq_vec, irq_hooks[irq_hook_id].id); + } + } + break; + default: - return(EINVAL); /* invalid IRQ_REQUEST */ + r = EINVAL; /* invalid IRQ_REQUEST */ } - return(OK); + return(r); }