xref: /linux/arch/um/drivers/tty.c (revision dbddf429dc514257170d4c5e116cbd95a86408ab)
1*dbddf429SAlex Dewar // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
3e99525f9SJeff Dike  * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include <errno.h>
7e99525f9SJeff Dike #include <fcntl.h>
8e99525f9SJeff Dike #include <termios.h>
91da177e4SLinus Torvalds #include "chan_user.h"
1037185b33SAl Viro #include <os.h>
1137185b33SAl Viro #include <um_malloc.h>
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds struct tty_chan {
141da177e4SLinus Torvalds 	char *dev;
151da177e4SLinus Torvalds 	int raw;
161da177e4SLinus Torvalds 	struct termios tt;
171da177e4SLinus Torvalds };
181da177e4SLinus Torvalds 
195e7672ecSJeff Dike static void *tty_chan_init(char *str, int device, const struct chan_opts *opts)
201da177e4SLinus Torvalds {
211da177e4SLinus Torvalds 	struct tty_chan *data;
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds 	if (*str != ':') {
24e99525f9SJeff Dike 		printk(UM_KERN_ERR "tty_init : channel type 'tty' must specify "
251da177e4SLinus Torvalds 		       "a device\n");
26108ffa8cSJeff Dike 		return NULL;
271da177e4SLinus Torvalds 	}
281da177e4SLinus Torvalds 	str++;
291da177e4SLinus Torvalds 
3043f5b308SJeff Dike 	data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
311da177e4SLinus Torvalds 	if (data == NULL)
32108ffa8cSJeff Dike 		return NULL;
331da177e4SLinus Torvalds 	*data = ((struct tty_chan) { .dev 	= str,
341da177e4SLinus Torvalds 				     .raw 	= opts->raw });
351da177e4SLinus Torvalds 
36108ffa8cSJeff Dike 	return data;
371da177e4SLinus Torvalds }
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds static int tty_open(int input, int output, int primary, void *d,
401da177e4SLinus Torvalds 		    char **dev_out)
411da177e4SLinus Torvalds {
421da177e4SLinus Torvalds 	struct tty_chan *data = d;
43e99525f9SJeff Dike 	int fd, err, mode = 0;
441da177e4SLinus Torvalds 
45e99525f9SJeff Dike 	if (input && output)
46e99525f9SJeff Dike 		mode = O_RDWR;
47e99525f9SJeff Dike 	else if (input)
48e99525f9SJeff Dike 		mode = O_RDONLY;
49e99525f9SJeff Dike 	else if (output)
50e99525f9SJeff Dike 		mode = O_WRONLY;
51e99525f9SJeff Dike 
52e99525f9SJeff Dike 	fd = open(data->dev, mode);
53108ffa8cSJeff Dike 	if (fd < 0)
54e99525f9SJeff Dike 		return -errno;
55108ffa8cSJeff Dike 
561da177e4SLinus Torvalds 	if (data->raw) {
571da177e4SLinus Torvalds 		CATCH_EINTR(err = tcgetattr(fd, &data->tt));
581da177e4SLinus Torvalds 		if (err)
59108ffa8cSJeff Dike 			return err;
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 		err = raw(fd);
621da177e4SLinus Torvalds 		if (err)
63108ffa8cSJeff Dike 			return err;
641da177e4SLinus Torvalds 	}
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	*dev_out = data->dev;
67108ffa8cSJeff Dike 	return fd;
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds 
705e7672ecSJeff Dike const struct chan_ops tty_ops = {
711da177e4SLinus Torvalds 	.type		= "tty",
721da177e4SLinus Torvalds 	.init		= tty_chan_init,
731da177e4SLinus Torvalds 	.open		= tty_open,
741da177e4SLinus Torvalds 	.close		= generic_close,
751da177e4SLinus Torvalds 	.read		= generic_read,
761da177e4SLinus Torvalds 	.write		= generic_write,
77fd9bc53bSPaolo 'Blaisorblade' Giarrusso 	.console_write	= generic_console_write,
781da177e4SLinus Torvalds 	.window_size	= generic_window_size,
791da177e4SLinus Torvalds 	.free		= generic_free,
801da177e4SLinus Torvalds 	.winch		= 0,
811da177e4SLinus Torvalds };
82