mISDN: Fix kernel crash when doing hardware conference with more than two members
[safe/jmp/linux-2.6] / drivers / isdn / capi / kcapi.c
index feec40c..5360c4f 100644 (file)
@@ -10,7 +10,7 @@
  *
  */
 
-#define CONFIG_AVMB1_COMPAT
+#define AVMB1_COMPAT
 
 #include "kcapi.h"
 #include <linux/module.h>
 #include <asm/uaccess.h>
 #include <linux/isdn/capicmd.h>
 #include <linux/isdn/capiutil.h>
-#ifdef CONFIG_AVMB1_COMPAT
+#ifdef AVMB1_COMPAT
 #include <linux/b1lli.h>
 #endif
+#include <linux/mutex.h>
 
 static char *revision = "$Revision: 1.1.2.8 $";
 
@@ -66,7 +67,7 @@ LIST_HEAD(capi_drivers);
 DEFINE_RWLOCK(capi_drivers_list_lock);
 
 static DEFINE_RWLOCK(application_lock);
-static DECLARE_MUTEX(controller_sem);
+static DEFINE_MUTEX(controller_mutex);
 
 struct capi20_appl *capi_applications[CAPI_MAXAPPL];
 struct capi_ctr *capi_cards[CAPI_MAXCONTR];
@@ -153,7 +154,7 @@ static void register_appl(struct capi_ctr *card, u16 applid, capi_register_param
        if (card)
                card->register_appl(card, applid, rparam);
        else
-               printk(KERN_WARNING "%s: cannot get card resources\n", __FUNCTION__);
+               printk(KERN_WARNING "%s: cannot get card resources\n", __func__);
 }
 
 
@@ -177,7 +178,7 @@ static void notify_up(u32 contr)
                printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
        }
        if (!card) {
-               printk(KERN_WARNING "%s: invalid contr %d\n", __FUNCTION__, contr);
+               printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
                return;
        }
        for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
@@ -207,9 +208,10 @@ static void notify_down(u32 contr)
        }
 }
 
-static void notify_handler(void *data)
+static void notify_handler(struct work_struct *work)
 {
-       struct capi_notifier *np = data;
+       struct capi_notifier *np =
+               container_of(work, struct capi_notifier, work);
 
        switch (np->cmd) {
        case KCI_CONTRUP:
@@ -234,7 +236,7 @@ static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci)
        if (!np)
                return -ENOMEM;
 
-       INIT_WORK(&np->work, notify_handler, np);
+       INIT_WORK(&np->work, notify_handler);
        np->cmd = cmd;
        np->controller = controller;
        np->applid = applid;
@@ -247,15 +249,16 @@ static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci)
        
 /* -------- Receiver ------------------------------------------ */
 
-static void recv_handler(void *_ap)
+static void recv_handler(struct work_struct *work)
 {
        struct sk_buff *skb;
-       struct capi20_appl *ap = (struct capi20_appl *) _ap;
+       struct capi20_appl *ap =
+               container_of(work, struct capi20_appl, recv_work);
 
        if ((!ap) || (ap->release_in_progress))
                return;
 
-       down(&ap->recv_sem);
+       mutex_lock(&ap->recv_mtx);
        while ((skb = skb_dequeue(&ap->recv_queue))) {
                if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
                        ap->nrecvdatapkt++;
@@ -264,7 +267,7 @@ static void recv_handler(void *_ap)
 
                ap->recv_message(ap, skb);
        }
-       up(&ap->recv_sem);
+       mutex_unlock(&ap->recv_mtx);
 }
 
 void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb)
@@ -273,10 +276,17 @@ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *s
        int showctl = 0;
        u8 cmd, subcmd;
        unsigned long flags;
+       _cdebbuf *cdb;
 
        if (card->cardstate != CARD_RUNNING) {
-               printk(KERN_INFO "kcapi: controller %d not active, got: %s",
-                      card->cnr, capi_message2str(skb->data));
+               cdb = capi_message2str(skb->data);
+               if (cdb) {
+                       printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
+                               card->cnr, cdb->buf);
+                       cdebbuf_free(cdb);
+               } else
+                       printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n",
+                               card->cnr);
                goto error;
        }
 
@@ -292,15 +302,21 @@ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *s
        showctl |= (card->traceflag & 1);
        if (showctl & 2) {
                if (showctl & 1) {
-                       printk(KERN_DEBUG "kcapi: got [0x%lx] id#%d %s len=%u\n",
-                              (unsigned long) card->cnr,
-                              CAPIMSG_APPID(skb->data),
+                       printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
+                              card->cnr, CAPIMSG_APPID(skb->data),
                               capi_cmd2str(cmd, subcmd),
                               CAPIMSG_LEN(skb->data));
                } else {
-                       printk(KERN_DEBUG "kcapi: got [0x%lx] %s\n",
-                                       (unsigned long) card->cnr,
-                                       capi_message2str(skb->data));
+                       cdb = capi_message2str(skb->data);
+                       if (cdb) {
+                               printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
+                                       card->cnr, cdb->buf);
+                               cdebbuf_free(cdb);
+                       } else
+                               printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
+                                       card->cnr, CAPIMSG_APPID(skb->data),
+                                       capi_cmd2str(cmd, subcmd),
+                                       CAPIMSG_LEN(skb->data));
                }
 
        }
