fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / isdn / capi / capi.c
index 3429d57..d22c022 100644 (file)
@@ -9,7 +9,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -38,7 +37,7 @@
 #include <linux/kernelcapi.h>
 #include <linux/init.h>
 #include <linux/device.h>
-#include <linux/devfs_fs_kernel.h>
+#include <linux/moduleparam.h>
 #include <linux/isdn/capiutil.h>
 #include <linux/isdn/capicmd.h>
 #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
@@ -57,20 +56,20 @@ MODULE_LICENSE("GPL");
 
 /* -------- driver information -------------------------------------- */
 
-static struct class_simple *capi_class;
+static struct class *capi_class;
 
-int capi_major = 68;           /* allocated */
+static int capi_major = 68;            /* allocated */
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 #define CAPINC_NR_PORTS        32
 #define CAPINC_MAX_PORTS       256
-int capi_ttymajor = 191;
-int capi_ttyminors = CAPINC_NR_PORTS;
+static int capi_ttymajor = 191;
+static int capi_ttyminors = CAPINC_NR_PORTS;
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
-MODULE_PARM(capi_major, "i");
+module_param_named(major, capi_major, uint, 0);
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-MODULE_PARM(capi_ttymajor, "i");
-MODULE_PARM(capi_ttyminors, "i");
+module_param_named(ttymajor, capi_ttymajor, uint, 0);
+module_param_named(ttyminors, capi_ttyminors, uint, 0);
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
 /* -------- defines ------------------------------------------------- */
@@ -86,6 +85,11 @@ struct capincci;
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 struct capiminor;
 
