Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
[safe/jmp/linux-2.6] / drivers / isdn / capi / capi.c
index 1200d1d..2d83524 100644 (file)
@@ -9,7 +9,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -19,6 +18,7 @@
 #include <linux/fcntl.h>
 #include <linux/fs.h>
 #include <linux/signal.h>
+#include <linux/mutex.h>
 #include <linux/mm.h>
 #include <linux/smp_lock.h>
 #include <linux/timer.h>
@@ -39,7 +39,6 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/moduleparam.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/isdn/capiutil.h>
 #include <linux/isdn/capicmd.h>
 #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
@@ -120,6 +119,15 @@ struct capiminor {
 };
 #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;
@@ -140,7 +148,7 @@ struct capidev {
 
        struct capincci *nccis;
 
-       struct semaphore ncci_list_sem;
+       struct mutex ncci_list_mtx;
 };
 
 /* -------- global variables ---------------------------------------- */
@@ -217,13 +225,12 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
        unsigned int minor = 0;
        unsigned long flags;
 
-       mp = kmalloc(sizeof(*mp), GFP_ATOMIC);
+       mp = kzalloc(sizeof(*mp), GFP_ATOMIC);
        if (!mp) {
                printk(KERN_ERR "capi: can't alloc capiminor\n");
                return NULL;
        }
 
-       memset(mp, 0, sizeof(struct capiminor));
        mp->ap = ap;
        mp->ncci = ncci;
        mp->msgid = 0;
@@ -270,7 +277,7 @@ static void capiminor_free(struct capiminor *mp)
        list_del(&mp->list);
        write_unlock_irqrestore(&capiminor_list_lock, flags);
 
-       if (mp->ttyskb) kfree_skb(mp->ttyskb);
+       kfree_skb(mp->ttyskb);
        mp->ttyskb = NULL;
        skb_queue_purge(&mp->inqueue);
        skb_queue_purge(&mp->outqueue);
@@ -306,10 +313,9 @@ static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci)
        struct capiminor *mp = NULL;
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
-       np = kmalloc(sizeof(*np), GFP_ATOMIC);
+       np = kzalloc(sizeof(*np), GFP_ATOMIC);
        if (!np)
                return NULL;
-       memset(np, 0, sizeof(struct capincci));
        np->ncci = ncci;
        np->cdev = cdev;
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -345,7 +351,7 @@ static void capincci_free(struct capidev *cdev, u32 ncci)
                if (ncci == 0xffffffff || np->ncci == ncci) {
                        *pp = (*pp)->next;
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-                       if ((mp = np->minorp) != 0) {
+                       if ((mp = np->minorp) != NULL) {
 #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
                                capifs_free_ncci(mp->minor);
 #endif
@@ -361,7 +367,7 @@ static void capincci_free(struct capidev *cdev, u32 ncci)
                        }
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
                        kfree(np);
-                       if (*pp == 0) return;
+                       if (*pp == NULL) return;
                } else {
                        pp = &(*pp)->next;
                }
@@ -386,12 +392,11 @@ static struct capidev *capidev_alloc(void)
        struct capidev *cdev;
        unsigned long flags;
 
-       cdev = kmalloc(sizeof(*cdev), GFP_KERNEL);
+       cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
        if (!cdev)
                return NULL;
-       memset(cdev, 0, sizeof(struct capidev));
 
-       init_MUTEX(&cdev->ncci_list_sem);
+       mutex_init(&cdev->ncci_list_mtx);
        skb_queue_head_init(&cdev->recvqueue);
        init_waitqueue_head(&cdev->recvwait);
        write_lock_irqsave(&capidev_list_lock, flags);
@@ -410,9 +415,9 @@ static void capidev_free(struct capidev *cdev)
        }
        skb_queue_purge(&cdev->recvqueue);
 
-       down(&cdev->ncci_list_sem);
+       mutex_lock(&cdev->ncci_list_mtx);
        capincci_free(cdev, 0xffffffff);
-       up(&cdev->ncci_list_sem);
+       mutex_unlock(&cdev->ncci_list_mtx);
 
        write_lock_irqsave(&capidev_list_lock, flags);
        list_del(&cdev->list);
@@ -461,7 +466,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
        ld = tty_ldisc_ref(mp->tty);
        if (ld == NULL)
                return -1;
-       if (ld->receive_buf == NULL) {
+       if (ld->ops->receive_buf == NULL) {
 #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
                printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
 #endif
@@ -479,7 +484,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
 #endif
                goto bad;
        }
-       if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
+       if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) {
                printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
                goto bad;
        }