@@ -309,8 +325,15 @@ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *s
        ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
        if ((!ap) || (ap->release_in_progress)) {
                read_unlock_irqrestore(&application_lock, flags);
-               printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
-                       CAPIMSG_APPID(skb->data), capi_message2str(skb->data));
+               cdb = capi_message2str(skb->data);
+               if (cdb) {
+                       printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
+                       CAPIMSG_APPID(skb->data), cdb->buf);
+                       cdebbuf_free(cdb);
+               } else
+                       printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n",
+                               CAPIMSG_APPID(skb->data),
+                               capi_cmd2str(cmd, subcmd));
                goto error;
        }
        skb_queue_tail(&ap->recv_queue, skb);
@@ -329,7 +352,7 @@ void capi_ctr_ready(struct capi_ctr * card)
 {
        card->cardstate = CARD_RUNNING;
 
-        printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
+        printk(KERN_NOTICE "kcapi: card [%03d] \"%s\" ready.\n",
               card->cnr, card->name);
 
        notify_push(KCI_CONTRUP, card->cnr, 0, 0);
@@ -361,7 +384,7 @@ void capi_ctr_reseted(struct capi_ctr * card)
                capi_ctr_put(card);
        }
 
-       printk(KERN_NOTICE "kcapi: card %d down.\n", card->cnr);
+       printk(KERN_NOTICE "kcapi: card [%03d] down.\n", card->cnr);
 
        notify_push(KCI_CONTRDOWN, card->cnr, 0, 0);
 }
@@ -371,7 +394,7 @@ EXPORT_SYMBOL(capi_ctr_reseted);
 void capi_ctr_suspend_output(struct capi_ctr *card)
 {
        if (!card->blocked) {
-               printk(KERN_DEBUG "kcapi: card %d suspend\n", card->cnr);
+               printk(KERN_DEBUG "kcapi: card [%03d] suspend\n", card->cnr);
                card->blocked = 1;
        }
 }
@@ -381,7 +404,7 @@ EXPORT_SYMBOL(capi_ctr_suspend_output);
 void capi_ctr_resume_output(struct capi_ctr *card)
 {
        if (card->blocked) {
-               printk(KERN_DEBUG "kcapi: card %d resume\n", card->cnr);
+               printk(KERN_DEBUG "kcapi: card [%03d] resume\n", card->cnr);
                card->blocked = 0;
        }
 }
@@ -395,20 +418,20 @@ attach_capi_ctr(struct capi_ctr *card)
 {
        int i;
 
-       down(&controller_sem);
+       mutex_lock(&controller_mutex);
 
        for (i = 0; i < CAPI_MAXCONTR; i++) {
                if (capi_cards[i] == NULL)
                        break;
        }
        if (i == CAPI_MAXCONTR) {
-               up(&controller_sem);
+               mutex_unlock(&controller_mutex);
                printk(KERN_ERR "kcapi: out of controller slots\n");
                return -EBUSY;
        }
        capi_cards[i] = card;
 
-       up(&controller_sem);
+       mutex_unlock(&controller_mutex);
 
        card->nrecvctlpkt = 0;
        card->nrecvdatapkt = 0;
@@ -429,7 +452,7 @@ attach_capi_ctr(struct capi_ctr *card)
        }
 
        ncards++;
-       printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n",
+       printk(KERN_NOTICE "kcapi: Controller [%03d]: %s attached\n",
                        card->cnr, card->name);
        return 0;
 }
@@ -448,7 +471,7 @@ int detach_capi_ctr(struct capi_ctr *card)
           card->procent = NULL;
        }
        capi_cards[card->cnr - 1] = NULL;
-       printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n",
+       printk(KERN_NOTICE "kcapi: Controller [%03d]: %s unregistered\n",
                        card->cnr, card->name);
 
        return 0;
@@ -524,20 +547,20 @@ u16 capi20_register(struct capi20_appl *ap)
        ap->nsentctlpkt = 0;
        ap->nsentdatapkt = 0;
        ap->callback = NULL;
-       init_MUTEX(&ap->recv_sem);
+       mutex_init(&ap->recv_mtx);
        skb_queue_head_init(&ap->recv_queue);
-       INIT_WORK(&ap->recv_work, recv_handler, (void *)ap);
+       INIT_WORK(&ap->recv_work, recv_handler);
        ap->release_in_progress = 0;
 
        write_unlock_irqrestore(&application_lock, flags);
        
-       down(&controller_sem);
+       mutex_lock(&controller_mutex);
        for (i = 0; i < CAPI_MAXCONTR; i++) {
                if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
                        continue;
                register_appl(capi_cards[i], applid, &ap->rparam);
        }
