lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250826-tty-tests-v1-2-e904a817df92@gmail.com>
Date: Tue, 26 Aug 2025 16:51:32 -0600
From: Abhinav Saxena <xandfury@...il.com>
To: Greg Kroah-Hartman <gregkh@...uxfoundation.org>, 
 Jiri Slaby <jirislaby@...nel.org>, Nathan Chancellor <nathan@...nel.org>, 
 Nick Desaulniers <nick.desaulniers+lkml@...il.com>, 
 Bill Wendling <morbo@...gle.com>, Justin Stitt <justinstitt@...gle.com>, 
 Kees Cook <kees@...nel.org>
Cc: linux-kernel@...r.kernel.org, linux-serial@...r.kernel.org, 
 llvm@...ts.linux.dev, linux-hardening@...r.kernel.org, 
 Abhinav Saxena <xandfury@...il.com>
Subject: [RFC PATCH 2/5] tty: Add KUnit test helper functions

Introduce comprehensive test helper infrastructure for TTY driver
testing through real kernel entry points. The helpers are included
directly into tty_io.c when CONFIG_TTY_KUNIT_TESTS=y to access
internal functions while maintaining clean symbol export boundaries.

Key features:
- Complete TTY lifecycle testing (open/close/read/write)
- RX data injection via flip buffers
- Termios manipulation for configuration testing
- Automatic resource cleanup via KUnit actions

All functions use EXPORT_SYMBOL_IF_KUNIT() to prevent production
symbol table pollution while enabling comprehensive testing.

Signed-off-by: Abhinav Saxena <xandfury@...il.com>
---
 drivers/tty/tests/tty_test_helpers.c | 387 +++++++++++++++++++++++++++++++++++
 drivers/tty/tests/tty_test_helpers.h | 239 +++++++++++++++++++++
 drivers/tty/tty_io.c                 |   4 +
 3 files changed, 630 insertions(+)

