--- ztdummy.c 2007-01-26 15:07:54.000000000 +0100 +++ /home/karsten/src/zaptel-1.2.12/ztdummy.c 2007-01-26 15:30:58.000000000 +0100 @@ -95,6 +95,9 @@ static int debug = 0; +/* interrupt from extern module in use? */ +static int use_extern_interrupt = 0; + #ifdef LINUX26 #ifndef USE_RTC /* New 2.6 kernel timer stuff */ @@ -125,6 +128,14 @@ #endif +/* 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); + #ifdef LINUX26 #ifdef USE_RTC @@ -195,7 +206,7 @@ return 0; } -int init_module(void) +static int ztdummy_init_interrupts(void) { #ifdef LINUX26 #ifdef USE_RTC @@ -208,39 +219,8 @@ #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 -#if defined(LINUX26) && !defined(USE_RTC) - if (HZ != 1000) { - printk("ztdummy: This module requires the kernel HZ setting to be 1000 ticks per second\n"); - return -ENODEV; - } -#endif /* defined(LINUX26) && !defined(USE_RTC) */ - - 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; - } - #ifdef LINUX26 #ifdef USE_RTC atomic_set(&ztd->ticks, 0); @@ -281,6 +261,90 @@ fill_td(td, TD_CTRL_IOC, 0, 0); insert_td_horizontal(s, s->int_chain[0], td); /* use int_chain[0] to get 1ms interrupts */ #endif + printk("ztdummy: Using internal time source\n"); + return 0; +} + +/* 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 + 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 + 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) +{ +#ifdef LINUX26 + module_put(THIS_MODULE); +#else + MOD_DEC_USE_COUNT; +#endif + use_extern_interrupt = 0; + + return ztdummy_init_interrupts(); + +} +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 + +#if defined(LINUX26) && !defined(USE_RTC) + if (HZ != 1000) { + printk("ztdummy: This module requires the kernel HZ setting to be 1000 ticks per second\n"); + return -ENODEV; + } +#endif /* defined(LINUX26) && !defined(USE_RTC) */ + + 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"); @@ -290,16 +354,19 @@ void cleanup_module(void) { + /* interrupts already disabled? */ + if (use_extern_interrupt==0) { #ifdef LINUX26 #ifdef USE_RTC - rtc_control(&ztd->rtc_task, RTC_PIE_OFF, 0); - rtc_unregister(&ztd->rtc_task); + 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