-       up(&controller_sem);
+       mutex_unlock(&controller_mutex);
 
        if (showcapimsgs & 1) {
                printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
@@ -560,13 +583,13 @@ u16 capi20_release(struct capi20_appl *ap)
        capi_applications[ap->applid - 1] = NULL;
        write_unlock_irqrestore(&application_lock, flags);
 
-       down(&controller_sem);
+       mutex_lock(&controller_mutex);
        for (i = 0; i < CAPI_MAXCONTR; i++) {
                if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
                        continue;
                release_appl(capi_cards[i], ap->applid);
        }
-       up(&controller_sem);
+       mutex_unlock(&controller_mutex);
 
        flush_scheduled_work();
        skb_queue_purge(&ap->recv_queue);
@@ -620,17 +643,25 @@ u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
        showctl |= (card->traceflag & 1);
        if (showctl & 2) {
                if (showctl & 1) {
-                       printk(KERN_DEBUG "kcapi: put [%#x] id#%d %s len=%u\n",
+                       printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
                               CAPIMSG_CONTROLLER(skb->data),
                               CAPIMSG_APPID(skb->data),
                               capi_cmd2str(cmd, subcmd),
                               CAPIMSG_LEN(skb->data));
                } else {
-                       printk(KERN_DEBUG "kcapi: put [%#x] %s\n",
-                              CAPIMSG_CONTROLLER(skb->data),
-                              capi_message2str(skb->data));
+                       _cdebbuf *cdb = capi_message2str(skb->data);
+                       if (cdb) {
+                               printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
+                                       CAPIMSG_CONTROLLER(skb->data),
+                                       cdb->buf);
+                               cdebbuf_free(cdb);
+                       } else
+                               printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
+                                       CAPIMSG_CONTROLLER(skb->data),
+                                       CAPIMSG_APPID(skb->data),
+                                       capi_cmd2str(cmd, subcmd),
+                                       CAPIMSG_LEN(skb->data));
                }
-
        }
        return card->send_message(card, skb);
 }
@@ -709,7 +740,7 @@ u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
 
 EXPORT_SYMBOL(capi20_get_profile);
 
-#ifdef CONFIG_AVMB1_COMPAT
+#ifdef AVMB1_COMPAT
 static int old_capi_manufacturer(unsigned int cmd, void __user *data)
 {
        avmb1_loadandconfigdef ldef;
@@ -790,20 +821,25 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
                                return -EFAULT;
                }
                card = get_capi_ctr_by_nr(ldef.contr);
+               if (!card)
+                       return -EINVAL;
                card = capi_ctr_get(card);
                if (!card)
                        return -ESRCH;
-               if (card->load_firmware == 0) {
+               if (card->load_firmware == NULL) {
                        printk(KERN_DEBUG "kcapi: load: no load function\n");
+                       capi_ctr_put(card);
                        return -ESRCH;
                }
 
                if (ldef.t4file.len <= 0) {
                        printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
+                       capi_ctr_put(card);
                        return -EINVAL;
                }
-               if (ldef.t4file.data == 0) {
+               if (ldef.t4file.data == NULL) {
                        printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
+                       capi_ctr_put(card);
                        return -EINVAL;
                }
 
@@ -816,6 +852,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
 
                if (card->cardstate != CARD_DETECTED) {
                        printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
+                       capi_ctr_put(card);
                        return -EBUSY;
                }
                card->cardstate = CARD_LOADING;
@@ -871,7 +908,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
         struct capi_ctr *card;
 
        switch (cmd) {
-#ifdef CONFIG_AVMB1_COMPAT
+#ifdef AVMB1_COMPAT
        case AVMB1_LOAD:
        case AVMB1_LOAD_AND_CONFIG:
        case AVMB1_RESETCARD:
@@ -891,7 +928,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
                        return -ESRCH;
 
                card->traceflag = fdef.flag;
-               printk(KERN_INFO "kcapi: contr %d set trace=%d\n",
+               printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
                        card->cnr, card->traceflag);
                return 0;
        }
@@ -918,7 +955,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
                        if (strcmp(driver->name, cdef.driver) == 0)
                                break;
                }
-               if (driver == 0) {
+               if (driver == NULL) {
                        printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
                                        cdef.driver);
                        return -ESRCH;
@@ -964,12 +1001,16 @@ static int __init kcapi_init(void)
 {
        char *p;
        char rev[32];
+       int ret;
 
+       ret = cdebug_init();
+       if (ret)
+               return ret;
         kcapi_proc_init();
 
-       if ((p = strchr(revision, ':')) != 0 && p[1]) {
+       if ((p = strchr(revision, ':')) != NULL && p[1]) {
                strlcpy(rev, p + 2, sizeof(rev));
-               if ((p = strchr(rev, '$')) != 0 && p > rev)
+               if ((p = strchr(rev, '$')) != NULL && p > rev)
                   *(p-1) = 0;
        } else
                strcpy(rev, "1.0");
@@ -985,6 +1026,7 @@ static void __exit kcapi_exit(void)
 
        /* make sure all notifiers are finished */
        flush_scheduled_work();
+       cdebug_exit();
 }
 
 module_init(kcapi_init);