diff --git a/drivers/tty/tests/tty_test_helpers.c b/drivers/tty/tests/tty_test_helpers.c
new file mode 100644
index 0000000000000000000000000000000000000000..0de61626ccef1d4e4246f43347401ff46ac432ec
--- /dev/null
+++ b/drivers/tty/tests/tty_test_helpers.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit test helpers for TTY drivers
+ *
+ * This file is included directly into tty_io.c when CONFIG_TTY_KUNIT_TESTS=y.
+ * This allows the helper functions to access internal TTY functions like
+ * tty_open() and tty_release() while providing exported symbols for use
+ * by test modules.
+ *
+ * All functions are exported via EXPORT_SYMBOL_IF_KUNIT() so they are
+ * only available when KUNIT is enabled, preventing pollution of the
+ * production symbol table.
+ *
+ * Copyright (c) 2025 Abhinav Saxena <xandfury@...il.com>
+ */
+
+#include <kunit/test.h>
+#include <kunit/visibility.h>
+#include <linux/fs.h>
+#include <linux/kdev_t.h>
+#include <linux/uio.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty_ldisc.h>
+#include <linux/termios.h>
+
+#include "tests/tty_test_helpers.h"
+
+
+static struct cdev tty_cdev;
+
+/**
+ * _tty_test_cleanup_release - KUnit cleanup action for TTY release
+ * @data: Pointer to tty_test_fixture
+ *
+ * Internal cleanup function registered with kunit_add_action() to ensure
+ * TTY is properly released even if test fails or exits early.
+ * This prevents resource leaks and system instability.
+ */
+static void _tty_test_cleanup_release(void *data)
+{
+	struct tty_test_fixture *fx = data;
+	int ret;
+
+	if (!fx || !fx->opened || !fx->file || !fx->inode)
+		return;
+
+	ret = tty_release(fx->inode, fx->file);
+	if (ret)
+		pr_warn("TTY test cleanup failed: %d\n", ret);
+	fx->opened = false;
+}
+
+/**
+ * tty_test_create_fixture - Create a test fixture for TTY driver testing
+ */
+struct tty_test_fixture *tty_test_create_fixture(struct kunit *test,
+						 struct tty_driver *driver,
+						 unsigned int index)
+{
+	struct tty_test_fixture *fx;
+
+	KUNIT_ASSERT_NOT_NULL(test, driver);
+
+	fx = kunit_kzalloc(test, sizeof(*fx), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, fx);
+
+	fx->test = test;
+	fx->driver = driver;
+	fx->dev = MKDEV(driver->major, driver->minor_start + index);
+
+	/* Create synthetic VFS structures for real TTY operations */
+	fx->file = kunit_kzalloc(test, sizeof(*fx->file), GFP_KERNEL);
+	fx->inode = kunit_kzalloc(test, sizeof(*fx->inode), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, fx->file);
+	KUNIT_ASSERT_NOT_NULL(test, fx->inode);
+
+	/* Initialize as character device with appropriate permissions */
+	init_special_inode(fx->inode, S_IFCHR | 0600, fx->dev);
+	fx->inode->i_rdev = fx->dev;
+	fx->inode->i_cdev = &tty_cdev;
+	KUNIT_ASSERT_NOT_NULL(test, fx->inode->i_cdev);
+
+	fx->file->f_flags = O_RDWR;
+	fx->file->f_mode = FMODE_READ | FMODE_WRITE;
+	fx->file->f_inode = fx->inode;
+
+	/* Register cleanup before any operations that might fail */
+	kunit_add_action(test, _tty_test_cleanup_release, fx);
+
+	fx->opened = false;
+	return fx;
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_create_fixture);
+
+/**
+ * tty_test_open - Open TTY through standard kernel path
+ */
+int tty_test_open(struct tty_test_fixture *fx)
+{
+	int ret;
+
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx);
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->file);
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->inode);
+
+	ret = tty_open(fx->inode, fx->file);
+	if (ret)
+		return ret;
+
+	fx->tty = file_tty(fx->file);
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->tty);
+
+	/* Verify the TTY is properly set up */
+	KUNIT_EXPECT_TRUE(fx->test, !list_empty(&fx->tty->tty_files));
+	/* Ldisc must now be fully installed */
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->tty->ldisc);
+	KUNIT_EXPECT_TRUE(fx->test, fx->tty->ldisc->ops);
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->tty->disc_data);
+	KUNIT_EXPECT_NOT_NULL(fx->test, fx->tty->port);
+
+	fx->port = fx->tty->port;
+	ret = fx->tty->ldisc->ops->open(fx->tty);
+	if (ret) {
+		tty_release(fx->inode, fx->file);
+		return ret;
+	}
+
+	/* Enable non-blocking mode for predictable test behavior */
+	fx->file->f_flags |= O_NONBLOCK;
+	fx->opened = true;
+	return 0;
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_open);
+
+/**
+ * tty_test_release - Close TTY through standard kernel path
+ */
+int tty_test_release(struct tty_test_fixture *fx)
+{
+	int ret;
+
+	if (!fx || !fx->opened)
+		return 0;
+
+	/*
+	 * This calls the internal tty_release() function directly.
+	 * This works because this code is compiled as part of tty_io.c.
+	 */
+	ret = tty_release(fx->inode, fx->file);
+	if (!ret) {
+		fx->opened = false;
+		fx->tty = NULL;
+		fx->port = NULL;
+	}
+	return ret;
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_release);
+
+/**
+ * tty_test_write - Write data to TTY
+ */
+ssize_t tty_test_write(struct tty_test_fixture *fx, const void *buf,
+		       size_t count)
+{
+	struct kiocb iocb;
+	struct iov_iter from;
+	struct kvec kvec = { .iov_base = (void *)buf, .iov_len = count };
+
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx);
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->file);
+	KUNIT_ASSERT_TRUE(fx->test, fx->opened);
+
+	init_sync_kiocb(&iocb, fx->file);
+	iov_iter_kvec(&from, WRITE, &kvec, 1, count);
+
+	/* tty_write() is exported, so this works */
+	return tty_write(&iocb, &from);
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_write);
+
+/**
+ * tty_test_write_all - Write all data or fail
+ */
+int tty_test_write_all(struct tty_test_fixture *fx, const void *buf, size_t len)
+{
+	size_t off = 0;
+	int retries = 10;
+
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx);
+	KUNIT_ASSERT_TRUE(fx->test, fx->opened);
+
+	while (off < len && retries--) {
+		ssize_t n =
+			tty_test_write(fx, (const char *)buf + off, len - off);
+		if (n < 0)
+			return n;
+		if (n == 0) {
+			/* No progress - prevent infinite loop */
+			if (--retries <= 0) {
+				KUNIT_FAIL(fx->test,
+					   "Write stalled after %zu bytes",
+					   off);
+				return -EIO;
+			}
+			continue;
+		}
+		off += n;
+	}
+
+	if (off < len) {
+		KUNIT_FAIL(fx->test, "Incomplete write: %zu/%zu bytes", off,
+			   len);
+		return -EIO;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_write_all);
+
+/**
+ * tty_test_read - Read data from TTY (non-blocking)
+ */
+ssize_t tty_test_read(struct tty_test_fixture *fx, void *buf, size_t count)
+{
+	struct kiocb iocb;
+	struct iov_iter to;
+	struct kvec kvec = { .iov_base = buf, .iov_len = count };
+
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx);
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->file);
+	KUNIT_ASSERT_TRUE(fx->test, fx->opened);
+
+	init_sync_kiocb(&iocb, fx->file);
+	iov_iter_kvec(&to, READ, &kvec, 1, count);
+
+	return tty_read(&iocb, &to);
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_read);
+
+/**
+ * tty_test_read_all - Attempt to read all requested data
+ */
+ssize_t tty_test_read_all(struct tty_test_fixture *fx, void *buf, size_t want)
+{
+	size_t off = 0;
+	int tries = 8;
+
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx);
+	KUNIT_ASSERT_TRUE(fx->test, fx->opened);
+
+	while (off < want && tries--) {
+		ssize_t n = tty_test_read(fx, (char *)buf + off, want - off);
+
+		if (n == -EAGAIN)
+			continue;
+		if (n < 0)
+			return n;
+		if (n == 0)
+			continue;
+		off += n;
+	}
+	return off;
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_read_all);
+
+/**
+ * tty_test_simulate_rx - Inject received data for testing
+ */
+int tty_test_simulate_rx(struct tty_test_fixture *fx, const unsigned char *data,
+			 size_t len)
+{
+	int ret;
+
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx);
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->port);
+	KUNIT_ASSERT_TRUE(fx->test, fx->opened);
+
+	ret = tty_insert_flip_string(fx->port, data, len);
+	if (ret > 0)
+		tty_flip_buffer_push(fx->port);
+
+	return ret;
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_simulate_rx);
+
+/**
+ * tty_fx_supports_rx - Check if fixture supports RX testing
+ */
+bool tty_fx_supports_rx(const struct tty_test_fixture *fx)
+{
+	struct tty_ldisc *ld;
+	const struct tty_ldisc_ops *ops;
+
+	if (!fx || !fx->tty || !fx->opened)
+		return false;
+
+	ld = tty_ldisc_ref(fx->tty);
+	if (!ld)
+		return false;
+
+	ops = READ_ONCE(ld->ops);
+	if (ops && (ops->receive_buf || ops->receive_buf2)) {
+		tty_ldisc_deref(ld);
+		return true;
+	}
+
+	tty_ldisc_deref(ld);
+	return false;
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_fx_supports_rx);
+
+/**
+ * tty_test_assert_valid_ops - Validate driver has required operations
+ */
+void tty_test_assert_valid_ops(struct kunit *test,
+			       const struct tty_driver *driver)
+{
+	KUNIT_ASSERT_NOT_NULL(test, driver);
+	KUNIT_ASSERT_NOT_NULL(test, driver->ops);
+	KUNIT_ASSERT_NOT_NULL(test, driver->ops->open);
+	KUNIT_ASSERT_NOT_NULL(test, driver->ops->close);
+	KUNIT_ASSERT_NOT_NULL(test, driver->ops->write);
+	KUNIT_ASSERT_NOT_NULL(test, driver->ops->write_room);
+	KUNIT_EXPECT_TRUE(test, driver->flags & TTY_DRIVER_INSTALLED);
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_assert_valid_ops);
+
+/**
+ * tty_test_get_chars_in_buffer - Get number of chars in output buffer
+ */
+unsigned int tty_test_get_chars_in_buffer(struct tty_test_fixture *fx)
+{
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx);
+	KUNIT_ASSERT_TRUE(fx->test, fx->opened);
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->tty);
+
+	if (fx->tty->ops->chars_in_buffer)
+		return fx->tty->ops->chars_in_buffer(fx->tty);
+
+	return 0;
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_get_chars_in_buffer);
+
+/**
+ * tty_test_get_write_room - Get available write room
+ */
+unsigned int tty_test_get_write_room(struct tty_test_fixture *fx)
+{
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx);
+	KUNIT_ASSERT_TRUE(fx->test, fx->opened);
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->tty);
+
+	if (fx->tty->ops->write_room)
+		return fx->tty->ops->write_room(fx->tty);
+
+	return 0;
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_get_write_room);
+
+/**
+ * tty_test_set_termios - Set terminal attributes for testing
+ */
+int tty_test_set_termios(struct tty_test_fixture *fx,
+			 const struct ktermios *termios)
+{
+	struct ktermios old_termios;
+
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx);
+	KUNIT_ASSERT_TRUE(fx->test, fx->opened);
+	KUNIT_ASSERT_NOT_NULL(fx->test, fx->tty);
+	KUNIT_ASSERT_NOT_NULL(fx->test, termios);
+
+	/* Save old termios for potential restoration */
+	old_termios = fx->tty->termios;
+
+	/* Update termios */
+	fx->tty->termios = *termios;
+
+	/* Call driver's set_termios if it exists */
+	if (fx->tty->ops->set_termios)
+		fx->tty->ops->set_termios(fx->tty, &old_termios);
+
+	return 0;
+}
+EXPORT_SYMBOL_IF_KUNIT(tty_test_set_termios);
diff --git a/drivers/tty/tests/tty_test_helpers.h b/drivers/tty/tests/tty_test_helpers.h
new file mode 100644
index 0000000000000000000000000000000000000000..10da4189e35880399e2c857f599ea7f4107f9e90
--- /dev/null
+++ b/drivers/tty/tests/tty_test_helpers.h
@@ -0,0 +1,239 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * KUnit test helpers for TTY drivers - Header declarations
+ *
+ * Provides reusable infrastructure for testing TTY drivers through
+ * real kernel entry points without requiring userspace interaction
+ * or hardware dependencies.
+ *
+ * The implementation (tty_test_helpers.c) is included directly into
+ * tty_io.c to allow access to internal TTY functions while providing
+ * exported symbols for test modules.
+ *
+ * Copyright (c) 2025 Abhinav Saxena <xandfury@...il.com>
+ *
+ */
+
+#ifndef _TTY_TEST_HELPERS_H
+#define _TTY_TEST_HELPERS_H
+
+#include <kunit/test.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/fs.h>
+
+/**
+ * struct tty_test_fixture - Test fixture for TTY driver testing
+ * @test: KUnit test context for assertions and memory management
+ * @driver: TTY driver being tested
+ * @tty: TTY structure (valid after successful open)
+ * @port: TTY port structure (valid after successful open)
+ * @file: Synthetic file structure for VFS operations
+ * @inode: Synthetic inode structure for device operations
+ * @dev: Device number (major:minor) for this TTY
+ * @opened: True if TTY has been opened successfully
+ *
+ * This fixture provides all necessary structures for testing TTY drivers
+ * through the standard kernel interfaces. Memory is managed by KUnit and
+ * automatic cleanup ensures proper resource release.
+ */
+struct tty_test_fixture {
+	struct kunit *test;
+	struct tty_driver *driver;
+	struct tty_struct *tty;
+	struct tty_port *port;
+	struct file *file;
+	struct inode *inode;
+	dev_t dev;
+	bool opened;
+};
+
+/* Core fixture management */
+
+/**
+ * tty_test_create_fixture - Create a test fixture for TTY driver testing
+ * @test: KUnit test context
+ * @driver: TTY driver to test (must be registered)
+ * @index: Minor number index for this TTY instance
+ *
+ * Creates a complete test fixture with synthetic VFS structures that
+ * enable testing through real tty_open()/tty_release() paths.
+ * All memory is managed by KUnit with automatic cleanup.
+ *
+ * Return: Allocated fixture or NULL on failure (test will abort)
+ */
+struct tty_test_fixture *tty_test_create_fixture(struct kunit *test,
+						 struct tty_driver *driver,
+						 unsigned int index);
+
+/* TTY lifecycle operations */
+
+/**
+ * tty_test_open - Open TTY through standard kernel path
+ * @fx: Test fixture created with tty_test_create_fixture()
+ *
+ * Opens the TTY using tty_open(), the same entry point used by userspace.
+ * This exercises the complete open sequence including driver install,
+ * line discipline attachment, and port initialization.
+ *
+ * After successful open:
+ * - fx->tty points to the allocated TTY structure
+ * - fx->port points to the associated TTY port
+ * - File is set to non-blocking mode for test convenience
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int tty_test_open(struct tty_test_fixture *fx);
+
+/**
+ * tty_test_release - Close TTY through standard kernel path
+ * @fx: Test fixture with opened TTY
+ *
+ * Closes the TTY using tty_release(), exercising the complete close
+ * Safe to call multiple times or on unopened fixtures.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int tty_test_release(struct tty_test_fixture *fx);
+
+/* Data transfer operations */
+
+/**
+ * tty_test_write - Write data to TTY
+ * @fx: Test fixture with opened TTY
+ * @buf: Data buffer to write
+ * @count: Number of bytes to write
+ *
+ * Writes data using tty_write(), the same path used by userspace write().
+ * This exercises line discipline processing, flow control, and driver
+ * write operations. May return partial writes based on buffer availability.
+ *
+ * Return: Number of bytes written, or negative error code
+ */
+ssize_t tty_test_write(struct tty_test_fixture *fx, const void *buf,
+		       size_t count);
+
+/**
+ * tty_test_write_all - Write all data or fail
+ * @fx: Test fixture with opened TTY
+ * @buf: Data buffer to write completely
+ * @len: Number of bytes that must be written
+ *
+ * Ensures all data is written by retrying partial writes.
+ * Useful for testing scenarios where complete data delivery is required.
+ * Will assert-fail the test if any individual write returns 0 bytes.
+ *
+ * Return: 0 on complete success, negative error code on failure
+ */
+int tty_test_write_all(struct tty_test_fixture *fx, const void *buf,
+		       size_t len);
+
+/**
+ * tty_test_read - Read data from TTY (non-blocking)
+ * @fx: Test fixture with opened TTY
+ * @buf: Buffer to receive data
+ * @count: Maximum bytes to read
+ *
+ * Reads data using tty_read() in non-blocking mode. This is useful for
+ * verifying that injected RX data is properly delivered through the
+ * line discipline to userspace. Returns immediately with -EAGAIN if
+ * no data is available.
+ *
+ * Return: Number of bytes read, -EAGAIN if no data, or other negative error
+ */
+ssize_t tty_test_read(struct tty_test_fixture *fx, void *buf, size_t count);
+
+/**
+ * tty_test_read_all - Attempt to read all requested data
+ * @fx: Test fixture with opened TTY
+ * @buf: Buffer to receive data
+ * @want: Number of bytes desired
+ *
+ * Makes a bounded number of read attempts to collect the requested amount
+ * of data. Useful for reading back data that was injected via flip buffers,
+ * accounting for potential delays in line discipline processing.
+ *
+ * Return: Number of bytes actually read (may be less than requested)
+ */
+ssize_t tty_test_read_all(struct tty_test_fixture *fx, void *buf, size_t want);
+
+/* RX simulation and testing */
+
+/**
+ * tty_test_simulate_rx - Inject received data for testing
+ * @fx: Test fixture with opened TTY
+ * @data: Data bytes to inject
+ * @len: Number of bytes to inject
+ *
+ * Simulates data reception by injecting bytes through the flip buffer
+ * interface and pushing them to the line discipline. This allows testing
+ * of RX data paths, flow control, and line discipline processing without
+ * requiring actual hardware or external data sources.
+ *
+ * Return: Number of bytes successfully queued, or negative error code
+ */
+int tty_test_simulate_rx(struct tty_test_fixture *fx, const unsigned char *data,
+			 size_t len);
+
+/**
+ * tty_fx_supports_rx - Check if fixture supports RX testing
+ * @fx: Test fixture to check
+ *
+ * Determines if the TTY has a line discipline attached that can receive
+ * data. This is used to conditionally run RX-related tests since not all
+ * TTY configurations support data reception (e.g., write-only devices).
+ *
+ * Return: true if RX testing is supported, false otherwise
+ */
+bool tty_fx_supports_rx(const struct tty_test_fixture *fx);
+
+/* Driver validation and utility functions */
+
+/**
+ * tty_test_assert_valid_ops - Validate driver has required operations
+ * @test: KUnit test context
+ * @driver: TTY driver to validate
+ *
+ * Performs basic sanity checks on TTY driver structure to ensure it has
+ * the minimum required operations. This catches configuration errors that
+ * would cause NULL pointer dereferences during testing.
+ */
+void tty_test_assert_valid_ops(struct kunit *test,
+			       const struct tty_driver *driver);
+
+/**
+ * tty_test_get_chars_in_buffer - Get number of chars in output buffer
+ * @fx: Test fixture with opened TTY
+ *
+ * Returns the number of characters currently in the driver's output buffer.
+ * Useful for testing flow control and buffer management.
+ *
+ * Return: Number of characters in buffer, or 0 if not supported
+ */
+unsigned int tty_test_get_chars_in_buffer(struct tty_test_fixture *fx);
+
+/**
+ * tty_test_get_write_room - Get available write room
+ * @fx: Test fixture with opened TTY
+ *
+ * Returns the number of bytes that can be written without blocking.
+ * Useful for testing buffer management and flow control.
+ *
+ * Return: Number of bytes available for writing
+ */
+unsigned int tty_test_get_write_room(struct tty_test_fixture *fx);
+
+/**
+ * tty_test_set_termios - Set terminal attributes for testing
+ * @fx: Test fixture with opened TTY
+ * @termios: Terminal attributes to set
+ *
+ * Sets terminal attributes through the standard termios interface.
+ * Useful for testing different terminal configurations.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int tty_test_set_termios(struct tty_test_fixture *fx,
+			 const struct ktermios *termios);
+
+#endif /* _TTY_TEST_HELPERS_H */
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index e2d92cf70eb78ec6b2b93b55192e46781160c9dc..ac94a037358c9df0ba4013152878ca83a2e001c5 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3650,3 +3650,7 @@ int __init tty_init(void)
 #endif
 	return 0;
 }
+
+#ifdef CONFIG_TTY_KUNIT_TESTS
+#include "tests/tty_test_helpers.c"
+#endif

-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