blob: 207b0444c9d9e6901b498843f9723b562490edc6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jeff Dikee99525f2007-10-16 01:26:41 -07002 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Licensed under the GPL
4 */
5
Jeff Dikee99525f2007-10-16 01:26:41 -07006#include <stddef.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007#include <stdlib.h>
Jeff Dikee99525f2007-10-16 01:26:41 -07008#include <stdio.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <errno.h>
Jeff Dikee99525f2007-10-16 01:26:41 -070010#include <termios.h>
11#include <unistd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include "chan_user.h"
Paolo 'Blaisorblade' Giarrussoc13e5692006-10-19 23:28:20 -070013#include "um_malloc.h"
Jeff Dikee99525f2007-10-16 01:26:41 -070014#include "user.h"
15#include "os.h"
16#include "kern_constants.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
18struct fd_chan {
19 int fd;
20 int raw;
21 struct termios tt;
22 char str[sizeof("1234567890\0")];
23};
24
Jeff Dike5e7672e2006-09-27 01:50:33 -070025static void *fd_init(char *str, int device, const struct chan_opts *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -070026{
27 struct fd_chan *data;
28 char *end;
29 int n;
30
Jeff Dikee99525f2007-10-16 01:26:41 -070031 if (*str != ':') {
32 printk(UM_KERN_ERR "fd_init : channel type 'fd' must specify a "
33 "file descriptor\n");
34 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 }
36 str++;
37 n = strtoul(str, &end, 0);
Jeff Dikee99525f2007-10-16 01:26:41 -070038 if ((*end != '\0') || (end == str)) {
39 printk(UM_KERN_ERR "fd_init : couldn't parse file descriptor "
40 "'%s'\n", str);
41 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 }
Jeff Dikee99525f2007-10-16 01:26:41 -070043
Jeff Dikee4c4bf992007-07-15 23:38:56 -070044 data = kmalloc(sizeof(*data), UM_GFP_KERNEL);
Jeff Dikee99525f2007-10-16 01:26:41 -070045 if(data == NULL)
46 return NULL;
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 *data = ((struct fd_chan) { .fd = n,
49 .raw = opts->raw });
Jeff Dikee99525f2007-10-16 01:26:41 -070050 return data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051}
52
53static int fd_open(int input, int output, int primary, void *d, char **dev_out)
54{
55 struct fd_chan *data = d;
56 int err;
57
Jeff Dikee99525f2007-10-16 01:26:41 -070058 if (data->raw && isatty(data->fd)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 CATCH_EINTR(err = tcgetattr(data->fd, &data->tt));
Jeff Dikee99525f2007-10-16 01:26:41 -070060 if (err)
61 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63 err = raw(data->fd);
Jeff Dikee99525f2007-10-16 01:26:41 -070064 if (err)
65 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 }
67 sprintf(data->str, "%d", data->fd);
68 *dev_out = data->str;
Jeff Dikee99525f2007-10-16 01:26:41 -070069 return data->fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070}
71
72static void fd_close(int fd, void *d)
73{
74 struct fd_chan *data = d;
75 int err;
76
Jeff Dikee99525f2007-10-16 01:26:41 -070077 if (!data->raw || !isatty(fd))
78 return;
79
80 CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt));
81 if (err)
82 printk(UM_KERN_ERR "Failed to restore terminal state - "
83 "errno = %d\n", -err);
84 data->raw = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085}
86
Jeff Dike5e7672e2006-09-27 01:50:33 -070087const struct chan_ops fd_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 .type = "fd",
89 .init = fd_init,
90 .open = fd_open,
91 .close = fd_close,
92 .read = generic_read,
93 .write = generic_write,
Paolo 'Blaisorblade' Giarrussofd9bc532005-11-13 16:07:10 -080094 .console_write = generic_console_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 .window_size = generic_window_size,
96 .free = generic_free,
97 .winch = 1,
98};