xref: /kernel/linux/linux-6.6/arch/um/drivers/tty.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <errno.h>
762306a36Sopenharmony_ci#include <fcntl.h>
862306a36Sopenharmony_ci#include <termios.h>
962306a36Sopenharmony_ci#include "chan_user.h"
1062306a36Sopenharmony_ci#include <os.h>
1162306a36Sopenharmony_ci#include <um_malloc.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistruct tty_chan {
1462306a36Sopenharmony_ci	char *dev;
1562306a36Sopenharmony_ci	int raw;
1662306a36Sopenharmony_ci	struct termios tt;
1762306a36Sopenharmony_ci};
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic void *tty_chan_init(char *str, int device, const struct chan_opts *opts)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	struct tty_chan *data;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	if (*str != ':') {
2462306a36Sopenharmony_ci		printk(UM_KERN_ERR "tty_init : channel type 'tty' must specify "
2562306a36Sopenharmony_ci		       "a device\n");
2662306a36Sopenharmony_ci		return NULL;
2762306a36Sopenharmony_ci	}
2862306a36Sopenharmony_ci	str++;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
3162306a36Sopenharmony_ci	if (data == NULL)
3262306a36Sopenharmony_ci		return NULL;
3362306a36Sopenharmony_ci	*data = ((struct tty_chan) { .dev 	= str,
3462306a36Sopenharmony_ci				     .raw 	= opts->raw });
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	return data;
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic int tty_open(int input, int output, int primary, void *d,
4062306a36Sopenharmony_ci		    char **dev_out)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct tty_chan *data = d;
4362306a36Sopenharmony_ci	int fd, err, mode = 0;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (input && output)
4662306a36Sopenharmony_ci		mode = O_RDWR;
4762306a36Sopenharmony_ci	else if (input)
4862306a36Sopenharmony_ci		mode = O_RDONLY;
4962306a36Sopenharmony_ci	else if (output)
5062306a36Sopenharmony_ci		mode = O_WRONLY;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	fd = open(data->dev, mode);
5362306a36Sopenharmony_ci	if (fd < 0)
5462306a36Sopenharmony_ci		return -errno;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (data->raw) {
5762306a36Sopenharmony_ci		CATCH_EINTR(err = tcgetattr(fd, &data->tt));
5862306a36Sopenharmony_ci		if (err)
5962306a36Sopenharmony_ci			return err;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		err = raw(fd);
6262306a36Sopenharmony_ci		if (err)
6362306a36Sopenharmony_ci			return err;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	*dev_out = data->dev;
6762306a36Sopenharmony_ci	return fd;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciconst struct chan_ops tty_ops = {
7162306a36Sopenharmony_ci	.type		= "tty",
7262306a36Sopenharmony_ci	.init		= tty_chan_init,
7362306a36Sopenharmony_ci	.open		= tty_open,
7462306a36Sopenharmony_ci	.close		= generic_close,
7562306a36Sopenharmony_ci	.read		= generic_read,
7662306a36Sopenharmony_ci	.write		= generic_write,
7762306a36Sopenharmony_ci	.console_write	= generic_console_write,
7862306a36Sopenharmony_ci	.window_size	= generic_window_size,
7962306a36Sopenharmony_ci	.free		= generic_free,
8062306a36Sopenharmony_ci	.winch		= 0,
8162306a36Sopenharmony_ci};
82