CAPI: Rework capiminor RX handler
[safe/jmp/linux-2.6] / drivers / isdn / capi / capi.c
index b1de0cb..c5c54fa 100644 (file)
@@ -45,7 +45,6 @@ MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");
 MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
 
-#undef _DEBUG_REFCOUNT         /* alloc/free and open/close debug */
 #undef _DEBUG_TTYFUNCS         /* call to tty_driver */
 #undef _DEBUG_DATAFLOW         /* data flow */
 
@@ -83,7 +82,8 @@ struct datahandle_queue {
 };
 
 struct capiminor {
-       struct capincci  *nccip;
+       struct kref kref;
+
        unsigned int      minor;
        struct dentry *capifs_dentry;
 
@@ -92,11 +92,10 @@ struct capiminor {
        u16              datahandle;
        u16              msgid;
 
-       struct tty_struct *tty;
+       struct tty_port port;
        int                ttyinstop;
        int                ttyoutstop;
        struct sk_buff    *ttyskb;
-       atomic_t           ttyopencount;
 
        struct sk_buff_head inqueue;
        int                 inbytes;
@@ -148,7 +147,7 @@ static LIST_HEAD(capidev_list);
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 
-static DEFINE_RWLOCK(capiminors_lock);
+static DEFINE_SPINLOCK(capiminors_lock);
 static struct capiminor **capiminors;
 
 static struct tty_driver *capinc_tty_driver;
@@ -210,12 +209,13 @@ static void capiminor_del_all_ack(struct capiminor *mp)
 
 /* -------- struct capiminor ---------------------------------------- */
 
+static const struct tty_port_operations capiminor_port_ops; /* we have none */
+
 static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
 {
        struct capiminor *mp;
        struct device *dev;
        unsigned int minor;
-       unsigned long flags;
 
        mp = kzalloc(sizeof(*mp), GFP_KERNEL);
        if (!mp) {
@@ -223,24 +223,28 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
                return NULL;
        }
 
+       kref_init(&mp->kref);
+
        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);
 
+       tty_port_init(&mp->port);
+       mp->port.ops = &capiminor_port_ops;
+
        /* Allocate the least unused minor number. */
-       write_lock_irqsave(&capiminors_lock, flags);
+       spin_lock(&capiminors_lock);
        for (minor = 0; minor < capi_ttyminors; minor++)
                if (!capiminors[minor]) {
                        capiminors[minor] = mp;
                        break;
                }
-       write_unlock_irqrestore(&capiminors_lock, flags);
+       spin_unlock(&capiminors_lock);
 
        if (minor == capi_ttyminors) {
                printk(KERN_NOTICE "capi: out of minors\n");
@@ -256,27 +260,20 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
        return mp;
 
 err_out2:
-       write_lock_irqsave(&capiminors_lock, flags);
+       spin_lock(&capiminors_lock);
        capiminors[minor] = NULL;
-       write_unlock_irqrestore(&capiminors_lock, flags);
+       spin_unlock(&capiminors_lock);
 
 err_out1:
        kfree(mp);
        return NULL;
 }
 
-static void capiminor_free(struct capiminor *mp)
+static void capiminor_destroy(struct kref *kref)
 {
-       unsigned long flags;
-
-       tty_unregister_device(capinc_tty_driver, mp->minor);
-
-       write_lock_irqsave(&capiminors_lock, flags);
-       capiminors[mp->minor] = NULL;
-       write_unlock_irqrestore(&capiminors_lock, flags);
+       struct capiminor *mp = container_of(kref, struct capiminor, kref);
 
        kfree_skb(mp->ttyskb);
-       mp->ttyskb = NULL;
        skb_queue_purge(&mp->inqueue);
        skb_queue_purge(&mp->outqueue);
        capiminor_del_all_ack(mp);
@@ -287,13 +284,31 @@ static struct capiminor *capiminor_get(unsigned int minor)
 {
        struct capiminor *mp;
 
-       read_lock(&capiminors_lock);
+       spin_lock(&capiminors_lock);
        mp = capiminors[minor];
-       read_unlock(&capiminors_lock);
+       if (mp)
+               kref_get(&mp->kref);
+       spin_unlock(&capiminors_lock);
 
        return mp;
 }
 
+static inline void capiminor_put(struct capiminor *mp)
+{
+       kref_put(&mp->kref, capiminor_destroy);
+}
+
+static void capiminor_free(struct capiminor *mp)
+{
+       tty_unregister_device(capinc_tty_driver, mp->minor);
+
+       spin_lock(&capiminors_lock);
+       capiminors[mp->minor] = NULL;
+       spin_unlock(&capiminors_lock);
+
+       capiminor_put(mp);
+}
+
 /* -------- struct capincci ----------------------------------------- */
 
 static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np)
@@ -306,10 +321,6 @@ static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np)
 
        mp = np->minorp = capiminor_alloc(&cdev->ap, np->ncci);
        if (mp) {
-               mp->nccip = np;
-#ifdef _DEBUG_REFCOUNT
-               printk(KERN_DEBUG "set mp->nccip\n");
-#endif
                device = MKDEV(capinc_tty_driver->major, mp->minor);
                mp->capifs_dentry = capifs_new_ncci(mp->minor, device);
        }
@@ -318,26 +329,35 @@ static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np)
 static void capincci_free_minor(struct capincci *np)
 {
        struct capiminor *mp = np->minorp;
+       struct tty_struct *tty;
 
        if (mp) {
                capifs_free_ncci(mp->capifs_dentry);
-               if (mp->tty) {
-                       mp->nccip = NULL;
-#ifdef _DEBUG_REFCOUNT
-                       printk(KERN_DEBUG "reset mp->nccip\n");
-#endif
-                       tty_hangup(mp->tty);
-               } else {
-                       capiminor_free(mp);
+
+               tty = tty_port_tty_get(&mp->port);
+               if (tty) {
+                       tty_vhangup(tty);
+                       tty_kref_put(tty);
                }
+
+               capiminor_free(mp);
        }
 }
 
 static inline unsigned int capincci_minor_opencount(struct capincci *np)
 {
        struct capiminor *mp = np->minorp;
+       unsigned int count = 0;
+       struct tty_struct *tty;
 
-       return mp ? atomic_read(&mp->ttyopencount) : 0;
+       if (mp) {
+               tty = tty_port_tty_get(&mp->port);
+               if (tty) {
+                       count = tty->count;
+                       tty_kref_put(tty);
+               }
+       }
+       return count;
 }
 
 #else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */
@@ -416,65 +436,86 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
 
 static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
 {
+       unsigned int datalen = skb->len - CAPIMSG_LEN(skb->data);
+       struct tty_struct *tty;
        struct sk_buff *nskb;
-       int datalen;
        u16 errcode, datahandle;
        struct tty_ldisc *ld;
-       
-       datalen = skb->len - CAPIMSG_LEN(skb->data);
-       if (mp->tty == NULL)
-       {
+       int ret = -1;
+
+       tty = tty_port_tty_get(&mp->port);
+       if (!tty) {
 #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;
+       ld = tty_ldisc_ref(tty);
+       if (!ld) {
+               /* fatal error, do not requeue */
+               ret = 0;
+               kfree_skb(skb);
+               goto deref_tty;
+       }
+
        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
-               goto bad;
+               /* fatal error, do not requeue */
+               goto free_skb;
        }
        if (mp->ttyinstop) {
 #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
                printk(KERN_DEBUG "capi: recv tty throttled\n");
 #endif
-               goto bad;
+               goto deref_ldisc;
        }
-       if (mp->tty->receive_room < datalen) {
+
+       if (tty->receive_room < datalen) {
 #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
                printk(KERN_DEBUG "capi: no room in tty\n");
 #endif
-               goto bad;
+               goto deref_ldisc;
        }
-       if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) {
+
+       nskb = gen_data_b3_resp_for(mp, skb);
+       if (!nskb) {
                printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
-               goto bad;
+               goto deref_ldisc;
        }
-       datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+
+       datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4);
+
        errcode = capi20_put_message(mp->ap, nskb);
-       if (errcode != CAPI_NOERROR) {
+
+       if (errcode == CAPI_NOERROR) {
+               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);
+#endif
+               ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
+       } else {
                printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
                                errcode);
                kfree_skb(nskb);
-               goto bad;
+
+               if (errcode == CAPI_SENDQUEUEFULL)
+                       goto deref_ldisc;
        }
-       (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);
-#endif
-       ld->ops->receive_buf(mp->tty, skb->data, NULL, skb->len);
+
+free_skb:
+       ret = 0;
        kfree_skb(skb);
+
+deref_ldisc:
        tty_ldisc_deref(ld);
-       return 0;
-bad:
-       tty_ldisc_deref(ld);
-       return -1;
+
+deref_tty:
+       tty_kref_put(tty);
+       return ret;
 }
 
 static void handle_minor_recv(struct capiminor *mp)
@@ -493,16 +534,22 @@ static void handle_minor_recv(struct capiminor *mp)
 
 static int handle_minor_send(struct capiminor *mp)
 {
+       struct tty_struct *tty;
        struct sk_buff *skb;
        u16 len;
        int count = 0;
        u16 errcode;
        u16 datahandle;
 
-       if (mp->tty && mp->ttyoutstop) {
+       tty = tty_port_tty_get(&mp->port);
+       if (!tty)
+               return 0;
+
+       if (mp->ttyoutstop) {
 #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
                printk(KERN_DEBUG "capi: send: tty stopped\n");
 #endif
+               tty_kref_put(tty);
                return 0;
        }
 
@@ -525,6 +572,7 @@ static int handle_minor_send(struct capiminor *mp)
                if (capiminor_add_ack(mp, datahandle) < 0) {
                        skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
                        skb_queue_head(&mp->outqueue, skb);
+                       tty_kref_put(tty);
                        return count;
                }
                errcode = capi20_put_message(mp->ap, skb);
@@ -551,6 +599,7 @@ static int handle_minor_send(struct capiminor *mp)
                mp->outbytes -= len;
                kfree_skb(skb);
        }
+       tty_kref_put(tty);
        return count;
 }
 
@@ -561,6 +610,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
 {
        struct capidev *cdev = ap->private;
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+       struct tty_struct *tty;
        struct capiminor *mp;
        u16 datahandle;
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
@@ -624,8 +674,11 @@ 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)
-                       tty_wakeup(mp->tty);
+               tty = tty_port_tty_get(&mp->port);
+               if (tty) {
+                       tty_wakeup(tty);
+                       tty_kref_put(tty);
+               }
                (void)handle_minor_send(mp);
 
        } else {
@@ -988,58 +1041,57 @@ static const struct file_operations capi_fops =
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 /* -------- tty_operations for capincci ----------------------------- */
 
-static int capinc_tty_open(struct tty_struct * tty, struct file * file)
+static int
+capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-       struct capiminor *mp;
-       unsigned long flags;
+       int idx = tty->index;
+       struct capiminor *mp = capiminor_get(idx);
+       int ret = tty_init_termios(tty);
+
+       if (ret == 0) {
+               tty_driver_kref_get(driver);
+               tty->count++;
+               tty->driver_data = mp;
+               driver->ttys[idx] = tty;
+       } else
+               capiminor_put(mp);
+       return ret;
+}
 
