Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+62 −32
Original line number Original line Diff line number Diff line
@@ -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)


/* -------- 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)
	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)
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)


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)
		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)


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)
		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)
		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)
{
{
	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)
#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)
	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)
	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)
#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)


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)