#include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_AR9) || defined(CONFIG_VR9) #include #endif /*--- #if defined(CONFIG_AR9) || defined(CONFIG_VR9) ---*/ #include "debug.h" #include "host.h" #include "ca.h" /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined(USE_TASKLETS) struct tasklet_struct scheduler_tasklet; struct tasklet_struct *p_scheduler_tasklet = NULL; #endif /*--- #if defined(USE_TASKLETS) ---*/ #if defined(USE_WORKQUEUES) struct workqueue_struct *p_scheduler_workqueue = NULL; struct work_struct scheduler_work; #endif /*--- #if defined(USE_WORKQUEUES) ---*/ void (*delic_tasklet_func)(unsigned long ); void (*delic_enable_irq)( void ); void (*delic_disable_irq)( void ); struct tasklet_struct delic_tasklet; struct tasklet_struct *p_delic_tasklet = NULL; static atomic_t capi_oslib_scheduler_enabled; static atomic_t capi_oslib_crit_level; static struct timer_list capi_oslib_scheduler_timer; /*--------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------*/ void capi_oslib_scheduler_timer_stop(void) { del_timer(&capi_oslib_scheduler_timer); } /*--------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------*/ void capi_oslib_scheduler_timer_start(void) { capi_oslib_scheduler_timer.data = 0; capi_oslib_scheduler_timer.expires = jiffies + (HZ / 100); /*--- 10 ms ---*/ if (timer_pending(&capi_oslib_scheduler_timer)) { mod_timer(&capi_oslib_scheduler_timer, capi_oslib_scheduler_timer.expires); } else { add_timer(&capi_oslib_scheduler_timer); } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void capi_oslib_trigger_scheduler(void) { if (atomic_read (&capi_oslib_scheduler_enabled)) { #if defined(USE_TASKLETS) if(p_scheduler_tasklet) tasklet_schedule(p_scheduler_tasklet); #endif /*--- #if defined(USE_TASKLETS) ---*/ #if defined(USE_WORKQUEUES) if(p_scheduler_workqueue) queue_work(p_scheduler_workqueue, &scheduler_work); #endif /*--- #if defined(USE_WORKQUEUES) ---*/ } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void os_trigger_scheduler(void) { /*--- DEB_TRACE("os_trigger_scheduler\n"); ---*/ capi_oslib_trigger_scheduler(); } EXPORT_SYMBOL(os_trigger_scheduler); /*--------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------*/ static void capi_oslib_scheduler_timer_handler(unsigned long nr __attribute__((unused))) { capi_oslib_scheduler_timer_stop(); capi_oslib_scheduler_timer_start(); capi_oslib_trigger_scheduler(); } /*--------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------*/ void capi_oslib_scheduler_timer_init(void) { DEB_INFO("capi_oslib_scheduler_timer_init\n"); init_timer(&capi_oslib_scheduler_timer); capi_oslib_scheduler_timer.expires = 0; capi_oslib_scheduler_timer.data = 0; capi_oslib_scheduler_timer.function = capi_oslib_scheduler_timer_handler; capi_oslib_scheduler_timer_start(); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void capi_oslib_scheduler (unsigned long data); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void capi_oslib_delic_tasklet_init(void (*tasklet_func) (unsigned long ), unsigned int enable) { if(tasklet_func) { if(enable) { tasklet_init(&delic_tasklet, tasklet_func, 0); p_delic_tasklet = &delic_tasklet; return; } if(p_delic_tasklet) { p_delic_tasklet = NULL; tasklet_kill(&delic_tasklet); } } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void capi_oslib_scheduler_tasklet_init(void (*scheduler_tasklet_func) (unsigned long ), unsigned int enable) { if(scheduler_tasklet_func) { if(enable) { #if defined(USE_TASKLETS) tasklet_init(&scheduler_tasklet, scheduler_tasklet_func, 0); p_scheduler_tasklet = &scheduler_tasklet; #endif /*--- #if defined(USE_TASKLETS) ---*/ #if defined(USE_WORKQUEUES) p_scheduler_workqueue = create_singlethread_workqueue("capi_oslib"); #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) INIT_WORK(&scheduler_work, (void (*)(void *))scheduler_tasklet_func, NULL); #else/*--- #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) ---*/ INIT_WORK(&scheduler_work, (void (*)(struct work_struct *))scheduler_tasklet_func); #endif/*--- #else ---*//*--- #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) ---*/ #endif /*--- #if defined(USE_WORKQUEUES) ---*/ return; } #if defined(USE_TASKLETS) if(p_scheduler_tasklet) { p_scheduler_tasklet = NULL; tasklet_kill(&scheduler_tasklet); } #endif /*--- #if defined(USE_TASKLETS) ---*/ #if defined(USE_WORKQUEUES) if(p_scheduler_workqueue) { destroy_workqueue(p_scheduler_workqueue); } #endif /*--- #if defined(USE_WORKQUEUES) ---*/ } } /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static inline void capi_oslib_enable_scheduler (void) { /*--- DEB_INFO("Enabling scheduler...\n"); ---*/ #if defined(USE_TASKLETS) if(p_scheduler_tasklet) tasklet_enable (p_scheduler_tasklet); #endif /*--- #if defined(USE_TASKLETS) ---*/ atomic_set (&capi_oslib_scheduler_enabled, 1); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void os_enable_scheduler (void) { capi_oslib_enable_scheduler(); } EXPORT_SYMBOL(os_enable_scheduler); /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static inline void capi_oslib_disable_scheduler (void) { /*--- DEB_INFO("Disabling scheduler...\n"); ---*/ atomic_set (&capi_oslib_scheduler_enabled, 0); #if defined(USE_TASKLETS) if(p_scheduler_tasklet) tasklet_disable(p_scheduler_tasklet); #endif /*--- #if defined(USE_TASKLETS) ---*/ } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void os_disable_scheduler (void) { capi_oslib_disable_scheduler(); } EXPORT_SYMBOL(os_disable_scheduler); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void capi_oslib_scheduler (unsigned long data __attribute__((unused))) { static atomic_t running = ATOMIC_INIT (0); if(atomic_inc_return(&running) == 1) { CA_TIMER_POLL(); (void)(*capi_oslib_stack->cm_schedule)(); atomic_set(&running, 0); } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) static irqreturn_t capi_oslib_irq_handler (int irq, void * args, struct pt_regs * regs) { #else/*--- #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) ---*/ static irqreturn_t capi_oslib_irq_handler (int irq __attribute__((unused)), void * args) { #endif/*--- #else ---*//*--- #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) ---*/ if (args != NULL) { if ((*capi_oslib_stack->cm_handle_events) ()) { if (atomic_read (&capi_oslib_scheduler_enabled)) { #if defined(USE_TASKLETS) if(p_scheduler_tasklet) tasklet_schedule (p_scheduler_tasklet); #endif /*--- #if defined(USE_TASKLETS) ---*/ #if defined(USE_WORKQUEUES) if(p_scheduler_workqueue) queue_work(p_scheduler_workqueue, &scheduler_work); #endif /*--- #if defined(USE_WORKQUEUES) ---*/ } if(p_delic_tasklet) tasklet_schedule(p_delic_tasklet); return IRQ_HANDLED; } } return IRQ_NONE; } /* irq_handler */ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #define IO_RANGE 256 /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ int capi_oslib_install_card (struct _stack_init_params * card) { int result = 0; capi_oslib_scheduler_tasklet_init(capi_oslib_scheduler, 1); capi_oslib_disable_scheduler (); if(capi_oslib_interrupt_library && capi_oslib_interrupt_library->tasklet_func) capi_oslib_delic_tasklet_init(capi_oslib_interrupt_library->tasklet_func, 1); if(card) { if(card->io_addr) { request_mem_region (card->io_addr, IO_RANGE, "capi_oslib"); DEB_INFO( "I/O memory range 0x%08x-0x%08x assigned to " "capi_oslib" " driver.\n", card->io_addr, card->io_addr + IO_RANGE - 1 ); } if(card->irq_num) { result = request_irq ( card->irq_num, &capi_oslib_irq_handler, #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) SA_INTERRUPT, #else/*--- #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) ---*/ IRQF_DISABLED, #endif/*--- #else ---*//*--- #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) ---*/ "capi_oslib", card ); if (result) { release_mem_region (card->io_addr, IO_RANGE); DEB_ERR("irq: %d registration failed\n", card->irq_num ); return 1; } else { DEB_INFO("irq: %d successfully registred\n", card->irq_num ); } } } capi_oslib_scheduler_timer_init(); return 0; } /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ void capi_oslib_remove_card (struct _stack_init_params* card) { capi_oslib_scheduler_timer_stop(); capi_oslib_disable_scheduler (); capi_oslib_scheduler_tasklet_init(capi_oslib_scheduler, 0); if(capi_oslib_interrupt_library && capi_oslib_interrupt_library->tasklet_func) capi_oslib_delic_tasklet_init(capi_oslib_interrupt_library->tasklet_func, 0); if(card == NULL) return; if(card->irq_num) { DEB_INFO("Releasing IRQ #%d...\n", card->irq_num); free_irq (card->irq_num, card); } if(card->io_addr) { DEB_INFO( "Releasing I/O memory range 0x%08x-0x%08x...\n", card->io_addr, card->io_addr + IO_RANGE - 1 ); release_mem_region (card->io_addr, IO_RANGE); } } /* remove_card */ /*--------------------------------------------------------------------------------*\ * not used: direct setting in isdn_fonx \*--------------------------------------------------------------------------------*/ void capi_oslib_init_tasklet_control(void (* tasklet_control)(enum _tasklet_control)){ if(capi_oslib_stack == NULL) { DEB_ERR("capioslib: not initialized\n"); return; } if(capi_oslib_stack->cm_ctrl_tasklet && tasklet_control) { DEB_ERR("capioslib: cm_ctrl_tasklet already initialized, ignore reinit!\n"); } capi_oslib_stack->cm_ctrl_tasklet = (void *)tasklet_control; DEB_INFO("capioslib: cm_ctrl_tasklet with %p initialized\n", tasklet_control); } EXPORT_SYMBOL(capi_oslib_init_tasklet_control); /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ void EnterCritical (void) { /*--- printk("[EnterCritical]"); ---*/ if(capi_oslib_init_params && capi_oslib_init_params->irq_num) disable_irq (capi_oslib_init_params->irq_num); /*--- printk("1"); ---*/ if(p_delic_tasklet) tasklet_disable (p_delic_tasklet); /*--- printk("2"); ---*/ if(capi_oslib_stack->cm_ctrl_tasklet) (*capi_oslib_stack->cm_ctrl_tasklet)(tasklet_control_enter_critical); /*--- printk("3"); ---*/ atomic_inc (&capi_oslib_crit_level); /*--- printk("4\n"); ---*/ } EXPORT_SYMBOL(EnterCritical); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void _EnterCritical (char *File __attribute__((unused)), int Line __attribute__((unused))) { EnterCritical(); } EXPORT_SYMBOL(_EnterCritical); /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ void LeaveCritical (void) { /*--- printk("[LeaveCritical]"); ---*/ atomic_dec (&capi_oslib_crit_level); BUG_ON( atomic_read(&capi_oslib_crit_level) < 0 ); /*--- printk("1"); ---*/ if(capi_oslib_init_params && capi_oslib_init_params->irq_num) enable_irq (capi_oslib_init_params->irq_num); /*--- printk("2"); ---*/ if(p_delic_tasklet) tasklet_enable(p_delic_tasklet); /*--- printk("3"); ---*/ if(capi_oslib_stack->cm_ctrl_tasklet) (*capi_oslib_stack->cm_ctrl_tasklet)(tasklet_control_leave_critical); /*--- printk("4\n"); ---*/ } EXPORT_SYMBOL(LeaveCritical); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void _LeaveCritical (char *File __attribute__((unused)), int Line __attribute__((unused))) { LeaveCritical(); } EXPORT_SYMBOL(_LeaveCritical); /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ #if 0 void EnterCacheSensitiveCode (void) { (*interface->enter_cache_sensitive_code) (); } /* EnterCacheSensitiveCode */ #endif /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ #if 0 void LeaveCacheSensitiveCode (void) { (*interface->leave_cache_sensitive_code) (); } /* LeaveCacheSensitiveCode */ #endif