-       mp = capiminor_get(iminor(file->f_path.dentry->d_inode));
-       if (mp->nccip == NULL)
-               return -ENXIO;
+static void capinc_tty_cleanup(struct tty_struct *tty)
+{
+       struct capiminor *mp = tty->driver_data;
+       tty->driver_data = NULL;
+       capiminor_put(mp);
+}
 
-       tty->driver_data = (void *)mp;
+static int capinc_tty_open(struct tty_struct *tty, struct file *filp)
+{
+       struct capiminor *mp = tty->driver_data;
+       unsigned long flags;
+       int err;
+
+       err = tty_port_open(&mp->port, tty, filp);
+       if (err)
+               return err;
 
        spin_lock_irqsave(&workaround_lock, flags);
-       if (atomic_read(&mp->ttyopencount) == 0)
-               mp->tty = tty;
-       atomic_inc(&mp->ttyopencount);
-#ifdef _DEBUG_REFCOUNT
-       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;
 }
 
-static void capinc_tty_close(struct tty_struct * tty, struct file * file)
+static void capinc_tty_close(struct tty_struct *tty, struct file *filp)
 {
-       struct capiminor *mp;
+       struct capiminor *mp = tty->driver_data;
 
-       mp = (struct capiminor *)tty->driver_data;
-       if (mp) {
-               if (atomic_dec_and_test(&mp->ttyopencount)) {
-#ifdef _DEBUG_REFCOUNT
-                       printk(KERN_DEBUG "capinc_tty_close lastclose\n");
-#endif
-                       tty->driver_data = NULL;
-                       mp->tty = NULL;
-               }
-#ifdef _DEBUG_REFCOUNT
-               printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));
-#endif
-               if (mp->nccip == NULL)
-                       capiminor_free(mp);
-       }
-
-#ifdef _DEBUG_REFCOUNT
-       printk(KERN_DEBUG "capinc_tty_close\n");
-#endif
+       tty_port_close(&mp->port, tty, filp);
 }
 
-static int capinc_tty_write(struct tty_struct * tty,
+static int capinc_tty_write(struct tty_struct *tty,
                            const unsigned char *buf, int count)
 {
-       struct capiminor *mp = (struct capiminor *)tty->driver_data;
+       struct capiminor *mp = tty->driver_data;
        struct sk_buff *skb;
        unsigned long flags;
 
@@ -1047,13 +1099,6 @@ static int capinc_tty_write(struct tty_struct * tty,
        printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count);
 #endif
 
-       if (!mp || !mp->nccip) {
-#ifdef _DEBUG_TTYFUNCS
-               printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n");
-#endif
-               return 0;
-       }
-
        spin_lock_irqsave(&workaround_lock, flags);
        skb = mp->ttyskb;
        if (skb) {
@@ -1075,14 +1120,13 @@ static int capinc_tty_write(struct tty_struct * tty,
        skb_queue_tail(&mp->outqueue, skb);
        mp->outbytes += skb->len;
        (void)handle_minor_send(mp);
-       (void)handle_minor_recv(mp);
        spin_unlock_irqrestore(&workaround_lock, flags);
        return count;
 }
 
 static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct capiminor *mp = (struct capiminor *)tty->driver_data;
+       struct capiminor *mp = tty->driver_data;
        struct sk_buff *skb;
        unsigned long flags;
        int ret = 1;
@@ -1091,13 +1135,6 @@ static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
        printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
 #endif
 
-       if (!mp || !mp->nccip) {
-#ifdef _DEBUG_TTYFUNCS
-               printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
-#endif
-               return 0;
-       }
-
        spin_lock_irqsave(&workaround_lock, flags);
        skb = mp->ttyskb;
        if (skb) {
@@ -1126,7 +1163,7 @@ static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
 
 static void capinc_tty_flush_chars(struct tty_struct *tty)
 {
-       struct capiminor *mp = (struct capiminor *)tty->driver_data;
+       struct capiminor *mp = tty->driver_data;
        struct sk_buff *skb;
        unsigned long flags;
 
@@ -1134,13 +1171,6 @@ static void capinc_tty_flush_chars(struct tty_struct *tty)
        printk(KERN_DEBUG "capinc_tty_flush_chars\n");
 #endif
 
-       if (!mp || !mp->nccip) {
-#ifdef _DEBUG_TTYFUNCS
-               printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n");
-#endif
-               return;
-       }
-
        spin_lock_irqsave(&workaround_lock, flags);
        skb = mp->ttyskb;
        if (skb) {
@@ -1155,14 +1185,9 @@ static void capinc_tty_flush_chars(struct tty_struct *tty)
 
 static int capinc_tty_write_room(struct tty_struct *tty)
 {
-       struct capiminor *mp = (struct capiminor *)tty->driver_data;
+       struct capiminor *mp = tty->driver_data;
        int room;
-       if (!mp || !mp->nccip) {
-#ifdef _DEBUG_TTYFUNCS
-               printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n");
-#endif
-               return 0;
-       }
+
        room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
        room *= CAPI_MAX_BLKSIZE;
 #ifdef _DEBUG_TTYFUNCS
@@ -1173,13 +1198,8 @@ static int capinc_tty_write_room(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) {
-#ifdef _DEBUG_TTYFUNCS
-               printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n");
-#endif
-               return 0;
-       }
+       struct capiminor *mp = tty->driver_data;
+
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
                        mp->outbytes, mp->nack,
@@ -1208,62 +1228,61 @@ static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old
 #endif
 }
 
-static void capinc_tty_throttle(struct tty_struct * tty)
+static void capinc_tty_throttle(struct tty_struct *tty)
 {
-       struct capiminor *mp = (struct capiminor *)tty->driver_data;
+       struct capiminor *mp = tty->driver_data;
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_throttle\n");
 #endif
-       if (mp)
-               mp->ttyinstop = 1;
+       mp->ttyinstop = 1;
 }
 
-static void capinc_tty_unthrottle(struct tty_struct * tty)
+static void capinc_tty_unthrottle(struct tty_struct *tty)
 {
-       struct capiminor *mp = (struct capiminor *)tty->driver_data;
+       struct capiminor *mp = 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);
-       }
+       spin_lock_irqsave(&workaround_lock, flags);
+       mp->ttyinstop = 0;
+       handle_minor_recv(mp);
+       spin_unlock_irqrestore(&workaround_lock, flags);
 }
 
 static void capinc_tty_stop(struct tty_struct *tty)
 {
-       struct capiminor *mp = (struct capiminor *)tty->driver_data;
+       struct capiminor *mp = tty->driver_data;
+
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_stop\n");
 #endif
-       if (mp) {
-               mp->ttyoutstop = 1;
-       }
+       mp->ttyoutstop = 1;
 }
 
 static void capinc_tty_start(struct tty_struct *tty)
 {
-       struct capiminor *mp = (struct capiminor *)tty->driver_data;
+       struct capiminor *mp = 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);
-       }
+       spin_lock_irqsave(&workaround_lock, flags);
+       mp->ttyoutstop = 0;
+       (void)handle_minor_send(mp);
+       spin_unlock_irqrestore(&workaround_lock, flags);
 }
 
 static void capinc_tty_hangup(struct tty_struct *tty)
 {
+       struct capiminor *mp = tty->driver_data;
+
 #ifdef _DEBUG_TTYFUNCS
        printk(KERN_DEBUG "capinc_tty_hangup\n");
 #endif
+       tty_port_hangup(&mp->port);
 }
 
 static int capinc_tty_break_ctl(struct tty_struct *tty, int state)
@@ -1314,6 +1333,8 @@ static const struct tty_operations capinc_ops = {
        .flush_buffer = capinc_tty_flush_buffer,
        .set_ldisc = capinc_tty_set_ldisc,
        .send_xchar = capinc_tty_send_xchar,
+       .install = capinc_tty_install,
+       .cleanup = capinc_tty_cleanup,
 };
 
 static int __init capinc_tty_init(void)