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 <stdio.h> 762306a36Sopenharmony_ci#include <stdlib.h> 862306a36Sopenharmony_ci#include <unistd.h> 962306a36Sopenharmony_ci#include <errno.h> 1062306a36Sopenharmony_ci#include <termios.h> 1162306a36Sopenharmony_ci#include "chan_user.h" 1262306a36Sopenharmony_ci#include <os.h> 1362306a36Sopenharmony_ci#include <um_malloc.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct fd_chan { 1662306a36Sopenharmony_ci int fd; 1762306a36Sopenharmony_ci int raw; 1862306a36Sopenharmony_ci struct termios tt; 1962306a36Sopenharmony_ci char str[sizeof("1234567890\0")]; 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic void *fd_init(char *str, int device, const struct chan_opts *opts) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct fd_chan *data; 2562306a36Sopenharmony_ci char *end; 2662306a36Sopenharmony_ci int n; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (*str != ':') { 2962306a36Sopenharmony_ci printk(UM_KERN_ERR "fd_init : channel type 'fd' must specify a " 3062306a36Sopenharmony_ci "file descriptor\n"); 3162306a36Sopenharmony_ci return NULL; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci str++; 3462306a36Sopenharmony_ci n = strtoul(str, &end, 0); 3562306a36Sopenharmony_ci if ((*end != '\0') || (end == str)) { 3662306a36Sopenharmony_ci printk(UM_KERN_ERR "fd_init : couldn't parse file descriptor " 3762306a36Sopenharmony_ci "'%s'\n", str); 3862306a36Sopenharmony_ci return NULL; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL); 4262306a36Sopenharmony_ci if (data == NULL) 4362306a36Sopenharmony_ci return NULL; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci *data = ((struct fd_chan) { .fd = n, 4662306a36Sopenharmony_ci .raw = opts->raw }); 4762306a36Sopenharmony_ci return data; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int fd_open(int input, int output, int primary, void *d, char **dev_out) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct fd_chan *data = d; 5362306a36Sopenharmony_ci int err; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (data->raw && isatty(data->fd)) { 5662306a36Sopenharmony_ci CATCH_EINTR(err = tcgetattr(data->fd, &data->tt)); 5762306a36Sopenharmony_ci if (err) 5862306a36Sopenharmony_ci return err; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci err = raw(data->fd); 6162306a36Sopenharmony_ci if (err) 6262306a36Sopenharmony_ci return err; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci sprintf(data->str, "%d", data->fd); 6562306a36Sopenharmony_ci *dev_out = data->str; 6662306a36Sopenharmony_ci return data->fd; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void fd_close(int fd, void *d) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct fd_chan *data = d; 7262306a36Sopenharmony_ci int err; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (!data->raw || !isatty(fd)) 7562306a36Sopenharmony_ci return; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt)); 7862306a36Sopenharmony_ci if (err) 7962306a36Sopenharmony_ci printk(UM_KERN_ERR "Failed to restore terminal state - " 8062306a36Sopenharmony_ci "errno = %d\n", -err); 8162306a36Sopenharmony_ci data->raw = 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciconst struct chan_ops fd_ops = { 8562306a36Sopenharmony_ci .type = "fd", 8662306a36Sopenharmony_ci .init = fd_init, 8762306a36Sopenharmony_ci .open = fd_open, 8862306a36Sopenharmony_ci .close = fd_close, 8962306a36Sopenharmony_ci .read = generic_read, 9062306a36Sopenharmony_ci .write = generic_write, 9162306a36Sopenharmony_ci .console_write = generic_console_write, 9262306a36Sopenharmony_ci .window_size = generic_window_size, 9362306a36Sopenharmony_ci .free = generic_free, 9462306a36Sopenharmony_ci .winch = 1, 9562306a36Sopenharmony_ci}; 96