do_irqctl.c

Go to the documentation of this file.
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 

Generated on Fri Apr 14 22:57:24 2006 for minix by  doxygen 1.4.6