00001 /* The kernel call implemented in this file: 00002 * m_type: SYS_IRQCTL 00003 * 00004 * The parameters for this kernel call are: 00005 * m5_c1: IRQ_REQUEST (control operation to perform) 00006 * m5_c2: IRQ_VECTOR (irq line that must be controlled) 00007 * m5_i1: IRQ_POLICY (irq policy allows reenabling interrupts) 00008 * m5_l3: IRQ_HOOK_ID (provides index to be returned on interrupt) 00009 * ,, ,, (returns index of irq hook assigned at kernel) 00010 */ 00011 00012 #include "../system.h" 00013 00014 #include <minix/endpoint.h> 00015 00016 #if USE_IRQCTL 00017 00018 FORWARD _PROTOTYPE(int generic_handler, (irq_hook_t *hook)); 00019 00020 /*===========================================================================* 00021 * do_irqctl * 00022 *===========================================================================*/ 00023 PUBLIC int do_irqctl(m_ptr) 00024 register message *m_ptr; /* pointer to request message */ 00025 { 00026 /* Dismember the request message. */ 00027 int irq_vec; 00028 int irq_hook_id; 00029 int notify_id; 00030 int r = OK; 00031 int i; 00032 irq_hook_t *hook_ptr; 00033 struct proc *rp; 00034 struct priv *privp; 00035 00036 /* Hook identifiers start at 1 and end at NR_IRQ_HOOKS. */ 00037 irq_hook_id = (unsigned) m_ptr->IRQ_HOOK_ID - 1; 00038 irq_vec = (unsigned) m_ptr->IRQ_VECTOR; 00039 00040 /* See what is requested and take needed actions. */ 00041 switch(m_ptr->IRQ_REQUEST) { 00042 00043 /* Enable or disable IRQs. This is straightforward. */ 00044 case IRQ_ENABLE: 00045 case IRQ_DISABLE: 00046 if (irq_hook_id >= NR_IRQ_HOOKS || irq_hook_id < 0 || 00047 irq_hooks[irq_hook_id].proc_nr_e == NONE) return(EINVAL); 00048 if (irq_hooks[irq_hook_id].proc_nr_e != m_ptr->m_source) return(EPERM); 00049 if (m_ptr->IRQ_REQUEST == IRQ_ENABLE) 00050 enable_irq(&irq_hooks[irq_hook_id]); 00051 else 00052 disable_irq(&irq_hooks[irq_hook_id]); 00053 break; 00054 00055 /* Control IRQ policies. Set a policy and needed details in the IRQ table. 00056 * This policy is used by a generic function to handle hardware interrupts. 00057 */ 00058 case IRQ_SETPOLICY: 00059 00060 /* Check if IRQ line is acceptable. */ 00061 if (irq_vec < 0 || irq_vec >= NR_IRQ_VECTORS) return(EINVAL); 00062 00063 rp= proc_addr(who_p); 00064 privp= priv(rp); 00065 if (!privp) 00066 { 00067 kprintf("no priv structure!\n"); 00068 return EPERM; 00069 } 00070 if (privp->s_flags & CHECK_IRQ) 00071 { 00072 for (i= 0; i<privp->s_nr_irq; i++) 00073 { 00074 if (irq_vec == privp->s_irq_tab[i]) 00075 break; 00076 } 00077 if (i >= privp->s_nr_irq) 00078 { 00079 kprintf( 00080 "do_irqctl: IRQ check failed for proc %d, IRQ %d\n", 00081 m_ptr->m_source, irq_vec); 00082 return EPERM; 00083 } 00084 } 00085 00086 /* Find a free IRQ hook for this mapping. */ 00087 hook_ptr = NULL; 00088 for (irq_hook_id=0; irq_hook_id<NR_IRQ_HOOKS; irq_hook_id++) { 00089 if (irq_hooks[irq_hook_id].proc_nr_e == NONE) { 00090 hook_ptr = &irq_hooks[irq_hook_id]; /* free hook */ 00091 break; 00092 } 00093 } 00094 if (hook_ptr == NULL) return(ENOSPC); 00095 00096 /* When setting a policy, the caller must provide an identifier that 00097 * is returned on the notification message if a interrupt occurs. 00098 */ 00099 notify_id = (unsigned) m_ptr->IRQ_HOOK_ID; 00100 if (notify_id > CHAR_BIT * sizeof(irq_id_t) - 1) return(EINVAL); 00101 00102 /* Install the handler. */ 00103 hook_ptr->proc_nr_e = m_ptr->m_source; /* process to notify */ 00104 hook_ptr->notify_id = notify_id; /* identifier to pass */ 00105 hook_ptr->policy = m_ptr->IRQ_POLICY; /* policy for interrupts */ 00106 put_irq_handler(hook_ptr, irq_vec, generic_handler); 00107 00108 /* Return index of the IRQ hook in use. */ 00109 m_ptr->IRQ_HOOK_ID = irq_hook_id + 1; 00110 break; 00111 00112 case IRQ_RMPOLICY: 00113 if (irq_hook_id < 0 || irq_hook_id >= NR_IRQ_HOOKS || 00114 irq_hooks[irq_hook_id].proc_nr_e == NONE) { 00115 return(EINVAL); 00116 } else if (m_ptr->m_source != irq_hooks[irq_hook_id].proc_nr_e) { 00117 return(EPERM); 00118 } 00119 /* Remove the handler and return. */ 00120 rm_irq_handler(&irq_hooks[irq_hook_id]); 00121 break; 00122 00123 default: 00124 r = EINVAL; /* invalid IRQ_REQUEST */ 00125 } 00126 return(r); 00127 } 00128 00129 /*===========================================================================* 00130 * generic_handler * 00131 *===========================================================================*/ 00132 PRIVATE int generic_handler(hook) 00133 irq_hook_t *hook; 00134 { 00135 /* This function handles hardware interrupt in a simple and generic way. All 00136 * interrupts are transformed into messages to a driver. The IRQ line will be 00137 * reenabled if the policy says so. 00138 */ 00139 int proc; 00140 00141 /* As a side-effect, the interrupt handler gathers random information by 00142 * timestamping the interrupt events. This is used for /dev/random. 00143 */ 00144 get_randomness(hook->irq); 00145 00146 /* Check if the handler is still alive. If not, forget about the 00147 * interrupt. This should never happen, as processes that die 00148 * automatically get their interrupt hooks unhooked. 00149 */ 00150 if(!isokendpt(hook->proc_nr_e, &proc)) { 00151 hook->proc_nr_e = NONE; 00152 return 0; 00153 } 00154 00155 /* Add a bit for this interrupt to the process' pending interrupts. When 00156 * sending the notification message, this bit map will be magically set 00157 * as an argument. 00158 */ 00159 priv(proc_addr(proc))->s_int_pending |= (1 << hook->notify_id); 00160 00161 /* Build notification message and return. */ 00162 lock_notify(HARDWARE, hook->proc_nr_e); 00163 return(hook->policy & IRQ_REENABLE); 00164 } 00165 00166 #endif /* USE_IRQCTL */ 00167
1.4.6