xref: /linux/arch/um/drivers/tty.c (revision 43f5b3085fdd27c4edf535d938b2cb0ccead4f75)
11da177e4SLinus Torvalds /*
2e99525f9SJeff Dike  * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
31da177e4SLinus Torvalds  * Licensed under the GPL
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"
10e99525f9SJeff Dike #include "kern_constants.h"
111da177e4SLinus Torvalds #include "os.h"
12c13e5690SPaolo 'Blaisorblade' Giarrusso #include "um_malloc.h"
13e99525f9SJeff Dike #include "user.h"
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds struct tty_chan {
161da177e4SLinus Torvalds 	char *dev;
171da177e4SLinus Torvalds 	int raw;
181da177e4SLinus Torvalds 	struct termios tt;
191da177e4SLinus Torvalds };
201da177e4SLinus Torvalds 
215e7672ecSJeff Dike static void *tty_chan_init(char *str, int device, const struct chan_opts *opts)
221da177e4SLinus Torvalds {
231da177e4SLinus Torvalds 	struct tty_chan *data;
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds 	if (*str != ':') {
26e99525f9SJeff Dike 		printk(UM_KERN_ERR "tty_init : channel type 'tty' must specify "
271da177e4SLinus Torvalds 		       "a device\n");
28108ffa8cSJeff Dike 		return NULL;
291da177e4SLinus Torvalds 	}
301da177e4SLinus Torvalds 	str++;
311da177e4SLinus Torvalds 
32*43f5b308SJeff Dike 	data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
331da177e4SLinus Torvalds 	if (data == NULL)
34108ffa8cSJeff Dike 		return NULL;
351da177e4SLinus Torvalds 	*data = ((struct tty_chan) { .dev 	= str,
361da177e4SLinus Torvalds 				     .raw 	= opts->raw });
371da177e4SLinus Torvalds 
38108ffa8cSJeff Dike 	return data;
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds static int tty_open(int input, int output, int primary, void *d,
421da177e4SLinus Torvalds 		    char **dev_out)
431da177e4SLinus Torvalds {
441da177e4SLinus Torvalds 	struct tty_chan *data = d;
45e99525f9SJeff Dike 	int fd, err, mode = 0;
461da177e4SLinus Torvalds 
47e99525f9SJeff Dike 	if (input && output)
48e99525f9SJeff Dike 		mode = O_RDWR;
49e99525f9SJeff Dike 	else if (input)
50e99525f9SJeff Dike 		mode = O_RDONLY;
51e99525f9SJeff Dike 	else if (output)
52e99525f9SJeff Dike 		mode = O_WRONLY;
53e99525f9SJeff Dike 
54e99525f9SJeff Dike 	fd = open(data->dev, mode);
55108ffa8cSJeff Dike 	if (fd < 0)
56e99525f9SJeff Dike 		return -errno;
57108ffa8cSJeff Dike 
581da177e4SLinus Torvalds 	if (data->raw) {
591da177e4SLinus Torvalds 		CATCH_EINTR(err = tcgetattr(fd, &data->tt));
601da177e4SLinus Torvalds 		if (err)
61108ffa8cSJeff Dike 			return err;
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 		err = raw(fd);
641da177e4SLinus Torvalds 		if (err)
65108ffa8cSJeff Dike 			return err;
661da177e4SLinus Torvalds 	}
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	*dev_out = data->dev;
69108ffa8cSJeff Dike 	return fd;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
725e7672ecSJeff Dike const struct chan_ops tty_ops = {
731da177e4SLinus Torvalds 	.type		= "tty",
741da177e4SLinus Torvalds 	.init		= tty_chan_init,
751da177e4SLinus Torvalds 	.open		= tty_open,
761da177e4SLinus Torvalds 	.close		= generic_close,
771da177e4SLinus Torvalds 	.read		= generic_read,
781da177e4SLinus Torvalds 	.write		= generic_write,
79fd9bc53bSPaolo 'Blaisorblade' Giarrusso 	.console_write	= generic_console_write,
801da177e4SLinus Torvalds 	.window_size	= generic_window_size,
811da177e4SLinus Torvalds 	.free		= generic_free,
821da177e4SLinus Torvalds 	.winch		= 0,
831da177e4SLinus Torvalds };
84