@@ -496,7 +501,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
        printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
                                datahandle, skb->len);
 #endif
-       ld->receive_buf(mp->tty, skb->data, NULL, skb->len);
+       ld->ops->receive_buf(mp->tty, skb->data, NULL, skb->len);
        kfree_skb(skb);
        tty_ldisc_deref(ld);
        return 0;
@@ -508,7 +513,7 @@ bad:
 static void handle_minor_recv(struct capiminor *mp)
 {
        struct sk_buff *skb;
-       while ((skb = skb_dequeue(&mp->inqueue)) != 0) {
+       while ((skb = skb_dequeue(&mp->inqueue)) != NULL) {
                unsigned int len = skb->len;
                mp->inbytes -= len;
                if (handle_recv_skb(mp, skb) < 0) {
@@ -534,7 +539,7 @@ static int handle_minor_send(struct capiminor *mp)
                return 0;
        }
 
-       while ((skb = skb_dequeue(&mp->outqueue)) != 0) {
+       while ((skb = skb_dequeue(&mp->outqueue)) != NULL) {
                datahandle = mp->datahandle;
                len = (u16)skb->len;
                skb_push(skb, CAPI_DATA_B3_REQ_LEN);
@@ -545,7 +550,7 @@ static int handle_minor_send(struct capiminor *mp)
                capimsg_setu8 (skb->data, 5, CAPI_REQ);
                capimsg_setu16(skb->data, 6, mp->msgid++);
                capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */
-               capimsg_setu32(skb->data, 12, (u32) skb->data); /* Data32 */
+               capimsg_setu32(skb->data, 12, (u32)(long)skb->data);/* Data32 */
                capimsg_setu16(skb->data, 16, len);     /* Data length */
                capimsg_setu16(skb->data, 18, datahandle);
                capimsg_setu16(skb->data, 20, 0);       /* Flags */
@@ -594,23 +599,26 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
 #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
                if (info == 0) {
-                       down(&cdev->ncci_list_sem);
+                       mutex_lock(&cdev->ncci_list_mtx);
                        capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
-                       up(&cdev->ncci_list_sem);
+                       mutex_unlock(&cdev->ncci_list_mtx);
                }
        }
        if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) {
-               down(&cdev->ncci_list_sem);
+               mutex_lock(&cdev->ncci_list_mtx);
                capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
-               up(&cdev->ncci_list_sem);
+               mutex_unlock(&cdev->ncci_list_mtx);
        }
+       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);
@@ -620,6 +628,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
                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
@@ -630,6 +639,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
        if (!mp) {
                skb_queue_tail(&cdev->recvqueue, skb);
                wake_up_interruptible(&cdev->recvwait);
+               spin_unlock_irqrestore(&workaround_lock, flags);
                return;
        }
 
@@ -665,6 +675,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
                wake_up_interruptible(&cdev->recvwait);
        }
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+       spin_unlock_irqrestore(&workaround_lock, flags);
 }
 
 /* -------- file_operations for capidev ----------------------------- */
@@ -679,19 +690,19 @@ capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        if (!cdev->ap.applid)
                return -ENODEV;
 
-       if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) {
+       if ((skb = skb_dequeue(&cdev->recvqueue)) == NULL) {
 
                if (file->f_flags & O_NONBLOCK)
                        return -EAGAIN;
 
                for (;;) {
                        interruptible_sleep_on(&cdev->recvwait);
-                       if ((skb = skb_dequeue(&cdev->recvqueue)) != 0)
+                       if ((skb = skb_dequeue(&cdev->recvqueue)) != NULL)
                                break;
                        if (signal_pending(current))
                                break;
                }
-               if (skb == 0)
+               if (skb == NULL)
                        return -ERESTARTNOHAND;
        }
        if (skb->len > count) {
@@ -742,9 +753,9 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
        CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
 
        if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
-               down(&cdev->ncci_list_sem);
+               mutex_lock(&cdev->ncci_list_mtx);
                capincci_free(cdev, CAPIMSG_NCCI(skb->data));
-               up(&cdev->ncci_list_sem);
+               mutex_unlock(&cdev->ncci_list_mtx);
        }
 
        cdev->errcode = capi20_put_message(&cdev->ap, skb);
@@ -929,17 +940,17 @@ capi_ioctl(struct inode *inode, struct file *file,
                        if (copy_from_user(&ncci, argp, sizeof(ncci)))
                                return -EFAULT;
 
-                       down(&cdev->ncci_list_sem);
-                       if ((nccip = capincci_find(cdev, (u32) ncci)) == 0) {
-                               up(&cdev->ncci_list_sem);
+                       mutex_lock(&cdev->ncci_list_mtx);
+                       if ((nccip = capincci_find(cdev, (u32) ncci)) == NULL) {
+                               mutex_unlock(&cdev->ncci_list_mtx);
                                return 0;
                        }
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-                       if ((mp = nccip->minorp) != 0) {
+                       if ((mp = nccip->minorp) != NULL) {
                                count += atomic_read(&mp->ttyopencount);
                        }
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-                       up(&cdev->ncci_list_sem);
+                       mutex_unlock(&cdev->ncci_list_mtx);
                        return count;
                }
                return 0;
@@ -954,14 +965,14 @@ capi_ioctl(struct inode *inode, struct file *file,
                        if (copy_from_user(&ncci, argp,
                                           sizeof(ncci)))
                                return -EFAULT;
-                       down(&cdev->ncci_list_sem);
+                       mutex_lock(&cdev->ncci_list_mtx);
                        nccip = capincci_find(cdev, (u32) ncci);
-                       if (!nccip || (mp = nccip->minorp) == 0) {
-                               up(&cdev->ncci_list_sem);
+                       if (!nccip || (mp = nccip->minorp) == NULL) {
+                               mutex_unlock(&cdev->ncci_list_mtx);
                                return -ESRCH;
                        }
                        unit = mp->minor;
-                       up(&cdev->ncci_list_sem);
+                       mutex_unlock(&cdev->ncci_list_mtx);
                        return unit;
                }
                return 0;
@@ -973,13 +984,17 @@ capi_ioctl(struct inode *inode, struct file *file,
 static int
 capi_open(struct inode *inode, struct file *file)
 {
+       int ret;
+       
+       lock_kernel();
        if (file->private_data)
-               return -EEXIST;
-
-       if ((file->private_data = capidev_alloc()) == 0)
-               return -ENOMEM;
-
-       return nonseekable_open(inode, file);
+               ret = -EEXIST;
+       else if ((file->private_data = capidev_alloc()) == NULL)
+               ret = -ENOMEM;
+       else
+               ret = nonseekable_open(inode, file);
+       unlock_kernel();
+       return ret;
 }
 
 static int
@@ -993,7 +1008,7 @@ capi_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static struct file_operations capi_fops =
+static const struct file_operations capi_fops =
 {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
@@ -1011,14 +1026,16 @@ static struct file_operations capi_fops =
 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_dentry->d_inode))) == 0)
+       if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == NULL)
                return -ENXIO;
-       if (mp->nccip == 0)
+       if (mp->nccip == NULL)
                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);
@@ -1026,6 +1043,7 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file)
        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;
 }
 
@@ -1045,7 +1063,7 @@ static void capinc_tty_close(struct tty_struct * tty, struct file * file)
 #ifdef _DEBUG_REFCOUNT
                printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));
 #endif
-               if (mp->nccip == 0)
+               if (mp->nccip == NULL)
                        capiminor_free(mp);
        }
 
@@ -1059,6 +1077,7 @@ static int capinc_tty_write(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_write(count=%d)\n", count);
@@ -1071,6 +1090,7 @@ static int capinc_tty_write(struct tty_struct * tty,
                return 0;
        }
 
+       spin_lock_irqsave(&workaround_lock, flags);
        skb = mp->ttyskb;
        if (skb) {
                mp->ttyskb = NULL;
@@ -1081,6 +1101,7 @@ static int capinc_tty_write(struct tty_struct * tty,
        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;
        }
 
@@ -1091,13 +1112,16 @@ static int capinc_tty_write(struct tty_struct * tty,
        mp->outbytes += skb->len;
        (void)handle_minor_send(mp);
        (void)handle_minor_recv(mp);
+       spin_unlock_irqrestore(&workaround_lock, flags);
        return count;
 }
 
-static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
+static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
 {
        struct capiminor *mp = (struct capiminor *)tty->driver_data;
        struct sk_buff *skb;
+       unsigned long flags;
+       int ret = 1;
 
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
@@ -1107,14 +1131,16 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
 #ifdef _DEBUG_TTYFUNCS
                printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
 #endif
-               return;
+               return 0;
        }
 
+       spin_lock_irqsave(&workaround_lock, flags);
        skb = mp->ttyskb;
        if (skb) {
                if (skb_tailroom(skb) > 0) {
                        *(skb_put(skb, 1)) = ch;
-                       return;
+                       spin_unlock_irqrestore(&workaround_lock, flags);
+                       return 1;
                }
                mp->ttyskb = NULL;
                skb_queue_tail(&mp->outqueue, skb);
@@ -1128,13 +1154,17 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
                mp->ttyskb = skb;
        } else {
                printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
+               ret = 0;
        }
+       spin_unlock_irqrestore(&workaround_lock, flags);
+       return ret;
 }
 
 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");
@@ -1147,6 +1177,7 @@ static void capinc_tty_flush_chars(struct tty_struct *tty)
                return;
        }
 
