--- ztdummy.c 2007-03-23 10:15:40.000000000 +0100 +++ /home/karsten/src/zaptel-trunk/ztdummy.c 2007-03-23 09:26:20.000000000 +0100 @@ -82,6 +82,9 @@ static int debug = 0; +/* interrupt from extern module in use? */ +static int use_extern_interrupt = 0; + #if defined(LINUX26) && defined(USE_RTC) static int rtc_rate = 0; static int current_rate = 0; @@ -118,7 +121,6 @@ #endif - #ifdef LINUX26 #ifdef USE_RTC static void update_rtc_rate(struct ztdummy *ztd) @@ -215,7 +217,7 @@ return 0; } -int init_module(void) +int ztdummy_init_interrupts(void) { #ifdef LINUX26 #ifdef USE_RTC @@ -228,16 +230,6 @@ #else spinlock_t mylock = SPIN_LOCK_UNLOCKED; #endif - - if (uhci_devices==NULL) { - printk ("ztdummy: Uhci_devices pointer error.\n"); - return -ENODEV; - } - s=*uhci_devices; /* uhci device */ - if (s==NULL) { - printk ("ztdummy: No uhci_device found.\n"); - return -ENODEV; - } #endif ztd = kmalloc(sizeof(struct ztdummy), GFP_KERNEL); @@ -302,6 +294,102 @@ #endif if (debug) + printk("ztdummy: Using internal time source\n"); + return 0; +} + +/* extern interrupt - called at 1000Hz for example from mISDN kernel module hfc_multi */ +static void ztdummy_extern_interrupt(void) +{ + zt_receive(&ztd->span); + zt_transmit(&ztd->span); +} +EXPORT_SYMBOL_GPL(ztdummy_extern_interrupt); + +/* function to register the interrupt from external module + * nothing more to do than to cancel the other interrupt routines */ +static void ztdummy_register_interrupt(void) +{ + /* to avoid second unregistration of old interrupts */ + if(!use_extern_interrupt) { + use_extern_interrupt = 1; +#ifdef LINUX26 + try_module_get(THIS_MODULE); +#ifdef USE_RTC + if (taskletpending) { + tasklet_disable(&ztd_tlet); + tasklet_kill(&ztd_tlet); + } + rtc_control(&ztd->rtc_task, RTC_PIE_OFF, 0); + rtc_unregister(&ztd->rtc_task); +#else + del_timer(&timer); +#endif +#else + MOD_INC_USE_COUNT; + free_irq(s->irq, ztd); /* disable interrupts */ +#endif + if(debug) + printk("ztdummy: Using external time source.\n"); + } +} +EXPORT_SYMBOL_GPL(ztdummy_register_interrupt); + +/* function to unregister the interrupt from external module + * reactivate formerly used routines */ +static int ztdummy_unregister_interrupt(void) +{ + int err; + + err = ztdummy_init_interrupts(); + if(!err) { + use_extern_interrupt = 0; +#ifdef LINUX26 + module_put(THIS_MODULE); +#else + MOD_DEC_USE_COUNT; +#endif + } + + return err; +} +EXPORT_SYMBOL_GPL(ztdummy_unregister_interrupt); + +int init_module(void) +{ + int err; + +#ifndef LINUX26 + if (uhci_devices==NULL) { + printk ("ztdummy: Uhci_devices pointer error.\n"); + return -ENODEV; + } + s=*uhci_devices; /* uhci device */ + if (s==NULL) { + printk ("ztdummy: No uhci_device found.\n"); + return -ENODEV; + } +#endif + + ztd = kmalloc(sizeof(struct ztdummy), GFP_KERNEL); + if (ztd == NULL) { + printk("ztdummy: Unable to allocate memory\n"); + return -ENOMEM; + } + + memset(ztd, 0x0, sizeof(struct ztdummy)); + + if (ztdummy_initialize(ztd)) { + printk("ztdummy: Unable to intialize zaptel driver\n"); + kfree(ztd); + return -ENODEV; + } + + /* unregister external interrupt means activate internal routines */ + err = ztdummy_init_interrupts(); + if (err) return err; + + if (debug) printk("ztdummy: init() finished\n"); return 0; } @@ -309,20 +397,22 @@ void cleanup_module(void) { + if(!use_extern_interrupt) { #ifdef LINUX26 #ifdef USE_RTC - if (taskletpending) { - tasklet_disable(&ztd_tlet); - tasklet_kill(&ztd_tlet); - } - rtc_control(&ztd->rtc_task, RTC_PIE_OFF, 0); - rtc_unregister(&ztd->rtc_task); + if (taskletpending) { + tasklet_disable(&ztd_tlet); + tasklet_kill(&ztd_tlet); + } + rtc_control(&ztd->rtc_task, RTC_PIE_OFF, 0); + rtc_unregister(&ztd->rtc_task); #else - del_timer(&timer); + del_timer(&timer); #endif #else - free_irq(s->irq, ztd); /* disable interrupts */ + free_irq(s->irq, ztd); /* disable interrupts */ #endif + } zt_unregister(&ztd->span); kfree(ztd); #ifndef LINUX26