Commit fb4b4881 authored by Jan Kiszka's avatar Jan Kiszka Committed by David S. Miller

CAPI: Use tty_port to keep track of capiminor's tty

Use the reference management features of tty_port to look up and drop
again the tty_struct associated with a capiminor.
Signed-off-by: default avatarJan Kiszka <jan.kiszka@web.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 46324511
...@@ -94,7 +94,7 @@ struct capiminor { ...@@ -94,7 +94,7 @@ struct capiminor {
u16 datahandle; u16 datahandle;
u16 msgid; u16 msgid;
struct tty_struct *tty; struct tty_port port;
int ttyinstop; int ttyinstop;
int ttyoutstop; int ttyoutstop;
struct sk_buff *ttyskb; struct sk_buff *ttyskb;
...@@ -212,6 +212,8 @@ static void capiminor_del_all_ack(struct capiminor *mp) ...@@ -212,6 +212,8 @@ static void capiminor_del_all_ack(struct capiminor *mp)
/* -------- struct capiminor ---------------------------------------- */ /* -------- 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) static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
{ {
struct capiminor *mp; struct capiminor *mp;
...@@ -237,6 +239,9 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) ...@@ -237,6 +239,9 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
skb_queue_head_init(&mp->inqueue); skb_queue_head_init(&mp->inqueue);
skb_queue_head_init(&mp->outqueue); skb_queue_head_init(&mp->outqueue);
tty_port_init(&mp->port);
mp->port.ops = &capiminor_port_ops;
/* Allocate the least unused minor number. */ /* Allocate the least unused minor number. */
write_lock_irqsave(&capiminors_lock, flags); write_lock_irqsave(&capiminors_lock, flags);
for (minor = 0; minor < capi_ttyminors; minor++) for (minor = 0; minor < capi_ttyminors; minor++)
...@@ -335,18 +340,22 @@ static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np) ...@@ -335,18 +340,22 @@ static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np)
static void capincci_free_minor(struct capincci *np) static void capincci_free_minor(struct capincci *np)
{ {
struct capiminor *mp = np->minorp; struct capiminor *mp = np->minorp;
struct tty_struct *tty;
if (mp) { if (mp) {
capifs_free_ncci(mp->capifs_dentry); capifs_free_ncci(mp->capifs_dentry);
if (mp->tty) {
tty = tty_port_tty_get(&mp->port);
if (tty) {
mp->nccip = NULL; mp->nccip = NULL;
#ifdef _DEBUG_REFCOUNT #ifdef _DEBUG_REFCOUNT
printk(KERN_DEBUG "reset mp->nccip\n"); printk(KERN_DEBUG "reset mp->nccip\n");
#endif #endif
tty_hangup(mp->tty); tty_hangup(tty);
} else { tty_kref_put(tty);
capiminor_free(mp);
} }
capiminor_free(mp);
} }
} }
...@@ -433,44 +442,48 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb) ...@@ -433,44 +442,48 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
{ {
struct tty_struct *tty;
struct sk_buff *nskb; struct sk_buff *nskb;
int datalen; int datalen;
u16 errcode, datahandle; u16 errcode, datahandle;
struct tty_ldisc *ld; struct tty_ldisc *ld;
int ret = -1;
datalen = skb->len - CAPIMSG_LEN(skb->data); datalen = skb->len - CAPIMSG_LEN(skb->data);
if (mp->tty == NULL)
{ tty = tty_port_tty_get(&mp->port);
if (!tty) {
#ifdef _DEBUG_DATAFLOW #ifdef _DEBUG_DATAFLOW
printk(KERN_DEBUG "capi: currently no receiver\n"); printk(KERN_DEBUG "capi: currently no receiver\n");
#endif #endif
return -1; return -1;
} }
ld = tty_ldisc_ref(mp->tty); ld = tty_ldisc_ref(tty);
if (ld == NULL) if (!ld)
return -1; goto out1;
if (ld->ops->receive_buf == NULL) { if (ld->ops->receive_buf == NULL) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
#endif #endif
goto bad; goto out2;
} }
if (mp->ttyinstop) { if (mp->ttyinstop) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: recv tty throttled\n"); printk(KERN_DEBUG "capi: recv tty throttled\n");
#endif #endif
goto bad; goto out2;
} }
if (mp->tty->receive_room < datalen) { if (tty->receive_room < datalen) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: no room in tty\n"); printk(KERN_DEBUG "capi: no room in tty\n");
#endif #endif
goto bad; goto out2;
} }
if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) { if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) {
printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
goto bad; goto out2;
} }
datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
errcode = capi20_put_message(mp->ap, nskb); errcode = capi20_put_message(mp->ap, nskb);
...@@ -478,20 +491,21 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) ...@@ -478,20 +491,21 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
errcode); errcode);
kfree_skb(nskb); kfree_skb(nskb);
goto bad; goto out2;
} }
(void)skb_pull(skb, CAPIMSG_LEN(skb->data)); (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
#ifdef _DEBUG_DATAFLOW #ifdef _DEBUG_DATAFLOW
printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
datahandle, skb->len); datahandle, skb->len);
#endif #endif
ld->ops->receive_buf(mp->tty, skb->data, NULL, skb->len); ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
kfree_skb(skb); kfree_skb(skb);
ret = 0;
out2:
tty_ldisc_deref(ld); tty_ldisc_deref(ld);
return 0; out1:
bad: tty_kref_put(tty);
tty_ldisc_deref(ld); return ret;
return -1;
} }
static void handle_minor_recv(struct capiminor *mp) static void handle_minor_recv(struct capiminor *mp)
...@@ -510,16 +524,22 @@ static void handle_minor_recv(struct capiminor *mp) ...@@ -510,16 +524,22 @@ static void handle_minor_recv(struct capiminor *mp)
static int handle_minor_send(struct capiminor *mp) static int handle_minor_send(struct capiminor *mp)
{ {
struct tty_struct *tty;
struct sk_buff *skb; struct sk_buff *skb;
u16 len; u16 len;
int count = 0; int count = 0;
u16 errcode; u16 errcode;
u16 datahandle; 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) #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: send: tty stopped\n"); printk(KERN_DEBUG "capi: send: tty stopped\n");
#endif #endif
tty_kref_put(tty);
return 0; return 0;
} }
...@@ -542,6 +562,7 @@ static int handle_minor_send(struct capiminor *mp) ...@@ -542,6 +562,7 @@ static int handle_minor_send(struct capiminor *mp)
if (capiminor_add_ack(mp, datahandle) < 0) { if (capiminor_add_ack(mp, datahandle) < 0) {
skb_pull(skb, CAPI_DATA_B3_REQ_LEN); skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
skb_queue_head(&mp->outqueue, skb); skb_queue_head(&mp->outqueue, skb);
tty_kref_put(tty);
return count; return count;
} }
errcode = capi20_put_message(mp->ap, skb); errcode = capi20_put_message(mp->ap, skb);
...@@ -568,6 +589,7 @@ static int handle_minor_send(struct capiminor *mp) ...@@ -568,6 +589,7 @@ static int handle_minor_send(struct capiminor *mp)
mp->outbytes -= len; mp->outbytes -= len;
kfree_skb(skb); kfree_skb(skb);
} }
tty_kref_put(tty);
return count; return count;
} }
...@@ -578,6 +600,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) ...@@ -578,6 +600,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
{ {
struct capidev *cdev = ap->private; struct capidev *cdev = ap->private;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
struct tty_struct *tty;
struct capiminor *mp; struct capiminor *mp;
u16 datahandle; u16 datahandle;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
...@@ -641,8 +664,11 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) ...@@ -641,8 +664,11 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
#endif #endif
kfree_skb(skb); kfree_skb(skb);
(void)capiminor_del_ack(mp, datahandle); (void)capiminor_del_ack(mp, datahandle);
if (mp->tty) tty = tty_port_tty_get(&mp->port);
tty_wakeup(mp->tty); if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
(void)handle_minor_send(mp); (void)handle_minor_send(mp);
} else { } else {
...@@ -1029,14 +1055,17 @@ static void capinc_tty_cleanup(struct tty_struct *tty) ...@@ -1029,14 +1055,17 @@ static void capinc_tty_cleanup(struct tty_struct *tty)
capiminor_put(mp); capiminor_put(mp);
} }
static int capinc_tty_open(struct tty_struct * tty, struct file * file) static int capinc_tty_open(struct tty_struct *tty, struct file *filp)
{ {
struct capiminor *mp = tty->driver_data; struct capiminor *mp = tty->driver_data;
unsigned long flags; unsigned long flags;
int err;
err = tty_port_open(&mp->port, tty, filp);
if (err)
return err;
spin_lock_irqsave(&workaround_lock, flags); spin_lock_irqsave(&workaround_lock, flags);
if (atomic_read(&mp->ttyopencount) == 0)
mp->tty = tty;
atomic_inc(&mp->ttyopencount); atomic_inc(&mp->ttyopencount);
#ifdef _DEBUG_REFCOUNT #ifdef _DEBUG_REFCOUNT
printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount)); printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount));
...@@ -1046,7 +1075,7 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file) ...@@ -1046,7 +1075,7 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file)
return 0; 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 = tty->driver_data; struct capiminor *mp = tty->driver_data;
...@@ -1054,17 +1083,15 @@ static void capinc_tty_close(struct tty_struct * tty, struct file * file) ...@@ -1054,17 +1083,15 @@ static void capinc_tty_close(struct tty_struct * tty, struct file * file)
#ifdef _DEBUG_REFCOUNT #ifdef _DEBUG_REFCOUNT
printk(KERN_DEBUG "capinc_tty_close lastclose\n"); printk(KERN_DEBUG "capinc_tty_close lastclose\n");
#endif #endif
mp->tty = NULL;
} }
#ifdef _DEBUG_REFCOUNT #ifdef _DEBUG_REFCOUNT
printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount)); printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));
#endif #endif
if (mp->nccip == NULL)
capiminor_free(mp);
#ifdef _DEBUG_REFCOUNT #ifdef _DEBUG_REFCOUNT
printk(KERN_DEBUG "capinc_tty_close\n"); printk(KERN_DEBUG "capinc_tty_close\n");
#endif #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,
...@@ -1292,9 +1319,12 @@ static void capinc_tty_start(struct tty_struct *tty) ...@@ -1292,9 +1319,12 @@ static void capinc_tty_start(struct tty_struct *tty)
static void capinc_tty_hangup(struct tty_struct *tty) static void capinc_tty_hangup(struct tty_struct *tty)
{ {
struct capiminor *mp = tty->driver_data;
#ifdef _DEBUG_TTYFUNCS #ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_hangup\n"); printk(KERN_DEBUG "capinc_tty_hangup\n");
#endif #endif
tty_port_hangup(&mp->port);
} }
static int capinc_tty_break_ctl(struct tty_struct *tty, int state) static int capinc_tty_break_ctl(struct tty_struct *tty, int state)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment