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

Commit c3485ee0 authored by Rob Herring's avatar Rob Herring Committed by Greg Kroah-Hartman
Browse files

tty_port: Add port client functions



Introduce a client (upward direction) operations struct for tty_port
clients. Initially supported operations are for receiving data and write
wake-up. This will allow for having clients other than an ldisc.

Convert the calls to the ldisc to use the client ops as the default
operations.

Signed-off-by: default avatarRob Herring <robh@kernel.org>
Reviewed-By: default avatarSebastian Reichel <sre@kernel.org>
Tested-By: default avatarSebastian Reichel <sre@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a380ed46
Loading
Loading
Loading
Loading
+3 −14
Original line number Diff line number Diff line
@@ -437,7 +437,7 @@ int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf);

static int
receive_buf(struct tty_ldisc *ld, struct tty_buffer *head, int count)
receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
{
	unsigned char *p = char_buf_ptr(head, head->read);
	char	      *f = NULL;
@@ -445,7 +445,7 @@ receive_buf(struct tty_ldisc *ld, struct tty_buffer *head, int count)
	if (~head->flags & TTYB_NORMAL)
		f = flag_buf_ptr(head, head->read);

	return tty_ldisc_receive_buf(ld, p, f, count);
	return port->client_ops->receive_buf(port, p, f, count);
}

/**
@@ -465,16 +465,6 @@ static void flush_to_ldisc(struct work_struct *work)
{
	struct tty_port *port = container_of(work, struct tty_port, buf.work);
	struct tty_bufhead *buf = &port->buf;
	struct tty_struct *tty;
	struct tty_ldisc *disc;

	tty = READ_ONCE(port->itty);
	if (tty == NULL)
		return;

	disc = tty_ldisc_ref(tty);
	if (disc == NULL)
		return;

	mutex_lock(&buf->lock);

@@ -504,7 +494,7 @@ static void flush_to_ldisc(struct work_struct *work)
			continue;
		}

		count = receive_buf(disc, head, count);
		count = receive_buf(port, head, count);
		if (!count)
			break;
		head->read += count;
@@ -512,7 +502,6 @@ static void flush_to_ldisc(struct work_struct *work)

	mutex_unlock(&buf->lock);

	tty_ldisc_deref(disc);
}

/**
+40 −6
Original line number Diff line number Diff line
@@ -17,6 +17,44 @@
#include <linux/delay.h>
#include <linux/module.h>

static int tty_port_default_receive_buf(struct tty_port *port,
					const unsigned char *p,
					const unsigned char *f, size_t count)
{
	int ret;
	struct tty_struct *tty;
	struct tty_ldisc *disc;

	tty = READ_ONCE(port->itty);
	if (!tty)
		return 0;

	disc = tty_ldisc_ref(tty);
	if (!disc)
		return 0;

	ret = tty_ldisc_receive_buf(disc, p, (char *)f, count);

	tty_ldisc_deref(disc);

	return ret;
}

static void tty_port_default_wakeup(struct tty_port *port)
{
	struct tty_struct *tty = tty_port_tty_get(port);

	if (tty) {
		tty_wakeup(tty);
		tty_kref_put(tty);
	}
}

static const struct tty_port_client_operations default_client_ops = {
	.receive_buf = tty_port_default_receive_buf,
	.write_wakeup = tty_port_default_wakeup,
};

void tty_port_init(struct tty_port *port)
{
	memset(port, 0, sizeof(*port));
@@ -28,6 +66,7 @@ void tty_port_init(struct tty_port *port)
	spin_lock_init(&port->lock);
	port->close_delay = (50 * HZ) / 100;
	port->closing_wait = (3000 * HZ) / 100;
	port->client_ops = &default_client_ops;
	kref_init(&port->kref);
}
EXPORT_SYMBOL(tty_port_init);
@@ -272,12 +311,7 @@ EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
 */
void tty_port_tty_wakeup(struct tty_port *port)
{
	struct tty_struct *tty = tty_port_tty_get(port);

	if (tty) {
		tty_wakeup(tty);
		tty_kref_put(tty);
	}
	port->client_ops->write_wakeup(port);
}
EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);

+8 −1
Original line number Diff line number Diff line
@@ -218,11 +218,17 @@ struct tty_port_operations {
	void (*destruct)(struct tty_port *port);
};

struct tty_port_client_operations {
	int (*receive_buf)(struct tty_port *port, const unsigned char *, const unsigned char *, size_t);
	void (*write_wakeup)(struct tty_port *port);
};

struct tty_port {
	struct tty_bufhead	buf;		/* Locked internally */
	struct tty_struct	*tty;		/* Back pointer */
	struct tty_struct	*itty;		/* internal back ptr */
	const struct tty_port_operations *ops;	/* Port operations */
	const struct tty_port_client_operations *client_ops; /* Port client operations */
	spinlock_t		lock;		/* Lock protecting tty field */
	int			blocked_open;	/* Waiting to open */
	int			count;		/* Usage count */
@@ -241,6 +247,7 @@ struct tty_port {
						   based drain is needed else
						   set to size of fifo */
	struct kref		kref;		/* Ref counter */
	void 			*client_data;
};

/* tty_port::iflags bits -- use atomic bit ops */