Commit 34d0d4c1 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://uml.bkbits.net/mconfig-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents f005d73a 13c27e8d
......@@ -24,7 +24,8 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts)
return(NULL);
}
static int not_configged_open(int input, int output, int primary, void *data)
static int not_configged_open(int input, int output, int primary, void *data,
char **dev_out)
{
printk(KERN_ERR "Using a channel type which is configured out of "
"UML\n");
......@@ -112,7 +113,8 @@ static int open_one_chan(struct chan *chan, int input, int output, int primary)
if(chan->opened) return(0);
if(chan->ops->open == NULL) fd = 0;
else fd = (*chan->ops->open)(input, output, primary, chan->data);
else fd = (*chan->ops->open)(input, output, primary, chan->data,
&chan->dev);
if(fd < 0) return(fd);
chan->fd = fd;
......@@ -258,6 +260,66 @@ void free_chan(struct list_head *chans)
}
}
static int one_chan_config_string(struct chan *chan, char *str, int size,
char **error_out)
{
int n = 0;
CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
if(chan->dev == NULL){
CONFIG_CHUNK(str, size, n, "", 1);
return(n);
}
CONFIG_CHUNK(str, size, n, ":", 0);
CONFIG_CHUNK(str, size, n, chan->dev, 0);
return(n);
}
static int chan_pair_config_string(struct chan *in, struct chan *out,
char *str, int size, char **error_out)
{
int n;
n = one_chan_config_string(in, str, size, error_out);
str += n;
size -= n;
if(in == out){
CONFIG_CHUNK(str, size, n, "", 1);
return(n);
}
CONFIG_CHUNK(str, size, n, ",", 1);
n = one_chan_config_string(out, str, size, error_out);
str += n;
size -= n;
CONFIG_CHUNK(str, size, n, "", 1);
return(n);
}
int chan_config_string(struct list_head *chans, char *str, int size,
char **error_out)
{
struct list_head *ele;
struct chan *chan, *in = NULL, *out = NULL;
list_for_each(ele, chans){
chan = list_entry(ele, struct chan, list);
if(!chan->primary)
continue;
if(chan->input)
in = chan;
if(chan->output)
out = chan;
}
return(chan_pair_config_string(in, out, str, size, error_out));
}
struct chan_type {
char *key;
struct chan_ops *ops;
......
......@@ -15,6 +15,7 @@ struct fd_chan {
int fd;
int raw;
struct termios tt;
char str[sizeof("1234567890\0")];
};
void *fd_init(char *str, int device, struct chan_opts *opts)
......@@ -40,7 +41,7 @@ void *fd_init(char *str, int device, struct chan_opts *opts)
return(data);
}
int fd_open(int input, int output, int primary, void *d)
int fd_open(int input, int output, int primary, void *d, char **dev_out)
{
struct fd_chan *data = d;
......@@ -48,6 +49,8 @@ int fd_open(int input, int output, int primary, void *d)
tcgetattr(data->fd, &data->tt);
raw(data->fd, 0);
}
sprintf(data->str, "%d", data->fd);
*dev_out = data->str;
return(data->fd);
}
......@@ -69,6 +72,7 @@ int fd_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops fd_ops = {
type: "fd",
init: fd_init,
open: fd_open,
close: fd_close,
......
......@@ -8,11 +8,13 @@
#include "linux/list.h"
#include "linux/devfs_fs_kernel.h"
#include "asm/irq.h"
#include "asm/uaccess.h"
#include "chan_kern.h"
#include "irq_user.h"
#include "line.h"
#include "kern.h"
#include "user_util.h"
#include "kern_util.h"
#include "os.h"
#define LINE_BUFSIZE 4096
......@@ -281,7 +283,7 @@ void close_lines(struct line *lines, int nlines)
close_chan(&lines[i].chan_list);
}
void line_setup(struct line *lines, int num, char *init)
int line_setup(struct line *lines, int num, char *init, int all_allowed)
{
int i, n;
char *end;
......@@ -292,12 +294,36 @@ void line_setup(struct line *lines, int num, char *init)
if(*end != '='){
printk(KERN_ERR "line_setup failed to parse \"%s\"\n",
init);
return;
return(1);
}
init = end;
}
init++;
if(n == -1){
if((n >= 0) && (n >= num)){
printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
n, num);
return(1);
}
else if(n >= 0){
if(lines[n].count > 0){
printk("line_setup - device %d is open\n", n);
return(1);
}
if(lines[n].init_pri <= INIT_ONE){
lines[n].init_pri = INIT_ONE;
if(!strcmp(init, "none")) lines[n].valid = 0;
else {
lines[n].init_str = init;
lines[n].valid = 1;
}
}
}
else if(!all_allowed){
printk("line_setup - can't configure all devices from "
"mconsole\n");
return(1);
}
else {
for(i = 0; i < num; i++){
if(lines[i].init_pri <= INIT_ALL){
lines[i].init_pri = INIT_ALL;
......@@ -309,14 +335,57 @@ void line_setup(struct line *lines, int num, char *init)
}
}
}
else if(lines[n].init_pri <= INIT_ONE){
lines[n].init_pri = INIT_ONE;
if(!strcmp(init, "none")) lines[n].valid = 0;
else {
lines[n].init_str = init;
lines[n].valid = 1;
}
return(0);
}
int line_config(struct line *lines, int num, char *str)
{
char *new = uml_strdup(str);
if(new == NULL){
printk("line_config - uml_strdup failed\n");
return(-ENOMEM);
}
return(line_setup(lines, num, new, 0));
}
int line_get_config(char *name, struct line *lines, int num, char *str,
int size, char **error_out)
{
struct line *line;
char *end;
int dev, n = 0;
dev = simple_strtoul(name, &end, 0);
if((*end != '\0') || (end == name)){
*error_out = "line_setup failed to parse device number";
return(0);
}
if((dev < 0) || (dev >= num)){
*error_out = "device number of of range";
return(0);
}
line = &lines[dev];
down(&line->sem);
if(!line->valid)
CONFIG_CHUNK(str, size, n, "none", 1);
else if(line->count == 0)
CONFIG_CHUNK(str, size, n, line->init_str, 1);
else n = chan_config_string(&line->chan_list, str, size, error_out);
up(&line->sem);
return(n);
}
int line_remove(struct line *lines, int num, char *str)
{
char config[sizeof("conxxxx=none\0")];
sprintf(config, "%s=none", str);
return(line_setup(lines, num, config, 0));
}
void line_register_devfs(struct lines *set, struct line_driver *line_driver,
......@@ -366,6 +435,8 @@ void line_register_devfs(struct lines *set, struct line_driver *line_driver,
if(!lines[i].valid)
tty_unregister_devfs(driver, driver->minor_start + i);
}
mconsole_register_dev(&line_driver->mc);
}
void lines_init(struct line *lines, int nlines)
......
......@@ -108,6 +108,7 @@ void mconsole_version(struct mc_request *req)
reboot - Reboot UML
config <dev>=<config> - Add a new device to UML;
same syntax as command line
config <dev> - Query the configuration of a device
remove <dev> - Remove a device from UML
sysrq <letter> - Performs the SysRq action controlled by the letter
cad - invoke the Ctl-Alt-Del handler
......@@ -181,10 +182,56 @@ static struct mc_device *mconsole_find_dev(char *name)
return(NULL);
}
#define CONFIG_BUF_SIZE 64
static void mconsole_get_config(int (*get_config)(char *, char *, int,
char **),
struct mc_request *req, char *name)
{
char default_buf[CONFIG_BUF_SIZE], *error, *buf;
int n, size;
if(get_config == NULL){
mconsole_reply(req, "No get_config routine defined", 1, 0);
return;
}
error = NULL;
size = sizeof(default_buf)/sizeof(default_buf[0]);
buf = default_buf;
while(1){
n = (*get_config)(name, buf, size, &error);
if(error != NULL){
mconsole_reply(req, error, 1, 0);
goto out;
}
if(n <= size){
mconsole_reply(req, buf, 0, 0);
goto out;
}
if(buf != default_buf)
kfree(buf);
size = n;
buf = kmalloc(size, GFP_KERNEL);
if(buf == NULL){
mconsole_reply(req, "Failed to allocate buffer", 1, 0);
return;
}
}
out:
if(buf != default_buf)
kfree(buf);
}
void mconsole_config(struct mc_request *req)
{
struct mc_device *dev;
char *ptr = req->request.data;
char *ptr = req->request.data, *name;
int err;
ptr += strlen("config");
......@@ -194,8 +241,17 @@ void mconsole_config(struct mc_request *req)
mconsole_reply(req, "Bad configuration option", 1, 0);
return;
}
err = (*dev->config)(&ptr[strlen(dev->name)]);
mconsole_reply(req, "", err, 0);
name = &ptr[strlen(dev->name)];
ptr = name;
while((*ptr != '=') && (*ptr != '\0'))
ptr++;
if(*ptr == '='){
err = (*dev->config)(name);
mconsole_reply(req, "", err, 0);
}
else mconsole_get_config(dev->get_config, req, name);
}
void mconsole_remove(struct mc_request *req)
......
......@@ -3,6 +3,7 @@
* Licensed under the GPL
*/
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include "chan_user.h"
......@@ -15,8 +16,9 @@ void *null_init(char *str, int device, struct chan_opts *opts)
return(&null_chan);
}
int null_open(int input, int output, int primary, void *d)
int null_open(int input, int output, int primary, void *d, char **dev_out)
{
*dev_out = NULL;
return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0));
}
......@@ -30,6 +32,7 @@ void null_free(void *data)
}
struct chan_ops null_ops = {
type: "null",
init: null_init,
open: null_open,
close: generic_close,
......
......@@ -3,11 +3,12 @@
* Licensed under the GPL
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include <sys/socket.h>
#include <sys/un.h>
......@@ -24,6 +25,7 @@ struct port_chan {
int raw;
struct termios tt;
void *kernel_data;
char dev[sizeof("32768\0")];
};
void *port_init(char *str, int device, struct chan_opts *opts)
......@@ -50,11 +52,12 @@ void *port_init(char *str, int device, struct chan_opts *opts)
if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
*data = ((struct port_chan) { raw : opts->raw,
kernel_data : kern_data });
sprintf(data->dev, "%d", port);
return(data);
}
int port_open(int input, int output, int primary, void *d)
int port_open(int input, int output, int primary, void *d, char **dev_out)
{
struct port_chan *data = d;
int fd;
......@@ -64,6 +67,7 @@ int port_open(int input, int output, int primary, void *d)
tcgetattr(fd, &data->tt);
raw(fd, 0);
}
*dev_out = data->dev;
return(fd);
}
......@@ -91,6 +95,7 @@ void port_free(void *d)
}
struct chan_ops port_ops = {
type: "port",
init: port_init,
open: port_open,
close: port_close,
......
......@@ -19,6 +19,7 @@ struct pty_chan {
int dev;
int raw;
struct termios tt;
char dev_name[sizeof("/dev/pts/0123456\0")];
};
void *pty_chan_init(char *str, int device, struct chan_opts *opts)
......@@ -32,9 +33,10 @@ void *pty_chan_init(char *str, int device, struct chan_opts *opts)
return(data);
}
int pts_open(int input, int output, int primary, void *d)
int pts_open(int input, int output, int primary, void *d, char **dev_out)
{
struct pty_chan *data = d;
char *dev;
int fd;
if((fd = get_pty()) < 0){
......@@ -45,7 +47,11 @@ int pts_open(int input, int output, int primary, void *d)
tcgetattr(fd, &data->tt);
raw(fd, 0);
}
if(data->announce) (*data->announce)(ptsname(fd), data->dev);
dev = ptsname(fd);
sprintf(data->dev_name, "%s", dev);
*dev_out = data->dev_name;
if(data->announce) (*data->announce)(dev, data->dev);
return(fd);
}
......@@ -94,7 +100,7 @@ static void grantpt_cb(void *arg)
info->err = errno;
}
int pty_open(int input, int output, int primary, void *d)
int pty_open(int input, int output, int primary, void *d, char **dev_out)
{
struct pty_chan *data = d;
int fd;
......@@ -110,6 +116,9 @@ int pty_open(int input, int output, int primary, void *d)
if(data->raw) raw(fd, 0);
if(data->announce) (*data->announce)(dev, data->dev);
sprintf(data->dev_name, "%s", dev);
*dev_out = data->dev_name;
return(fd);
}
......@@ -121,6 +130,7 @@ int pty_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops pty_ops = {
type: "pty",
init: pty_chan_init,
open: pty_open,
close: generic_close,
......@@ -133,6 +143,7 @@ struct chan_ops pty_ops = {
};
struct chan_ops pts_ops = {
type: "pts",
init: pty_chan_init,
open: pts_open,
close: generic_close,
......
......@@ -20,6 +20,7 @@
#include "kern.h"
#include "init.h"
#include "irq_user.h"
#include "mconsole_kern.h"
#include "2_5compat.h"
static int ssl_version = 1;
......@@ -47,6 +48,10 @@ static struct chan_opts opts = {
in_kernel : 1,
};
static int ssl_config(char *str);
static int ssl_get_config(char *dev, char *str, int size, char **error_out);
static int ssl_remove(char *str);
static struct line_driver driver = {
name : "UML serial line",
devfs_name : "tts/%d",
......@@ -60,6 +65,12 @@ static struct line_driver driver = {
write_irq_name : "ssl-write",
symlink_from : "serial",
symlink_to : "tts",
mc : {
name : "ssl",
config : ssl_config,
get_config : ssl_get_config,
remove : ssl_remove,
},
};
/* The array is initialized by line_init, which is an initcall. The
......@@ -70,6 +81,25 @@ static struct line serial_lines[NR_PORTS] =
static struct lines lines = LINES_INIT(NR_PORTS);
static int ssl_config(char *str)
{
return(line_config(serial_lines,
sizeof(serial_lines)/sizeof(serial_lines[0]), str));
}
static int ssl_get_config(char *dev, char *str, int size, char **error_out)
{
return(line_get_config(dev, serial_lines,
sizeof(serial_lines)/sizeof(serial_lines[0]),
str, size, error_out));
}
static int ssl_remove(char *str)
{
return(line_remove(serial_lines,
sizeof(serial_lines)/sizeof(serial_lines[0]), str));
}
int ssl_open(struct tty_struct *tty, struct file *filp)
{
return(line_open(serial_lines, tty, &opts));
......@@ -207,7 +237,7 @@ __initcall(ssl_init);
static int ssl_chan_setup(char *str)
{
line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]),
str);
str, 1);
return(1);
}
......
......@@ -27,6 +27,7 @@
#include "user_util.h"
#include "kern_util.h"
#include "irq_user.h"
#include "mconsole_kern.h"
#include "init.h"
#include "2_5compat.h"
......@@ -41,6 +42,7 @@ static struct tty_driver console_driver;
static int console_refcount = 0;
static struct chan_ops init_console_ops = {
type: "you shouldn't see this",
init : NULL,
open : NULL,
close : NULL,
......@@ -78,6 +80,10 @@ static struct chan_opts opts = {
in_kernel : 1,
};
static int con_config(char *str);
static int con_get_config(char *dev, char *str, int size, char **error_out);
static int con_remove(char *str);
static struct line_driver driver = {
name : "UML console",
devfs_name : "vc/%d",
......@@ -91,6 +97,12 @@ static struct line_driver driver = {
write_irq_name : "console-write",
symlink_from : "ttys",
symlink_to : "vc",
mc : {
name : "con",
config : con_config,
get_config : con_get_config,
remove : con_remove,
},
};
static struct lines console_lines = LINES_INIT(MAX_TTYS);
......@@ -102,6 +114,22 @@ struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
[ 1 ... MAX_TTYS - 1 ] =
LINE_INIT(CONFIG_CON_CHAN, &driver) };
static int con_config(char *str)
{
return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str));
}
static int con_get_config(char *dev, char *str, int size, char **error_out)
{
return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str,
size, error_out));
}
static int con_remove(char *str)
{
return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str));
}
static int open_console(struct tty_struct *tty)
{
return(line_open(vts, tty, &opts));
......@@ -195,7 +223,7 @@ void stdio_console_init(void)
static int console_chan_setup(char *str)
{
line_setup(vts, sizeof(vts)/sizeof(vts[0]), str);
line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1);
return(1);
}
......
......@@ -30,14 +30,15 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts)
}
str++;
if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
if((data = um_kmalloc(sizeof(*data))) == NULL)
return(NULL);
*data = ((struct tty_chan) { dev : str,
raw : opts->raw });
return(data);
}
int tty_open(int input, int output, int primary, void *d)
int tty_open(int input, int output, int primary, void *d, char **dev_out)
{
struct tty_chan *data = d;
int fd;
......@@ -48,6 +49,8 @@ int tty_open(int input, int output, int primary, void *d)
tcgetattr(fd, &data->tt);
raw(fd, 0);
}
*dev_out = data->dev;
return(fd);
}
......@@ -59,6 +62,7 @@ int tty_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops tty_ops = {
type: "tty",
init: tty_chan_init,
open: tty_open,
close: generic_close,
......
......@@ -574,6 +574,44 @@ static int ubd_config(char *str)
return(err);
}
static int ubd_get_config(char *dev, char *str, int size, char **error_out)
{
struct ubd *ubd;
char *end;
int major, n = 0;
major = simple_strtoul(dev, &end, 0);
if((*end != '\0') || (end == dev)){
*error_out = "ubd_get_config : didn't parse major number";
return(-1);
}
if((major >= MAX_DEV) || (major < 0)){
*error_out = "ubd_get_config : major number out of range";
return(-1);
}
ubd = &ubd_dev[major];
spin_lock(&ubd_lock);
if(ubd->file == NULL){
CONFIG_CHUNK(str, size, n, "", 1);
goto out;
}
CONFIG_CHUNK(str, size, n, ubd->file, 0);
if(ubd->cow.file != NULL){
CONFIG_CHUNK(str, size, n, ",", 0);
CONFIG_CHUNK(str, size, n, ubd->cow.file, 1);
}
else CONFIG_CHUNK(str, size, n, "", 1);
out:
spin_unlock(&ubd_lock);
return(n);
}
static int ubd_remove(char *str)
{
struct ubd *dev;
......@@ -620,6 +658,7 @@ static int ubd_remove(char *str)
static struct mc_device ubd_mc = {
.name = "ubd",
.config = ubd_config,
.get_config = ubd_get_config,
.remove = ubd_remove,
};
......
......@@ -83,7 +83,7 @@ __uml_setup("xterm=", xterm_setup,
" are 'xterm=gnome-terminal,-t,-x'.\n\n"
);
int xterm_open(int input, int output, int primary, void *d)
int xterm_open(int input, int output, int primary, void *d, char **dev_out)
{
struct xterm_chan *data = d;
unsigned long stack;
......@@ -141,6 +141,7 @@ int xterm_open(int input, int output, int primary, void *d)
if(data->raw) raw(new, 0);
data->pid = pid;
*dev_out = NULL;
return(new);
}
......@@ -168,6 +169,7 @@ int xterm_console_write(int fd, const char *buf, int n, void *d)
}
struct chan_ops xterm_ops = {
type: "xterm",
init: xterm_init,
open: xterm_open,
close: xterm_close,
......
......@@ -12,6 +12,7 @@
struct chan {
struct list_head list;
char *dev;
unsigned int primary:1;
unsigned int input:1;
unsigned int output:1;
......@@ -38,6 +39,8 @@ extern int chan_window_size(struct list_head *chans,
unsigned short *rows_out,
unsigned short *cols_out);
extern int chan_out_fd(struct list_head *chans);
extern int chan_config_string(struct list_head *chans, char *str, int size,
char **error_out);
#endif
......
......@@ -19,8 +19,9 @@ struct chan_opts {
enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
struct chan_ops {
char *type;
void *(*init)(char *, int, struct chan_opts *);
int (*open)(int, int, int, void *);
int (*open)(int, int, int, void *, char **);
void (*close)(int, void *);
int (*read)(int, char *, void *);
int (*write)(int, const char *, int, void *);
......
......@@ -11,6 +11,7 @@
#include "linux/tty.h"
#include "asm/semaphore.h"
#include "chan_user.h"
#include "mconsole_kern.h"
struct line_driver {
char *name;
......@@ -25,6 +26,7 @@ struct line_driver {
char *write_irq_name;
char *symlink_from;
char *symlink_to;
struct mc_device mc;
};
struct line {
......@@ -70,8 +72,9 @@ extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused);
extern void line_close(struct line *lines, struct tty_struct *tty);
extern int line_open(struct line *lines, struct tty_struct *tty,
struct chan_opts *opts);
extern void line_setup(struct line *lines, int num, char *init);
extern int line_write(struct line *line, struct tty_struct *tty,
extern int line_setup(struct line *lines, int num, char *init,
int all_allowed);
extern int line_write(struct line *line, struct tty_struct *tty,
const char *buf, int len);
extern int line_write_room(struct tty_struct *tty);
extern char *add_xterm_umid(char *base);
......@@ -84,6 +87,10 @@ extern void line_register_devfs(struct lines *set,
int nlines);
extern void lines_init(struct line *lines, int nlines);
extern void close_lines(struct line *lines, int nlines);
extern int line_config(struct line *lines, int num, char *str);
extern int line_remove(struct line *lines, int num, char *str);
extern int line_get_config(char *dev, struct line *lines, int num, char *str,
int size, char **error_out);
#endif
......
/*
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
......@@ -19,9 +19,23 @@ struct mc_device {
struct list_head list;
char *name;
int (*config)(char *);
int (*get_config)(char *, char *, int, char **);
int (*remove)(char *);
};
#define CONFIG_CHUNK(str, size, current, chunk, end) \
do { \
current += strlen(chunk); \
if(current >= size) \
str = NULL; \
if(str != NULL){ \
strcpy(str, chunk); \
str += strlen(chunk); \
} \
if(end) \
current++; \
} while(0)
#ifdef CONFIG_MCONSOLE
extern void mconsole_register_dev(struct mc_device *new);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment