--- driver.c.orig 2004-06-17 02:00:00.000000000 +0200 +++ driver.c 2005-02-26 10:40:39.000000000 +0100 @@ -18,6 +18,16 @@ * http://www.opensource.org/licenses/lgpl-license.html * * Contact: AVM GmbH, Alt-Moabit 95, 10559 Berlin, Germany, email: info@avm.de + * + * Sunday Dec 07 18:10 2003 + * Modified by Christian 'greeny' Heckhoff to improve locking + * based on modifications by Joerg Lehrke for Fritz!Card DSL + * + * Saturday Jul 24 2004, Oswin Horvath + * small modifications to make the patch work for the Fritz!Card SL USB (03.11.94) + * + * Saturday Feb 26 2005, Stefan Schweizer + * Fixed patch for rev 0.2.2 */ #include @@ -54,6 +64,8 @@ #include "devif.h" #include "driver.h" +#undef SINGLE_LOCK + #ifndef HZ # error HZ is not defined... #endif @@ -84,7 +96,11 @@ \*---------------------------------------------------------------------------*/ card_p capi_card = NULL; lib_callback_t * capi_lib = NULL; +#if defined (SINGLE_LOCK) +# define stack_lock qt_lock +#else spinlock_t stack_lock = SPIN_LOCK_UNLOCKED; +#endif struct capi_ctr * capi_controller[2] = { NULL, NULL } ; int card_config; @@ -919,12 +935,17 @@ static inline int in_critical (void) { /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static inline void check (void) { + unsigned long flags; if (atomic_read (&rx_flag) > 0) { + spin_lock_irqsave (&stack_lock, flags); rx_handler (capi_card); + spin_unlock_irqrestore (&stack_lock, flags); } if (atomic_read (&tx_flag) > 0) { + spin_lock_irqsave (&stack_lock, flags); tx_handler (capi_card); + spin_unlock_irqrestore (&stack_lock, flags); } } /* check */ @@ -1101,6 +1122,7 @@ static __attr void __stack scheduler_con /*-S-------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static int scheduler (void * arg) { + unsigned long flags; UNUSED_ARG (arg); daemonize (TARGET); @@ -1134,6 +1156,7 @@ static int scheduler (void * arg) { } /* Body of thread, invoke scheduler */ + local_irq_save(flags); if (spin_trylock (&stack_lock)) { info (!atomic_xchg (&in_scheduler, 1)); os_timer_poll (); @@ -1146,6 +1169,7 @@ static int scheduler (void * arg) { #endif spin_unlock (&stack_lock); } + local_irq_restore(flags); } LOG("Scheduler thread stopped.\n"); up (&thread_sync); @@ -1324,22 +1348,44 @@ static void rx_handler (card_p pdc) { /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static void tx_task (unsigned long data) { - + unsigned long flags; UNUSED_ARG (data); - if (!in_critical () && spin_trylock (&stack_lock)) { - tx_handler (capi_card); - spin_unlock (&stack_lock); + + if (in_critical ()){ + atomic_set (&tx_flag, 1); + kick_scheduler (); + } else { + local_irq_save(flags); + if (spin_trylock (&stack_lock)) { + tx_handler (capi_card); + spin_unlock (&stack_lock); + } else { + atomic_set (&tx_flag, 1); + kick_scheduler (); + } + local_irq_restore(flags); } } /* tx_task */ /*---------------------------------------------------------------------------*\ \*---------------------------------------------------------------------------*/ static void rx_task (unsigned long data) { - + unsigned long flags; UNUSED_ARG (data); - if (!in_critical () && spin_trylock (&stack_lock)) { - rx_handler (capi_card); - spin_unlock (&stack_lock); + + if (in_critical ()){ + atomic_set (&tx_flag, 1); + kick_scheduler (); + } else { + local_irq_save(flags); + if (spin_trylock (&stack_lock)) { + tx_handler (capi_card); + spin_unlock (&stack_lock); + } else { + atomic_set (&tx_flag, 1); + kick_scheduler (); + } + local_irq_restore(flags); } } /* rx_task */