+       spin_lock_irqsave(&workaround_lock, flags);
        skb = mp->ttyskb;
        if (skb) {
                mp->ttyskb = NULL;
@@ -1155,6 +1186,7 @@ static void capinc_tty_flush_chars(struct tty_struct *tty)
                (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)
@@ -1199,13 +1231,13 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
        int error = 0;
        switch (cmd) {
        default:
-               error = n_tty_ioctl (tty, file, cmd, arg);
+               error = n_tty_ioctl_helper(tty, file, cmd, arg);
                break;
        }
        return error;
 }
 
-static void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
+static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old)
 {
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_set_termios\n");
@@ -1225,12 +1257,15 @@ static void capinc_tty_throttle(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);
        }
 }
 
@@ -1248,12 +1283,15 @@ static void capinc_tty_stop(struct tty_struct *tty)
 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);
        }
 }
 
@@ -1264,11 +1302,12 @@ static void capinc_tty_hangup(struct tty_struct *tty)
 #endif
 }
 
-static void capinc_tty_break_ctl(struct tty_struct *tty, int state)
+static int capinc_tty_break_ctl(struct tty_struct *tty, int state)
 {
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state);
 #endif
+       return 0;
 }
 
 static void capinc_tty_flush_buffer(struct tty_struct *tty)
@@ -1292,15 +1331,9 @@ static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
 #endif
 }
 
-static int capinc_tty_read_proc(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return 0;
-}
-
 static struct tty_driver *capinc_tty_driver;
 
-static struct tty_operations capinc_ops = {
+static const struct tty_operations capinc_ops = {
        .open = capinc_tty_open,
        .close = capinc_tty_close,
        .write = capinc_tty_write,
@@ -1319,7 +1352,6 @@ static struct tty_operations capinc_ops = {
        .flush_buffer = capinc_tty_flush_buffer,
        .set_ldisc = capinc_tty_set_ldisc,
        .send_xchar = capinc_tty_send_xchar,
-       .read_proc = capinc_tty_read_proc,
 };
 
 static int capinc_tty_init(void)
@@ -1337,7 +1369,6 @@ static int capinc_tty_init(void)
 
        drv->owner = THIS_MODULE;
        drv->driver_name = "capi_nc";
-       drv->devfs_name = "capi/";
        drv->name = "capi";
        drv->major = capi_ttymajor;
        drv->minor_start = 0;
@@ -1462,7 +1493,7 @@ static struct procfsentries {
 
 static void __init proc_init(void)
 {
-    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+    int nelem = ARRAY_SIZE(procfsentries);
     int i;
 
     for (i=0; i < nelem; i++) {
@@ -1474,7 +1505,7 @@ static void __init proc_init(void)
 
 static void __exit proc_exit(void)
 {
-    int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+    int nelem = ARRAY_SIZE(procfsentries);
     int i;
 
     for (i=nelem-1; i >= 0; i--) {
@@ -1497,9 +1528,9 @@ static int __init capi_init(void)
        char *compileinfo;
        int major_ret;
 
-       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");
@@ -1515,11 +1546,11 @@ static int __init capi_init(void)
                return PTR_ERR(capi_class);
        }
 
-       class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
+       device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
        if (capinc_tty_init() < 0) {
-               class_device_destroy(capi_class, MKDEV(capi_major, 0));
+               device_destroy(capi_class, MKDEV(capi_major, 0));
                class_destroy(capi_class);
                unregister_chrdev(capi_major, "capi20");
                return -ENOMEM;
@@ -1547,7 +1578,7 @@ static void __exit capi_exit(void)
 {
        proc_exit();
 
-       class_device_destroy(capi_class, MKDEV(capi_major, 0));
+       device_destroy(capi_class, MKDEV(capi_major, 0));
        class_destroy(capi_class);
        unregister_chrdev(capi_major, "capi20");