xref: /kernel/linux/linux-5.10/arch/um/drivers/tty.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <errno.h>
78c2ecf20Sopenharmony_ci#include <fcntl.h>
88c2ecf20Sopenharmony_ci#include <termios.h>
98c2ecf20Sopenharmony_ci#include "chan_user.h"
108c2ecf20Sopenharmony_ci#include <os.h>
118c2ecf20Sopenharmony_ci#include <um_malloc.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistruct tty_chan {
148c2ecf20Sopenharmony_ci	char *dev;
158c2ecf20Sopenharmony_ci	int raw;
168c2ecf20Sopenharmony_ci	struct termios tt;
178c2ecf20Sopenharmony_ci};
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic void *tty_chan_init(char *str, int device, const struct chan_opts *opts)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	struct tty_chan *data;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	if (*str != ':') {
248c2ecf20Sopenharmony_ci		printk(UM_KERN_ERR "tty_init : channel type 'tty' must specify "
258c2ecf20Sopenharmony_ci		       "a device\n");
268c2ecf20Sopenharmony_ci		return NULL;
278c2ecf20Sopenharmony_ci	}
288c2ecf20Sopenharmony_ci	str++;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
318c2ecf20Sopenharmony_ci	if (data == NULL)
328c2ecf20Sopenharmony_ci		return NULL;
338c2ecf20Sopenharmony_ci	*data = ((struct tty_chan) { .dev 	= str,
348c2ecf20Sopenharmony_ci				     .raw 	= opts->raw });
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	return data;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int tty_open(int input, int output, int primary, void *d,
408c2ecf20Sopenharmony_ci		    char **dev_out)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	struct tty_chan *data = d;
438c2ecf20Sopenharmony_ci	int fd, err, mode = 0;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	if (input && output)
468c2ecf20Sopenharmony_ci		mode = O_RDWR;
478c2ecf20Sopenharmony_ci	else if (input)
488c2ecf20Sopenharmony_ci		mode = O_RDONLY;
498c2ecf20Sopenharmony_ci	else if (output)
508c2ecf20Sopenharmony_ci		mode = O_WRONLY;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	fd = open(data->dev, mode);
538c2ecf20Sopenharmony_ci	if (fd < 0)
548c2ecf20Sopenharmony_ci		return -errno;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (data->raw) {
578c2ecf20Sopenharmony_ci		CATCH_EINTR(err = tcgetattr(fd, &data->tt));
588c2ecf20Sopenharmony_ci		if (err)
598c2ecf20Sopenharmony_ci			return err;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci		err = raw(fd);
628c2ecf20Sopenharmony_ci		if (err)
638c2ecf20Sopenharmony_ci			return err;
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	*dev_out = data->dev;
678c2ecf20Sopenharmony_ci	return fd;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciconst struct chan_ops tty_ops = {
718c2ecf20Sopenharmony_ci	.type		= "tty",
728c2ecf20Sopenharmony_ci	.init		= tty_chan_init,
738c2ecf20Sopenharmony_ci	.open		= tty_open,
748c2ecf20Sopenharmony_ci	.close		= generic_close,
758c2ecf20Sopenharmony_ci	.read		= generic_read,
768c2ecf20Sopenharmony_ci	.write		= generic_write,
778c2ecf20Sopenharmony_ci	.console_write	= generic_console_write,
788c2ecf20Sopenharmony_ci	.window_size	= generic_window_size,
798c2ecf20Sopenharmony_ci	.free		= generic_free,
808c2ecf20Sopenharmony_ci	.winch		= 0,
818c2ecf20Sopenharmony_ci};
82