};
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
+/* FIXME: The following lock is a sledgehammer-workaround to a
+ * locking issue with the capiminor (and maybe other) data structure(s).
+ * Access to this data is done in a racy way and crashes the machine with
+ * a FritzCard DSL driver; sooner or later. This is a workaround
+ * which trades scalability vs stability, so it doesn't crash the kernel anymore.
+ * The correct (and scalable) fix for the issue seems to require
+ * an API change to the drivers... . */
+static DEFINE_SPINLOCK(workaround_lock);
+
 struct capincci {
        struct capincci *next;
        u32              ncci;
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
        struct capincci *np;
        u32 ncci;
+       unsigned long flags;
 
        if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
                u16 info = CAPIMSG_U16(skb->data, 12); // Info field
                capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
                up(&cdev->ncci_list_sem);
        }
+       spin_lock_irqsave(&workaround_lock, flags);
        if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
                skb_queue_tail(&cdev->recvqueue, skb);
                wake_up_interruptible(&cdev->recvwait);
+               spin_unlock_irqrestore(&workaround_lock, flags);
                return;
        }
        ncci = CAPIMSG_CONTROL(skb->data);
                printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
                skb_queue_tail(&cdev->recvqueue, skb);
                wake_up_interruptible(&cdev->recvwait);
+               spin_unlock_irqrestore(&workaround_lock, flags);
                return;
        }
 #ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
        if (!mp) {
                skb_queue_tail(&cdev->recvqueue, skb);
                wake_up_interruptible(&cdev->recvwait);
+               spin_unlock_irqrestore(&workaround_lock, flags);
                return;
        }
 
                wake_up_interruptible(&cdev->recvwait);
        }
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+       spin_unlock_irqrestore(&workaround_lock, flags);
 }
 
 /* -------- file_operations for capidev ----------------------------- */
 static int capinc_tty_open(struct tty_struct * tty, struct file * file)
 {
        struct capiminor *mp;
+       unsigned long flags;
 
        if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == 0)
                return -ENXIO;
 
        tty->driver_data = (void *)mp;
 
+       spin_lock_irqsave(&workaround_lock, flags);
        if (atomic_read(&mp->ttyopencount) == 0)
                mp->tty = tty;
        atomic_inc(&mp->ttyopencount);
        printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount));
 #endif
        handle_minor_recv(mp);
+       spin_unlock_irqrestore(&workaround_lock, flags);
        return 0;
 }
 
 {
        struct capiminor *mp = (struct capiminor *)tty->driver_data;
        struct sk_buff *skb;
+       unsigned long flags;
 
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count);
                return 0;
        }
 
+       spin_lock_irqsave(&workaround_lock, flags);
        skb = mp->ttyskb;
        if (skb) {
                mp->ttyskb = NULL;
        skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC);
        if (!skb) {
                printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n");
+               spin_unlock_irqrestore(&workaround_lock, flags);
                return -ENOMEM;
        }
 
        mp->outbytes += skb->len;
        (void)handle_minor_send(mp);
        (void)handle_minor_recv(mp);
+       spin_unlock_irqrestore(&workaround_lock, flags);
        return count;
 }
 
 {
        struct capiminor *mp = (struct capiminor *)tty->driver_data;
        struct sk_buff *skb;
+       unsigned long flags;
 
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
                return;
        }
 
+       spin_lock_irqsave(&workaround_lock, flags);
        skb = mp->ttyskb;
        if (skb) {
                if (skb_tailroom(skb) > 0) {
                        *(skb_put(skb, 1)) = ch;
+                       spin_unlock_irqrestore(&workaround_lock, flags);
                        return;
                }
                mp->ttyskb = NULL;
        } else {
                printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
        }
+       spin_unlock_irqrestore(&workaround_lock, flags);
 }
 
 static void capinc_tty_flush_chars(struct tty_struct *tty)
 {
        struct capiminor *mp = (struct capiminor *)tty->driver_data;
        struct sk_buff *skb;
+       unsigned long flags;
 
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_flush_chars\n");
                return;
        }
 
+       spin_lock_irqsave(&workaround_lock, flags);
        skb = mp->ttyskb;
        if (skb) {
                mp->ttyskb = NULL;
                (void)handle_minor_send(mp);
        }
        (void)handle_minor_recv(mp);
+       spin_unlock_irqrestore(&workaround_lock, flags);
 }
 
 static int capinc_tty_write_room(struct tty_struct *tty)
 static void capinc_tty_unthrottle(struct tty_struct * tty)
 {
        struct capiminor *mp = (struct capiminor *)tty->driver_data;
+       unsigned long flags;
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_unthrottle\n");
 #endif
        if (mp) {
+               spin_lock_irqsave(&workaround_lock, flags);
                mp->ttyinstop = 0;
                handle_minor_recv(mp);
+               spin_unlock_irqrestore(&workaround_lock, flags);
        }
 }
 
 static void capinc_tty_start(struct tty_struct *tty)
 {
        struct capiminor *mp = (struct capiminor *)tty->driver_data;
+       unsigned long flags;
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_start\n");
 #endif
        if (mp) {
+               spin_lock_irqsave(&workaround_lock, flags);
                mp->ttyoutstop = 0;
                (void)handle_minor_send(mp);
+               spin_unlock_irqrestore(&workaround_lock, flags);
        }
 }