/* * ------------------------ RTEMS Shared Irq Handler Mngt Routines ---------------- */ int BSP_install_rtems_shared_irq_handler (const rtems_irq_connect_data* irq) { rtems_interrupt_level level; rtems_irq_connect_data* vchain; printk(" BSP_install_rtems_shared_irq_handler %d\n", irq->name ); if (!isValidInterrupt(irq->name)) { printk("Invalid interrupt vector %d\n",irq->name); return 0; } rtems_interrupt_disable(level); if ( (int)rtems_hdl_tbl[irq->name].next_handler == -1 ) { rtems_interrupt_enable(level); printk("IRQ vector %d already connected to an unshared handler\n",irq->name); return 0; } vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data)); /* save off topmost handler */ vchain[0]= rtems_hdl_tbl[irq->name]; /* * store the data provided by user */ rtems_hdl_tbl[irq->name] = *irq; /* link chain to new topmost handler */ rtems_hdl_tbl[irq->name].next_handler = (void *)vchain; /* * XXX FIX ME */ if (is_pci_irq(irq->name)) { } if (is_processor_irq(irq->name)) { /* * Enable exception at processor level */ } /* * Enable interrupt on device */ if (irq->on) irq->on(irq); rtems_interrupt_enable(level); return 1; }
int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) { rtems_interrupt_level level; if (!isValidInterrupt(irq->name)) { return 0; } rtems_interrupt_disable(level); *irq = rtems_hdl_tbl[irq->name]; rtems_interrupt_enable(level); return 1; }
/* * ------------------------ RTEMS Shared Irq Handler Mngt Routines ---------------- */ int BSP_install_rtems_shared_irq_handler (const rtems_irq_connect_data* irq) { rtems_interrupt_level level; rtems_irq_connect_data* vchain; if (!isValidInterrupt(irq->name)) { printk("Invalid interrupt vector %d\n",irq->name); return 0; } /* pre-allocate memory outside of critical section */ vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data)); rtems_interrupt_disable(level); if ( (int)rtems_hdl_tbl[irq->name].next_handler == -1 ) { rtems_interrupt_enable(level); printk("IRQ vector %d already connected to an unshared handler\n",irq->name); free(vchain); return 0; } /* save off topmost handler */ vchain[0]= rtems_hdl_tbl[irq->name]; /* * store the data provided by user */ rtems_hdl_tbl[irq->name] = *irq; /* link chain to new topmost handler */ rtems_hdl_tbl[irq->name].next_handler = (void *)vchain; /* * enable_irq_at_pic is supposed to ignore * requests to disable interrupts outside * of the range handled by the PIC */ BSP_enable_irq_at_pic(irq->name); /* * Enable interrupt on device */ if (irq->on) irq->on(irq); rtems_interrupt_enable(level); return 1; }
int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) { rtems_interrupt_level level; if (!isValidInterrupt(irq->name)) { printk("Invalid interrupt vector %d\n",irq->name); return 0; } /* * Check if default handler is actually connected. If not issue an error. * You must first get the current handler via i386_get_current_idt_entry * and then disconnect it using i386_delete_idt_entry. * RATIONALE : to always have the same transition by forcing the user * to get the previous handler before accepting to disconnect. */ rtems_interrupt_disable(level); if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) { rtems_interrupt_enable(level); printk("IRQ vector %d already connected\n",irq->name); return 0; } /* * store the data provided by user */ rtems_hdl_tbl[irq->name] = *irq; rtems_hdl_tbl[irq->name].next_handler = (void *)-1; /* * enable_irq_at_pic is supposed to ignore * requests to disable interrupts outside * of the range handled by the PIC */ BSP_enable_irq_at_pic(irq->name); /* * Enable interrupt on device */ if (irq->on) irq->on(irq); rtems_interrupt_enable(level); return 1; }
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) { rtems_irq_connect_data *pchain= NULL, *vchain = NULL; rtems_interrupt_level level; if (!isValidInterrupt(irq->name)) { return 0; } /* * Check if default handler is actually connected. If not issue an error. * You must first get the current handler via i386_get_current_idt_entry * and then disconnect it using i386_delete_idt_entry. * RATIONALE : to always have the same transition by forcing the user * to get the previous handler before accepting to disconnect. */ rtems_interrupt_disable(level); if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { rtems_interrupt_enable(level); return 0; } if( (int)rtems_hdl_tbl[irq->name].next_handler != -1 ) { int found = 0; for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]); (vchain->hdl != default_rtems_entry.hdl); (pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) ) { if( vchain->hdl == irq->hdl ) { found= -1; break; } } if( !found ) { rtems_interrupt_enable(level); return 0; } } else { if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { rtems_interrupt_enable(level); return 0; } } /* * Disable interrupt on device */ if (irq->off) irq->off(irq); /* * restore the default irq value */ if( !vchain ) { /* single handler vector... */ rtems_hdl_tbl[irq->name] = default_rtems_entry; } else { if( pchain ) { /* non-first handler being removed */ pchain->next_handler = vchain->next_handler; } else { /* first handler isn't malloc'ed, so just overwrite it. Since the contents of vchain are being struct copied, vchain itself goes away */ vchain = vchain->next_handler; rtems_hdl_tbl[irq->name]= *vchain; } } /* Only disable at PIC if we removed the last handler */ if ( rtems_hdl_tbl[irq->name].hdl == default_rtems_entry.hdl ) { /* * disable_irq_at_pic is supposed to ignore * requests to disable interrupts outside * of the range handled by the PIC; */ BSP_disable_irq_at_pic(irq->name); } rtems_interrupt_enable(level); free(vchain); return 1; }