+struct datahandle_queue {
+       struct list_head        list;
+       u16                     datahandle;
+};
+
 struct capiminor {
        struct list_head list;
        struct capincci  *nccip;
@@ -108,12 +112,9 @@ struct capiminor {
        int                 outbytes;
 
        /* transmit path */
-       struct datahandle_queue {
-                   struct datahandle_queue *next;
-                   u16                    datahandle;
-       } *ackqueue;
+       struct list_head ackqueue;
        int nack;
-
+       spinlock_t ackqlock;
 };
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
@@ -142,11 +143,11 @@ struct capidev {
 
 /* -------- global variables ---------------------------------------- */
 
-static rwlock_t capidev_list_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(capidev_list_lock);
 static LIST_HEAD(capidev_list);
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-static rwlock_t capiminor_list_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(capiminor_list_lock);
 static LIST_HEAD(capiminor_list);
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
@@ -155,48 +156,54 @@ static LIST_HEAD(capiminor_list);
 
 static int capincci_add_ack(struct capiminor *mp, u16 datahandle)
 {
-       struct datahandle_queue *n, **pp;
+       struct datahandle_queue *n;
+       unsigned long flags;
 
        n = kmalloc(sizeof(*n), GFP_ATOMIC);
-       if (!n) {
-          printk(KERN_ERR "capi: alloc datahandle failed\n");
-          return -1;
+       if (unlikely(!n)) {
+               printk(KERN_ERR "capi: alloc datahandle failed\n");
+               return -1;
        }
-       n->next = NULL;
        n->datahandle = datahandle;
-       for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ;
-       *pp = n;
+       INIT_LIST_HEAD(&n->list);
+       spin_lock_irqsave(&mp->ackqlock, flags);
+       list_add_tail(&n->list, &mp->ackqueue);
        mp->nack++;
+       spin_unlock_irqrestore(&mp->ackqlock, flags);
        return 0;
 }
 
 static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
 {
-       struct datahandle_queue **pp, *p;
+       struct datahandle_queue *p, *tmp;
+       unsigned long flags;
 
-       for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
-               if ((*pp)->datahandle == datahandle) {
-                       p = *pp;
-                       *pp = (*pp)->next;
+       spin_lock_irqsave(&mp->ackqlock, flags);
+       list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
+               if (p->datahandle == datahandle) {
+                       list_del(&p->list);
                        kfree(p);
                        mp->nack--;
+                       spin_unlock_irqrestore(&mp->ackqlock, flags);
                        return 0;
                }
        }
+       spin_unlock_irqrestore(&mp->ackqlock, flags);
        return -1;
 }
 
 static void capiminor_del_all_ack(struct capiminor *mp)
 {
-       struct datahandle_queue **pp, *p;
+       struct datahandle_queue *p, *tmp;
+       unsigned long flags;
 
-       pp = &mp->ackqueue;
-       while (*pp) {
-               p = *pp;
-               *pp = (*pp)->next;
+       spin_lock_irqsave(&mp->ackqlock, flags);
+       list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
+               list_del(&p->list);
                kfree(p);
                mp->nack--;
        }
+       spin_unlock_irqrestore(&mp->ackqlock, flags);
 }
 
 
@@ -208,17 +215,18 @@ 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;
        atomic_set(&mp->ttyopencount,0);
+       INIT_LIST_HEAD(&mp->ackqueue);
+       spin_lock_init(&mp->ackqlock);
 
        skb_queue_head_init(&mp->inqueue);
        skb_queue_head_init(&mp->outqueue);
@@ -267,7 +275,7 @@ static void capiminor_free(struct capiminor *mp)
        kfree(mp);
 }
 
-struct capiminor *capiminor_find(unsigned int minor)
+static struct capiminor *capiminor_find(unsigned int minor)
 {
        struct list_head *l;
        struct capiminor *p = NULL;
@@ -295,10 +303,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
@@ -375,10 +382,9 @@ 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);
        skb_queue_head_init(&cdev->recvqueue);
@@ -436,51 +442,61 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
        struct sk_buff *nskb;
        int datalen;
        u16 errcode, datahandle;
-
+       struct tty_ldisc *ld;
+       
        datalen = skb->len - CAPIMSG_LEN(skb->data);
-       if (mp->tty) {
-               if (mp->tty->ldisc.receive_buf == 0) {
-                       printk(KERN_ERR "capi: ldisc has no receive_buf function\n");
-                       return -1;
-               }
-               if (mp->ttyinstop) {
+       if (mp->tty == NULL)
+       {
+#ifdef _DEBUG_DATAFLOW
+               printk(KERN_DEBUG "capi: currently no receiver\n");
+#endif
+               return -1;
+       }
+       
+       ld = tty_ldisc_ref(mp->tty);
+       if (ld == NULL)
+               return -1;
+       if (ld->receive_buf == NULL) {
 #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
-                       printk(KERN_DEBUG "capi: recv tty throttled\n");
+               printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
 #endif
-                       return -1;
-               }
-               if (mp->tty->ldisc.receive_room &&
-                   mp->tty->ldisc.receive_room(mp->tty) < datalen) {
+               goto bad;
+       }
+       if (mp->ttyinstop) {
 #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
-                       printk(KERN_DEBUG "capi: no room in tty\n");
+               printk(KERN_DEBUG "capi: recv tty throttled\n");
 #endif
-                       return -1;
-               }
-               if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
-                       printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
-                       return -1;
-               }
-               datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
-               errcode = capi20_put_message(mp->ap, nskb);
-               if (errcode != CAPI_NOERROR) {
-                       printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
-                                       errcode);
-                       kfree_skb(nskb);
-                       return -1;
-               }
-               (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
-#ifdef _DEBUG_DATAFLOW
-               printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
-                                       datahandle, skb->len);
+               goto bad;
+       }
+       if (mp->tty->receive_room < datalen) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+               printk(KERN_DEBUG "capi: no room in tty\n");
 #endif
-               mp->tty->ldisc.receive_buf(mp->tty, skb->data, NULL, skb->len);
-               kfree_skb(skb);
-               return 0;
-
+               goto bad;
        }
+       if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
+               printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
+               goto bad;
+       }
+       datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+       errcode = capi20_put_message(mp->ap, nskb);
+       if (errcode != CAPI_NOERROR) {
+               printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
+                               errcode);
+               kfree_skb(nskb);
+               goto bad;
+       }
+       (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
 #ifdef _DEBUG_DATAFLOW
-       printk(KERN_DEBUG "capi: currently no receiver\n");
+       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);
+       kfree_skb(skb);
+       tty_ldisc_deref(ld);
+       return 0;
+bad:
+       tty_ldisc_deref(ld);
        return -1;
 }
 
@@ -614,6 +630,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
 
 
        if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
+               
                datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
 #ifdef _DEBUG_DATAFLOW
                printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n",
@@ -633,10 +650,8 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
 #endif
                kfree_skb(skb);
                (void)capiminor_del_ack(mp, datahandle);
-               if (mp->tty) {
-                       if (mp->tty->ldisc.write_wakeup)
-                               mp->tty->ldisc.write_wakeup(mp->tty);
-               }
+               if (mp->tty)
+                       tty_wakeup(mp->tty);
                (void)handle_minor_send(mp);
 
        } else {
@@ -992,7 +1007,7 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file)
 {
        struct capiminor *mp;
 
-       if ((mp = capiminor_find(iminor(file->f_dentry->d_inode))) == 0)
+       if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == 0)
                return -ENXIO;
        if (mp->nccip == 0)
                return -ENXIO;
@@ -1034,16 +1049,14 @@ static void capinc_tty_close(struct tty_struct * tty, struct file * file)
 #endif
 }
 
-static int capinc_tty_write(struct tty_struct * tty, int from_user,
+static int capinc_tty_write(struct tty_struct * tty,
                            const unsigned char *buf, int count)
 {
        struct capiminor *mp = (struct capiminor *)tty->driver_data;
        struct sk_buff *skb;
-       int retval;
 
 #ifdef _DEBUG_TTYFUNCS
-       printk(KERN_DEBUG "capinc_tty_write(from_user=%d,count=%d)\n",
-                               from_user, count);
+       printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count);
 #endif
 
        if (!mp || !mp->nccip) {
@@ -1067,18 +1080,7 @@ static int capinc_tty_write(struct tty_struct * tty, int from_user,
        }
 
        skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
-       if (from_user) {
-               retval = copy_from_user(skb_put(skb, count), buf, count);
-               if (retval) {
-                       kfree_skb(skb);
-#ifdef _DEBUG_TTYFUNCS
-                       printk(KERN_DEBUG "capinc_tty_write: copy_from_user=%d\n", retval);
-#endif
-                       return -EFAULT;
-               }
-       } else {
-               memcpy(skb_put(skb, count), buf, count);
-       }
+       memcpy(skb_put(skb, count), buf, count);
 
        skb_queue_tail(&mp->outqueue, skb);
        mp->outbytes += skb->len;
@@ -1168,7 +1170,7 @@ static int capinc_tty_write_room(struct tty_struct *tty)
        return room;
 }
 
-int capinc_tty_chars_in_buffer(struct tty_struct *tty)
+static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
 {
        struct capiminor *mp = (struct capiminor *)tty->driver_data;
        if (!mp || !mp->nccip) {
@@ -1198,7 +1200,7 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
        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");
@@ -1293,7 +1295,7 @@ static int capinc_tty_read_proc(char *page, char **start, off_t off,
 
 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,
@@ -1330,7 +1332,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;
@@ -1488,6 +1489,7 @@ static int __init capi_init(void)
 {
        char *p;
        char *compileinfo;
+       int major_ret;
 
        if ((p = strchr(revision, ':')) != 0 && p[1]) {
                strlcpy(rev, p + 2, sizeof(rev));
@@ -1496,25 +1498,23 @@ static int __init capi_init(void)
        } else
                strcpy(rev, "1.0");
 
-       if (register_chrdev(capi_major, "capi20", &capi_fops)) {
+       major_ret = register_chrdev(capi_major, "capi20", &capi_fops);
+       if (major_ret < 0) {
                printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
-               return -EIO;
+               return major_ret;
        }
-
-       capi_class = class_simple_create(THIS_MODULE, "capi");
+       capi_class = class_create(THIS_MODULE, "capi");
        if (IS_ERR(capi_class)) {
                unregister_chrdev(capi_major, "capi20");
                return PTR_ERR(capi_class);
        }
 
-       class_simple_device_add(capi_class, MKDEV(capi_major, 0), NULL, "capi");
-       devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR,
-                       "isdn/capi20");
+       class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
        if (capinc_tty_init() < 0) {
-               class_simple_device_remove(MKDEV(capi_major, 0));
-               class_simple_destroy(capi_class);
+               class_device_destroy(capi_class, MKDEV(capi_major, 0));
+               class_destroy(capi_class);
                unregister_chrdev(capi_major, "capi20");
                return -ENOMEM;
        }
@@ -1541,10 +1541,9 @@ static void __exit capi_exit(void)
 {
        proc_exit();
 
-       class_simple_device_remove(MKDEV(capi_major, 0));
-       class_simple_destroy(capi_class);
+       class_device_destroy(capi_class, MKDEV(capi_major, 0));
+       class_destroy(capi_class);
        unregister_chrdev(capi_major, "capi20");
-       devfs_remove("isdn/capi20");
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
        capinc_tty_exit();