aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/um/drivers
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/um/drivers')
-rw-r--r--arch/um/drivers/Makefile46
-rw-r--r--arch/um/drivers/chan_kern.c577
-rw-r--r--arch/um/drivers/chan_user.c210
-rw-r--r--arch/um/drivers/cow.h42
-rw-r--r--arch/um/drivers/cow_sys.h48
-rw-r--r--arch/um/drivers/cow_user.c378
-rw-r--r--arch/um/drivers/daemon.h35
-rw-r--r--arch/um/drivers/daemon_kern.c108
-rw-r--r--arch/um/drivers/daemon_user.c197
-rw-r--r--arch/um/drivers/fd.c108
-rw-r--r--arch/um/drivers/harddog_kern.c190
-rw-r--r--arch/um/drivers/harddog_user.c143
-rw-r--r--arch/um/drivers/hostaudio_kern.c352
-rw-r--r--arch/um/drivers/line.c681
-rw-r--r--arch/um/drivers/mcast.h30
-rw-r--r--arch/um/drivers/mcast_kern.c143
-rw-r--r--arch/um/drivers/mcast_user.c177
-rw-r--r--arch/um/drivers/mconsole_kern.c619
-rw-r--r--arch/um/drivers/mconsole_user.c215
-rw-r--r--arch/um/drivers/mmapper_kern.c150
-rw-r--r--arch/um/drivers/net_kern.c896
-rw-r--r--arch/um/drivers/net_user.c255
-rw-r--r--arch/um/drivers/null.c56
-rw-r--r--arch/um/drivers/pcap_kern.c123
-rw-r--r--arch/um/drivers/pcap_user.c143
-rw-r--r--arch/um/drivers/pcap_user.h31
-rw-r--r--arch/um/drivers/port.h30
-rw-r--r--arch/um/drivers/port_kern.c309
-rw-r--r--arch/um/drivers/port_user.c225
-rw-r--r--arch/um/drivers/pty.c162
-rw-r--r--arch/um/drivers/random.c122
-rw-r--r--arch/um/drivers/slip.h39
-rw-r--r--arch/um/drivers/slip_kern.c109
-rw-r--r--arch/um/drivers/slip_proto.h93
-rw-r--r--arch/um/drivers/slip_user.c280
-rw-r--r--arch/um/drivers/slirp.h51
-rw-r--r--arch/um/drivers/slirp_kern.c135
-rw-r--r--arch/um/drivers/slirp_user.c201
-rw-r--r--arch/um/drivers/ssl.c251
-rw-r--r--arch/um/drivers/ssl.h23
-rw-r--r--arch/um/drivers/stderr_console.c45
-rw-r--r--arch/um/drivers/stdio_console.c205
-rw-r--r--arch/um/drivers/stdio_console.h21
-rw-r--r--arch/um/drivers/tty.c92
-rw-r--r--arch/um/drivers/ubd_kern.c1669
-rw-r--r--arch/um/drivers/ubd_user.c75
-rw-r--r--arch/um/drivers/xterm.c225
-rw-r--r--arch/um/drivers/xterm.h22
-rw-r--r--arch/um/drivers/xterm_kern.c93
49 files changed, 10430 insertions, 0 deletions
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
new file mode 100644
index 000000000000..323f72c64cd2
--- /dev/null
+++ b/arch/um/drivers/Makefile
@@ -0,0 +1,46 @@
1#
2# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com)
3# Licensed under the GPL
4#
5
6# pcap is broken in 2.5 because kbuild doesn't allow pcap.a to be linked
7# in to pcap.o
8
9slip-objs := slip_kern.o slip_user.o
10slirp-objs := slirp_kern.o slirp_user.o
11daemon-objs := daemon_kern.o daemon_user.o
12mcast-objs := mcast_kern.o mcast_user.o
13#pcap-objs := pcap_kern.o pcap_user.o $(PCAP)
14net-objs := net_kern.o net_user.o
15mconsole-objs := mconsole_kern.o mconsole_user.o
16hostaudio-objs := hostaudio_kern.o
17ubd-objs := ubd_kern.o ubd_user.o
18port-objs := port_kern.o port_user.o
19harddog-objs := harddog_kern.o harddog_user.o
20
21obj-y := stdio_console.o fd.o chan_kern.o chan_user.o line.o
22obj-$(CONFIG_SSL) += ssl.o
23obj-$(CONFIG_STDERR_CONSOLE) += stderr_console.o
24
25obj-$(CONFIG_UML_NET_SLIP) += slip.o
26obj-$(CONFIG_UML_NET_SLIRP) += slirp.o
27obj-$(CONFIG_UML_NET_DAEMON) += daemon.o
28obj-$(CONFIG_UML_NET_MCAST) += mcast.o
29#obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP)
30obj-$(CONFIG_UML_NET) += net.o
31obj-$(CONFIG_MCONSOLE) += mconsole.o
32obj-$(CONFIG_MMAPPER) += mmapper_kern.o
33obj-$(CONFIG_BLK_DEV_UBD) += ubd.o
34obj-$(CONFIG_HOSTAUDIO) += hostaudio.o
35obj-$(CONFIG_NULL_CHAN) += null.o
36obj-$(CONFIG_PORT_CHAN) += port.o
37obj-$(CONFIG_PTY_CHAN) += pty.o
38obj-$(CONFIG_TTY_CHAN) += tty.o
39obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
40obj-$(CONFIG_UML_WATCHDOG) += harddog.o
41obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
42obj-$(CONFIG_UML_RANDOM) += random.o
43
44USER_OBJS := fd.o null.o pty.o tty.o xterm.o
45
46include arch/um/scripts/Makefile.rules
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
new file mode 100644
index 000000000000..1f77deb3fd23
--- /dev/null
+++ b/arch/um/drivers/chan_kern.c
@@ -0,0 +1,577 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <linux/stddef.h>
7#include <linux/kernel.h>
8#include <linux/list.h>
9#include <linux/slab.h>
10#include <linux/tty.h>
11#include <linux/string.h>
12#include <linux/tty_flip.h>
13#include <asm/irq.h>
14#include "chan_kern.h"
15#include "user_util.h"
16#include "kern.h"
17#include "irq_user.h"
18#include "sigio.h"
19#include "line.h"
20#include "os.h"
21
22#ifdef CONFIG_NOCONFIG_CHAN
23static void *not_configged_init(char *str, int device, struct chan_opts *opts)
24{
25 printk(KERN_ERR "Using a channel type which is configured out of "
26 "UML\n");
27 return(NULL);
28}
29
30static int not_configged_open(int input, int output, int primary, void *data,
31 char **dev_out)
32{
33 printk(KERN_ERR "Using a channel type which is configured out of "
34 "UML\n");
35 return(-ENODEV);
36}
37
38static void not_configged_close(int fd, void *data)
39{
40 printk(KERN_ERR "Using a channel type which is configured out of "
41 "UML\n");
42}
43
44static int not_configged_read(int fd, char *c_out, void *data)
45{
46 printk(KERN_ERR "Using a channel type which is configured out of "
47 "UML\n");
48 return(-EIO);
49}
50
51static int not_configged_write(int fd, const char *buf, int len, void *data)
52{
53 printk(KERN_ERR "Using a channel type which is configured out of "
54 "UML\n");
55 return(-EIO);
56}
57
58static int not_configged_console_write(int fd, const char *buf, int len,
59 void *data)
60{
61 printk(KERN_ERR "Using a channel type which is configured out of "
62 "UML\n");
63 return(-EIO);
64}
65
66static int not_configged_window_size(int fd, void *data, unsigned short *rows,
67 unsigned short *cols)
68{
69 printk(KERN_ERR "Using a channel type which is configured out of "
70 "UML\n");
71 return(-ENODEV);
72}
73
74static void not_configged_free(void *data)
75{
76 printk(KERN_ERR "Using a channel type which is configured out of "
77 "UML\n");
78}
79
80static struct chan_ops not_configged_ops = {
81 .init = not_configged_init,
82 .open = not_configged_open,
83 .close = not_configged_close,
84 .read = not_configged_read,
85 .write = not_configged_write,
86 .console_write = not_configged_console_write,
87 .window_size = not_configged_window_size,
88 .free = not_configged_free,
89 .winch = 0,
90};
91#endif /* CONFIG_NOCONFIG_CHAN */
92
93void generic_close(int fd, void *unused)
94{
95 os_close_file(fd);
96}
97
98int generic_read(int fd, char *c_out, void *unused)
99{
100 int n;
101
102 n = os_read_file(fd, c_out, sizeof(*c_out));
103
104 if(n == -EAGAIN)
105 return(0);
106 else if(n == 0)
107 return(-EIO);
108 return(n);
109}
110
111/* XXX Trivial wrapper around os_write_file */
112
113int generic_write(int fd, const char *buf, int n, void *unused)
114{
115 return(os_write_file(fd, buf, n));
116}
117
118int generic_window_size(int fd, void *unused, unsigned short *rows_out,
119 unsigned short *cols_out)
120{
121 int rows, cols;
122 int ret;
123
124 ret = os_window_size(fd, &rows, &cols);
125 if(ret < 0)
126 return(ret);
127
128 ret = ((*rows_out != rows) || (*cols_out != cols));
129
130 *rows_out = rows;
131 *cols_out = cols;
132
133 return(ret);
134}
135
136void generic_free(void *data)
137{
138 kfree(data);
139}
140
141static void tty_receive_char(struct tty_struct *tty, char ch)
142{
143 if(tty == NULL) return;
144
145 if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
146 if(ch == STOP_CHAR(tty)){
147 stop_tty(tty);
148 return;
149 }
150 else if(ch == START_CHAR(tty)){
151 start_tty(tty);
152 return;
153 }
154 }
155
156 if((tty->flip.flag_buf_ptr == NULL) ||
157 (tty->flip.char_buf_ptr == NULL))
158 return;
159 tty_insert_flip_char(tty, ch, TTY_NORMAL);
160}
161
162static int open_one_chan(struct chan *chan, int input, int output, int primary)
163{
164 int fd;
165
166 if(chan->opened) return(0);
167 if(chan->ops->open == NULL) fd = 0;
168 else fd = (*chan->ops->open)(input, output, primary, chan->data,
169 &chan->dev);
170 if(fd < 0) return(fd);
171 chan->fd = fd;
172
173 chan->opened = 1;
174 return(0);
175}
176
177int open_chan(struct list_head *chans)
178{
179 struct list_head *ele;
180 struct chan *chan;
181 int ret, err = 0;
182
183 list_for_each(ele, chans){
184 chan = list_entry(ele, struct chan, list);
185 ret = open_one_chan(chan, chan->input, chan->output,
186 chan->primary);
187 if(chan->primary) err = ret;
188 }
189 return(err);
190}
191
192void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
193{
194 struct list_head *ele;
195 struct chan *chan;
196
197 list_for_each(ele, chans){
198 chan = list_entry(ele, struct chan, list);
199 if(chan->primary && chan->output && chan->ops->winch){
200 register_winch(chan->fd, tty);
201 return;
202 }
203 }
204}
205
206void enable_chan(struct list_head *chans, struct tty_struct *tty)
207{
208 struct list_head *ele;
209 struct chan *chan;
210
211 list_for_each(ele, chans){
212 chan = list_entry(ele, struct chan, list);
213 if(!chan->opened) continue;
214
215 line_setup_irq(chan->fd, chan->input, chan->output, tty);
216 }
217}
218
219void close_chan(struct list_head *chans)
220{
221 struct chan *chan;
222
223 /* Close in reverse order as open in case more than one of them
224 * refers to the same device and they save and restore that device's
225 * state. Then, the first one opened will have the original state,
226 * so it must be the last closed.
227 */
228 list_for_each_entry_reverse(chan, chans, list) {
229 if(!chan->opened) continue;
230 if(chan->ops->close != NULL)
231 (*chan->ops->close)(chan->fd, chan->data);
232 chan->opened = 0;
233 chan->fd = -1;
234 }
235}
236
237int write_chan(struct list_head *chans, const char *buf, int len,
238 int write_irq)
239{
240 struct list_head *ele;
241 struct chan *chan = NULL;
242 int n, ret = 0;
243
244 list_for_each(ele, chans) {
245 chan = list_entry(ele, struct chan, list);
246 if (!chan->output || (chan->ops->write == NULL))
247 continue;
248 n = chan->ops->write(chan->fd, buf, len, chan->data);
249 if (chan->primary) {
250 ret = n;
251 if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
252 reactivate_fd(chan->fd, write_irq);
253 }
254 }
255 return(ret);
256}
257
258int console_write_chan(struct list_head *chans, const char *buf, int len)
259{
260 struct list_head *ele;
261 struct chan *chan;
262 int n, ret = 0;
263
264 list_for_each(ele, chans){
265 chan = list_entry(ele, struct chan, list);
266 if(!chan->output || (chan->ops->console_write == NULL))
267 continue;
268 n = chan->ops->console_write(chan->fd, buf, len, chan->data);
269 if(chan->primary) ret = n;
270 }
271 return(ret);
272}
273
274int console_open_chan(struct line *line, struct console *co, struct chan_opts *opts)
275{
276 if (!list_empty(&line->chan_list))
277 return 0;
278
279 if (0 != parse_chan_pair(line->init_str, &line->chan_list,
280 line->init_pri, co->index, opts))
281 return -1;
282 if (0 != open_chan(&line->chan_list))
283 return -1;
284 printk("Console initialized on /dev/%s%d\n",co->name,co->index);
285 return 0;
286}
287
288int chan_window_size(struct list_head *chans, unsigned short *rows_out,
289 unsigned short *cols_out)
290{
291 struct list_head *ele;
292 struct chan *chan;
293
294 list_for_each(ele, chans){
295 chan = list_entry(ele, struct chan, list);
296 if(chan->primary){
297 if(chan->ops->window_size == NULL) return(0);
298 return(chan->ops->window_size(chan->fd, chan->data,
299 rows_out, cols_out));
300 }
301 }
302 return(0);
303}
304
305void free_one_chan(struct chan *chan)
306{
307 list_del(&chan->list);
308 if(chan->ops->free != NULL)
309 (*chan->ops->free)(chan->data);
310 free_irq_by_fd(chan->fd);
311 if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
312 kfree(chan);
313}
314
315void free_chan(struct list_head *chans)
316{
317 struct list_head *ele, *next;
318 struct chan *chan;
319
320 list_for_each_safe(ele, next, chans){
321 chan = list_entry(ele, struct chan, list);
322 free_one_chan(chan);
323 }
324}
325
326static int one_chan_config_string(struct chan *chan, char *str, int size,
327 char **error_out)
328{
329 int n = 0;
330
331 if(chan == NULL){
332 CONFIG_CHUNK(str, size, n, "none", 1);
333 return(n);
334 }
335
336 CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
337
338 if(chan->dev == NULL){
339 CONFIG_CHUNK(str, size, n, "", 1);
340 return(n);
341 }
342
343 CONFIG_CHUNK(str, size, n, ":", 0);
344 CONFIG_CHUNK(str, size, n, chan->dev, 0);
345
346 return(n);
347}
348
349static int chan_pair_config_string(struct chan *in, struct chan *out,
350 char *str, int size, char **error_out)
351{
352 int n;
353
354 n = one_chan_config_string(in, str, size, error_out);
355 str += n;
356 size -= n;
357
358 if(in == out){
359 CONFIG_CHUNK(str, size, n, "", 1);
360 return(n);
361 }
362
363 CONFIG_CHUNK(str, size, n, ",", 1);
364 n = one_chan_config_string(out, str, size, error_out);
365 str += n;
366 size -= n;
367 CONFIG_CHUNK(str, size, n, "", 1);
368
369 return(n);
370}
371
372int chan_config_string(struct list_head *chans, char *str, int size,
373 char **error_out)
374{
375 struct list_head *ele;
376 struct chan *chan, *in = NULL, *out = NULL;
377
378 list_for_each(ele, chans){
379 chan = list_entry(ele, struct chan, list);
380 if(!chan->primary)
381 continue;
382 if(chan->input)
383 in = chan;
384 if(chan->output)
385 out = chan;
386 }
387
388 return(chan_pair_config_string(in, out, str, size, error_out));
389}
390
391struct chan_type {
392 char *key;
393 struct chan_ops *ops;
394};
395
396struct chan_type chan_table[] = {
397 { "fd", &fd_ops },
398
399#ifdef CONFIG_NULL_CHAN
400 { "null", &null_ops },
401#else
402 { "null", &not_configged_ops },
403#endif
404
405#ifdef CONFIG_PORT_CHAN
406 { "port", &port_ops },
407#else
408 { "port", &not_configged_ops },
409#endif
410
411#ifdef CONFIG_PTY_CHAN
412 { "pty", &pty_ops },
413 { "pts", &pts_ops },
414#else
415 { "pty", &not_configged_ops },
416 { "pts", &not_configged_ops },
417#endif
418
419#ifdef CONFIG_TTY_CHAN
420 { "tty", &tty_ops },
421#else
422 { "tty", &not_configged_ops },
423#endif
424
425#ifdef CONFIG_XTERM_CHAN
426 { "xterm", &xterm_ops },
427#else
428 { "xterm", &not_configged_ops },
429#endif
430};
431
432static struct chan *parse_chan(char *str, int pri, int device,
433 struct chan_opts *opts)
434{
435 struct chan_type *entry;
436 struct chan_ops *ops;
437 struct chan *chan;
438 void *data;
439 int i;
440
441 ops = NULL;
442 data = NULL;
443 for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){
444 entry = &chan_table[i];
445 if(!strncmp(str, entry->key, strlen(entry->key))){
446 ops = entry->ops;
447 str += strlen(entry->key);
448 break;
449 }
450 }
451 if(ops == NULL){
452 printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n",
453 str);
454 return(NULL);
455 }
456 if(ops->init == NULL) return(NULL);
457 data = (*ops->init)(str, device, opts);
458 if(data == NULL) return(NULL);
459
460 chan = kmalloc(sizeof(*chan), GFP_KERNEL);
461 if(chan == NULL) return(NULL);
462 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
463 .primary = 1,
464 .input = 0,
465 .output = 0,
466 .opened = 0,
467 .fd = -1,
468 .pri = pri,
469 .ops = ops,
470 .data = data });
471 return(chan);
472}
473
474int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
475 struct chan_opts *opts)
476{
477 struct chan *new, *chan;
478 char *in, *out;
479
480 if(!list_empty(chans)){
481 chan = list_entry(chans->next, struct chan, list);
482 if(chan->pri >= pri) return(0);
483 free_chan(chans);
484 INIT_LIST_HEAD(chans);
485 }
486
487 out = strchr(str, ',');
488 if(out != NULL){
489 in = str;
490 *out = '\0';
491 out++;
492 new = parse_chan(in, pri, device, opts);
493 if(new == NULL) return(-1);
494 new->input = 1;
495 list_add(&new->list, chans);
496
497 new = parse_chan(out, pri, device, opts);
498 if(new == NULL) return(-1);
499 list_add(&new->list, chans);
500 new->output = 1;
501 }
502 else {
503 new = parse_chan(str, pri, device, opts);
504 if(new == NULL) return(-1);
505 list_add(&new->list, chans);
506 new->input = 1;
507 new->output = 1;
508 }
509 return(0);
510}
511
512int chan_out_fd(struct list_head *chans)
513{
514 struct list_head *ele;
515 struct chan *chan;
516
517 list_for_each(ele, chans){
518 chan = list_entry(ele, struct chan, list);
519 if(chan->primary && chan->output)
520 return(chan->fd);
521 }
522 return(-1);
523}
524
525void chan_interrupt(struct list_head *chans, struct work_struct *task,
526 struct tty_struct *tty, int irq)
527{
528 struct list_head *ele, *next;
529 struct chan *chan;
530 int err;
531 char c;
532
533 list_for_each_safe(ele, next, chans){
534 chan = list_entry(ele, struct chan, list);
535 if(!chan->input || (chan->ops->read == NULL)) continue;
536 do {
537 if((tty != NULL) &&
538 (tty->flip.count >= TTY_FLIPBUF_SIZE)){
539 schedule_work(task);
540 goto out;
541 }
542 err = chan->ops->read(chan->fd, &c, chan->data);
543 if(err > 0)
544 tty_receive_char(tty, c);
545 } while(err > 0);
546
547 if(err == 0) reactivate_fd(chan->fd, irq);
548 if(err == -EIO){
549 if(chan->primary){
550 if(tty != NULL)
551 tty_hangup(tty);
552 line_disable(tty, irq);
553 close_chan(chans);
554 free_chan(chans);
555 return;
556 }
557 else {
558 if(chan->ops->close != NULL)
559 chan->ops->close(chan->fd, chan->data);
560 free_one_chan(chan);
561 }
562 }
563 }
564 out:
565 if(tty) tty_flip_buffer_push(tty);
566}
567
568/*
569 * Overrides for Emacs so that we follow Linus's tabbing style.
570 * Emacs will notice this stuff at the end of the file and automatically
571 * adjust the settings for this buffer only. This must remain at the end
572 * of the file.
573 * ---------------------------------------------------------------------------
574 * Local variables:
575 * c-file-style: "linux"
576 * End:
577 */
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
new file mode 100644
index 000000000000..583b8e137c33
--- /dev/null
+++ b/arch/um/drivers/chan_user.c
@@ -0,0 +1,210 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <stdlib.h>
8#include <errno.h>
9#include <termios.h>
10#include <string.h>
11#include <signal.h>
12#include <sys/stat.h>
13#include <sys/ioctl.h>
14#include <sys/socket.h>
15#include "kern_util.h"
16#include "user_util.h"
17#include "chan_user.h"
18#include "user.h"
19#include "helper.h"
20#include "os.h"
21#include "choose-mode.h"
22#include "mode.h"
23
24int generic_console_write(int fd, const char *buf, int n, void *unused)
25{
26 struct termios save, new;
27 int err;
28
29 if(isatty(fd)){
30 CATCH_EINTR(err = tcgetattr(fd, &save));
31 if (err)
32 goto error;
33 new = save;
34 /* The terminal becomes a bit less raw, to handle \n also as
35 * "Carriage Return", not only as "New Line". Otherwise, the new
36 * line won't start at the first column.*/
37 new.c_oflag |= OPOST;
38 CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new));
39 if (err)
40 goto error;
41 }
42 err = generic_write(fd, buf, n, NULL);
43 /* Restore raw mode, in any case; we *must* ignore any error apart
44 * EINTR, except for debug.*/
45 if(isatty(fd))
46 CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save));
47 return(err);
48error:
49 return(-errno);
50}
51
52/*
53 * UML SIGWINCH handling
54 *
55 * The point of this is to handle SIGWINCH on consoles which have host ttys and
56 * relay them inside UML to whatever might be running on the console and cares
57 * about the window size (since SIGWINCH notifies about terminal size changes).
58 *
59 * So, we have a separate thread for each host tty attached to a UML device
60 * (side-issue - I'm annoyed that one thread can't have multiple controlling
61 * ttys for purposed of handling SIGWINCH, but I imagine there are other reasons
62 * that doesn't make any sense).
63 *
64 * SIGWINCH can't be received synchronously, so you have to set up to receive it
65 * as a signal. That being the case, if you are going to wait for it, it is
66 * convenient to sit in a pause() and wait for the signal to bounce you out of
67 * it (see below for how we make sure to exit only on SIGWINCH).
68 */
69
70static void winch_handler(int sig)
71{
72}
73
74struct winch_data {
75 int pty_fd;
76 int pipe_fd;
77 int close_me;
78};
79
80static int winch_thread(void *arg)
81{
82 struct winch_data *data = arg;
83 sigset_t sigs;
84 int pty_fd, pipe_fd;
85 int count, err;
86 char c = 1;
87
88 os_close_file(data->close_me);
89 pty_fd = data->pty_fd;
90 pipe_fd = data->pipe_fd;
91 count = os_write_file(pipe_fd, &c, sizeof(c));
92 if(count != sizeof(c))
93 printk("winch_thread : failed to write synchronization "
94 "byte, err = %d\n", -count);
95
96 /* We are not using SIG_IGN on purpose, so don't fix it as I thought to
97 * do! If using SIG_IGN, the pause() call below would not stop on
98 * SIGWINCH. */
99
100 signal(SIGWINCH, winch_handler);
101 sigfillset(&sigs);
102 sigdelset(&sigs, SIGWINCH);
103 /* Block anything else than SIGWINCH. */
104 if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){
105 printk("winch_thread : sigprocmask failed, errno = %d\n",
106 errno);
107 exit(1);
108 }
109
110 if(setsid() < 0){
111 printk("winch_thread : setsid failed, errno = %d\n", errno);
112 exit(1);
113 }
114
115 err = os_new_tty_pgrp(pty_fd, os_getpid());
116 if(err < 0){
117 printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err);
118 exit(1);
119 }
120
121 /* These are synchronization calls between various UML threads on the
122 * host - since they are not different kernel threads, we cannot use
123 * kernel semaphores. We don't use SysV semaphores because they are
124 * persistant. */
125 count = os_read_file(pipe_fd, &c, sizeof(c));
126 if(count != sizeof(c))
127 printk("winch_thread : failed to read synchronization byte, "
128 "err = %d\n", -count);
129
130 while(1){
131 /* This will be interrupted by SIGWINCH only, since other signals
132 * are blocked.*/
133 pause();
134
135 count = os_write_file(pipe_fd, &c, sizeof(c));
136 if(count != sizeof(c))
137 printk("winch_thread : write failed, err = %d\n",
138 -count);
139 }
140}
141
142static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
143{
144 struct winch_data data;
145 unsigned long stack;
146 int fds[2], pid, n, err;
147 char c;
148
149 err = os_pipe(fds, 1, 1);
150 if(err < 0){
151 printk("winch_tramp : os_pipe failed, err = %d\n", -err);
152 return(err);
153 }
154
155 data = ((struct winch_data) { .pty_fd = fd,
156 .pipe_fd = fds[1],
157 .close_me = fds[0] } );
158 pid = run_helper_thread(winch_thread, &data, 0, &stack, 0);
159 if(pid < 0){
160 printk("fork of winch_thread failed - errno = %d\n", errno);
161 return(pid);
162 }
163
164 os_close_file(fds[1]);
165 *fd_out = fds[0];
166 n = os_read_file(fds[0], &c, sizeof(c));
167 if(n != sizeof(c)){
168 printk("winch_tramp : failed to read synchronization byte\n");
169 printk("read failed, err = %d\n", -n);
170 printk("fd %d will not support SIGWINCH\n", fd);
171 *fd_out = -1;
172 }
173 return(pid);
174}
175
176void register_winch(int fd, struct tty_struct *tty)
177{
178 int pid, thread, thread_fd;
179 int count;
180 char c = 1;
181
182 if(!isatty(fd))
183 return;
184
185 pid = tcgetpgrp(fd);
186 if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd,
187 tty) && (pid == -1)){
188 thread = winch_tramp(fd, tty, &thread_fd);
189 if(fd != -1){
190 register_winch_irq(thread_fd, fd, thread, tty);
191
192 count = os_write_file(thread_fd, &c, sizeof(c));
193 if(count != sizeof(c))
194 printk("register_winch : failed to write "
195 "synchronization byte, err = %d\n",
196 -count);
197 }
198 }
199}
200
201/*
202 * Overrides for Emacs so that we follow Linus's tabbing style.
203 * Emacs will notice this stuff at the end of the file and automatically
204 * adjust the settings for this buffer only. This must remain at the end
205 * of the file.
206 * ---------------------------------------------------------------------------
207 * Local variables:
208 * c-file-style: "linux"
209 * End:
210 */
diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h
new file mode 100644
index 000000000000..4fcbe8b1b77e
--- /dev/null
+++ b/arch/um/drivers/cow.h
@@ -0,0 +1,42 @@
1#ifndef __COW_H__
2#define __COW_H__
3
4#include <asm/types.h>
5
6#if __BYTE_ORDER == __BIG_ENDIAN
7# define ntohll(x) (x)
8# define htonll(x) (x)
9#elif __BYTE_ORDER == __LITTLE_ENDIAN
10# define ntohll(x) bswap_64(x)
11# define htonll(x) bswap_64(x)
12#else
13#error "__BYTE_ORDER not defined"
14#endif
15
16extern int init_cow_file(int fd, char *cow_file, char *backing_file,
17 int sectorsize, int alignment, int *bitmap_offset_out,
18 unsigned long *bitmap_len_out, int *data_offset_out);
19
20extern int file_reader(__u64 offset, char *buf, int len, void *arg);
21extern int read_cow_header(int (*reader)(__u64, char *, int, void *),
22 void *arg, __u32 *version_out,
23 char **backing_file_out, time_t *mtime_out,
24 unsigned long long *size_out, int *sectorsize_out,
25 __u32 *align_out, int *bitmap_offset_out);
26
27extern int write_cow_header(char *cow_file, int fd, char *backing_file,
28 int sectorsize, int alignment,
29 unsigned long long *size);
30
31extern void cow_sizes(int version, __u64 size, int sectorsize, int align,
32 int bitmap_offset, unsigned long *bitmap_len_out,
33 int *data_offset_out);
34
35#endif
36
37/*
38 * ---------------------------------------------------------------------------
39 * Local variables:
40 * c-file-style: "linux"
41 * End:
42 */
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
new file mode 100644
index 000000000000..c83fc5d68936
--- /dev/null
+++ b/arch/um/drivers/cow_sys.h
@@ -0,0 +1,48 @@
1#ifndef __COW_SYS_H__
2#define __COW_SYS_H__
3
4#include "kern_util.h"
5#include "user_util.h"
6#include "os.h"
7#include "user.h"
8
9static inline void *cow_malloc(int size)
10{
11 return(um_kmalloc(size));
12}
13
14static inline void cow_free(void *ptr)
15{
16 kfree(ptr);
17}
18
19#define cow_printf printk
20
21static inline char *cow_strdup(char *str)
22{
23 return(uml_strdup(str));
24}
25
26static inline int cow_seek_file(int fd, unsigned long long offset)
27{
28 return(os_seek_file(fd, offset));
29}
30
31static inline int cow_file_size(char *file, unsigned long long *size_out)
32{
33 return(os_file_size(file, size_out));
34}
35
36static inline int cow_write_file(int fd, char *buf, int size)
37{
38 return(os_write_file(fd, buf, size));
39}
40
41#endif
42
43/*
44 * ---------------------------------------------------------------------------
45 * Local variables:
46 * c-file-style: "linux"
47 * End:
48 */
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c
new file mode 100644
index 000000000000..a8ce6fc3ef26
--- /dev/null
+++ b/arch/um/drivers/cow_user.c
@@ -0,0 +1,378 @@
1#include <stddef.h>
2#include <string.h>
3#include <errno.h>
4/* _XOPEN_SOURCE is needed for pread, but we define _GNU_SOURCE, which defines
5 * that.
6 */
7#include <unistd.h>
8#include <byteswap.h>
9#include <sys/time.h>
10#include <sys/param.h>
11#include <sys/user.h>
12#include <netinet/in.h>
13
14#include "os.h"
15
16#include "cow.h"
17#include "cow_sys.h"
18
19#define PATH_LEN_V1 256
20
21struct cow_header_v1 {
22 int magic;
23 int version;
24 char backing_file[PATH_LEN_V1];
25 time_t mtime;
26 __u64 size;
27 int sectorsize;
28};
29
30#define PATH_LEN_V2 MAXPATHLEN
31
32struct cow_header_v2 {
33 __u32 magic;
34 __u32 version;
35 char backing_file[PATH_LEN_V2];
36 time_t mtime;
37 __u64 size;
38 int sectorsize;
39};
40
41/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in
42 * case other systems have different values for MAXPATHLEN
43 */
44#define PATH_LEN_V3 4096
45
46/* Changes from V2 -
47 * PATH_LEN_V3 as described above
48 * Explicitly specify field bit lengths for systems with different
49 * lengths for the usual C types. Not sure whether char or
50 * time_t should be changed, this can be changed later without
51 * breaking compatibility
52 * Add alignment field so that different alignments can be used for the
53 * bitmap and data
54 * Add cow_format field to allow for the possibility of different ways
55 * of specifying the COW blocks. For now, the only value is 0,
56 * for the traditional COW bitmap.
57 * Move the backing_file field to the end of the header. This allows
58 * for the possibility of expanding it into the padding required
59 * by the bitmap alignment.
60 * The bitmap and data portions of the file will be aligned as specified
61 * by the alignment field. This is to allow COW files to be
62 * put on devices with restrictions on access alignments, such as
63 * /dev/raw, with a 512 byte alignment restriction. This also
64 * allows the data to be more aligned more strictly than on
65 * sector boundaries. This is needed for ubd-mmap, which needs
66 * the data to be page aligned.
67 * Fixed (finally!) the rounding bug
68 */
69
70struct cow_header_v3 {
71 __u32 magic;
72 __u32 version;
73 __u32 mtime;
74 __u64 size;
75 __u32 sectorsize;
76 __u32 alignment;
77 __u32 cow_format;
78 char backing_file[PATH_LEN_V3];
79};
80
81/* COW format definitions - for now, we have only the usual COW bitmap */
82#define COW_BITMAP 0
83
84union cow_header {
85 struct cow_header_v1 v1;
86 struct cow_header_v2 v2;
87 struct cow_header_v3 v3;
88};
89
90#define COW_MAGIC 0x4f4f4f4d /* MOOO */
91#define COW_VERSION 3
92
93#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
94#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
95
96void cow_sizes(int version, __u64 size, int sectorsize, int align,
97 int bitmap_offset, unsigned long *bitmap_len_out,
98 int *data_offset_out)
99{
100 if(version < 3){
101 *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
102
103 *data_offset_out = bitmap_offset + *bitmap_len_out;
104 *data_offset_out = (*data_offset_out + sectorsize - 1) /
105 sectorsize;
106 *data_offset_out *= sectorsize;
107 }
108 else {
109 *bitmap_len_out = DIV_ROUND(size, sectorsize);
110 *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
111
112 *data_offset_out = bitmap_offset + *bitmap_len_out;
113 *data_offset_out = ROUND_UP(*data_offset_out, align);
114 }
115}
116
117static int absolutize(char *to, int size, char *from)
118{
119 char save_cwd[256], *slash;
120 int remaining;
121
122 if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
123 cow_printf("absolutize : unable to get cwd - errno = %d\n",
124 errno);
125 return(-1);
126 }
127 slash = strrchr(from, '/');
128 if(slash != NULL){
129 *slash = '\0';
130 if(chdir(from)){
131 *slash = '/';
132 cow_printf("absolutize : Can't cd to '%s' - "
133 "errno = %d\n", from, errno);
134 return(-1);
135 }
136 *slash = '/';
137 if(getcwd(to, size) == NULL){
138 cow_printf("absolutize : unable to get cwd of '%s' - "
139 "errno = %d\n", from, errno);
140 return(-1);
141 }
142 remaining = size - strlen(to);
143 if(strlen(slash) + 1 > remaining){
144 cow_printf("absolutize : unable to fit '%s' into %d "
145 "chars\n", from, size);
146 return(-1);
147 }
148 strcat(to, slash);
149 }
150 else {
151 if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
152 cow_printf("absolutize : unable to fit '%s' into %d "
153 "chars\n", from, size);
154 return(-1);
155 }
156 strcpy(to, save_cwd);
157 strcat(to, "/");
158 strcat(to, from);
159 }
160 chdir(save_cwd);
161 return(0);
162}
163
164int write_cow_header(char *cow_file, int fd, char *backing_file,
165 int sectorsize, int alignment, unsigned long long *size)
166{
167 struct cow_header_v3 *header;
168 unsigned long modtime;
169 int err;
170
171 err = cow_seek_file(fd, 0);
172 if(err < 0){
173 cow_printf("write_cow_header - lseek failed, err = %d\n", -err);
174 goto out;
175 }
176
177 err = -ENOMEM;
178 header = cow_malloc(sizeof(*header));
179 if(header == NULL){
180 cow_printf("Failed to allocate COW V3 header\n");
181 goto out;
182 }
183 header->magic = htonl(COW_MAGIC);
184 header->version = htonl(COW_VERSION);
185
186 err = -EINVAL;
187 if(strlen(backing_file) > sizeof(header->backing_file) - 1){
188 cow_printf("Backing file name \"%s\" is too long - names are "
189 "limited to %d characters\n", backing_file,
190 sizeof(header->backing_file) - 1);
191 goto out_free;
192 }
193
194 if(absolutize(header->backing_file, sizeof(header->backing_file),
195 backing_file))
196 goto out_free;
197
198 err = os_file_modtime(header->backing_file, &modtime);
199 if(err < 0){
200 cow_printf("Backing file '%s' mtime request failed, "
201 "err = %d\n", header->backing_file, -err);
202 goto out_free;
203 }
204
205 err = cow_file_size(header->backing_file, size);
206 if(err < 0){
207 cow_printf("Couldn't get size of backing file '%s', "
208 "err = %d\n", header->backing_file, -err);
209 goto out_free;
210 }
211
212 header->mtime = htonl(modtime);
213 header->size = htonll(*size);
214 header->sectorsize = htonl(sectorsize);
215 header->alignment = htonl(alignment);
216 header->cow_format = COW_BITMAP;
217
218 err = os_write_file(fd, header, sizeof(*header));
219 if(err != sizeof(*header)){
220 cow_printf("Write of header to new COW file '%s' failed, "
221 "err = %d\n", cow_file, -err);
222 goto out_free;
223 }
224 err = 0;
225 out_free:
226 cow_free(header);
227 out:
228 return(err);
229}
230
231int file_reader(__u64 offset, char *buf, int len, void *arg)
232{
233 int fd = *((int *) arg);
234
235 return(pread(fd, buf, len, offset));
236}
237
238/* XXX Need to sanity-check the values read from the header */
239
240int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
241 __u32 *version_out, char **backing_file_out,
242 time_t *mtime_out, unsigned long long *size_out,
243 int *sectorsize_out, __u32 *align_out,
244 int *bitmap_offset_out)
245{
246 union cow_header *header;
247 char *file;
248 int err, n;
249 unsigned long version, magic;
250
251 header = cow_malloc(sizeof(*header));
252 if(header == NULL){
253 cow_printf("read_cow_header - Failed to allocate header\n");
254 return(-ENOMEM);
255 }
256 err = -EINVAL;
257 n = (*reader)(0, (char *) header, sizeof(*header), arg);
258 if(n < offsetof(typeof(header->v1), backing_file)){
259 cow_printf("read_cow_header - short header\n");
260 goto out;
261 }
262
263 magic = header->v1.magic;
264 if(magic == COW_MAGIC) {
265 version = header->v1.version;
266 }
267 else if(magic == ntohl(COW_MAGIC)){
268 version = ntohl(header->v1.version);
269 }
270 /* No error printed because the non-COW case comes through here */
271 else goto out;
272
273 *version_out = version;
274
275 if(version == 1){
276 if(n < sizeof(header->v1)){
277 cow_printf("read_cow_header - failed to read V1 "
278 "header\n");
279 goto out;
280 }
281 *mtime_out = header->v1.mtime;
282 *size_out = header->v1.size;
283 *sectorsize_out = header->v1.sectorsize;
284 *bitmap_offset_out = sizeof(header->v1);
285 *align_out = *sectorsize_out;
286 file = header->v1.backing_file;
287 }
288 else if(version == 2){
289 if(n < sizeof(header->v2)){
290 cow_printf("read_cow_header - failed to read V2 "
291 "header\n");
292 goto out;
293 }
294 *mtime_out = ntohl(header->v2.mtime);
295 *size_out = ntohll(header->v2.size);
296 *sectorsize_out = ntohl(header->v2.sectorsize);
297 *bitmap_offset_out = sizeof(header->v2);
298 *align_out = *sectorsize_out;
299 file = header->v2.backing_file;
300 }
301 else if(version == 3){
302 if(n < sizeof(header->v3)){
303 cow_printf("read_cow_header - failed to read V2 "
304 "header\n");
305 goto out;
306 }
307 *mtime_out = ntohl(header->v3.mtime);
308 *size_out = ntohll(header->v3.size);
309 *sectorsize_out = ntohl(header->v3.sectorsize);
310 *align_out = ntohl(header->v3.alignment);
311 *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out);
312 file = header->v3.backing_file;
313 }
314 else {
315 cow_printf("read_cow_header - invalid COW version\n");
316 goto out;
317 }
318 err = -ENOMEM;
319 *backing_file_out = cow_strdup(file);
320 if(*backing_file_out == NULL){
321 cow_printf("read_cow_header - failed to allocate backing "
322 "file\n");
323 goto out;
324 }
325 err = 0;
326 out:
327 cow_free(header);
328 return(err);
329}
330
331int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
332 int alignment, int *bitmap_offset_out,
333 unsigned long *bitmap_len_out, int *data_offset_out)
334{
335 unsigned long long size, offset;
336 char zero = 0;
337 int err;
338
339 err = write_cow_header(cow_file, fd, backing_file, sectorsize,
340 alignment, &size);
341 if(err)
342 goto out;
343
344 *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
345 cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
346 bitmap_len_out, data_offset_out);
347
348 offset = *data_offset_out + size - sizeof(zero);
349 err = cow_seek_file(fd, offset);
350 if(err < 0){
351 cow_printf("cow bitmap lseek failed : err = %d\n", -err);
352 goto out;
353 }
354
355 /* does not really matter how much we write it is just to set EOF
356 * this also sets the entire COW bitmap
357 * to zero without having to allocate it
358 */
359 err = cow_write_file(fd, &zero, sizeof(zero));
360 if(err != sizeof(zero)){
361 cow_printf("Write of bitmap to new COW file '%s' failed, "
362 "err = %d\n", cow_file, -err);
363 err = -EINVAL;
364 goto out;
365 }
366
367 return(0);
368
369 out:
370 return(err);
371}
372
373/*
374 * ---------------------------------------------------------------------------
375 * Local variables:
376 * c-file-style: "linux"
377 * End:
378 */
diff --git a/arch/um/drivers/daemon.h b/arch/um/drivers/daemon.h
new file mode 100644
index 000000000000..7326c42f7ef9
--- /dev/null
+++ b/arch/um/drivers/daemon.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "net_user.h"
7
8#define SWITCH_VERSION 3
9
10struct daemon_data {
11 char *sock_type;
12 char *ctl_sock;
13 void *ctl_addr;
14 void *data_addr;
15 void *local_addr;
16 int fd;
17 int control;
18 void *dev;
19};
20
21extern struct net_user_info daemon_user_info;
22
23extern int daemon_user_write(int fd, void *buf, int len,
24 struct daemon_data *pri);
25
26/*
27 * Overrides for Emacs so that we follow Linus's tabbing style.
28 * Emacs will notice this stuff at the end of the file and automatically
29 * adjust the settings for this buffer only. This must remain at the end
30 * of the file.
31 * ---------------------------------------------------------------------------
32 * Local variables:
33 * c-file-style: "linux"
34 * End:
35 */
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
new file mode 100644
index 000000000000..30d285b266af
--- /dev/null
+++ b/arch/um/drivers/daemon_kern.c
@@ -0,0 +1,108 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
3 * James Leu (jleu@mindspring.net).
4 * Copyright (C) 2001 by various other people who didn't put their name here.
5 * Licensed under the GPL.
6 */
7
8#include "linux/kernel.h"
9#include "linux/init.h"
10#include "linux/netdevice.h"
11#include "linux/etherdevice.h"
12#include "net_kern.h"
13#include "net_user.h"
14#include "daemon.h"
15
16struct daemon_init {
17 char *sock_type;
18 char *ctl_sock;
19};
20
21void daemon_init(struct net_device *dev, void *data)
22{
23 struct uml_net_private *pri;
24 struct daemon_data *dpri;
25 struct daemon_init *init = data;
26
27 pri = dev->priv;
28 dpri = (struct daemon_data *) pri->user;
29 dpri->sock_type = init->sock_type;
30 dpri->ctl_sock = init->ctl_sock;
31 dpri->fd = -1;
32 dpri->control = -1;
33 dpri->dev = dev;
34
35 printk("daemon backend (uml_switch version %d) - %s:%s",
36 SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock);
37 printk("\n");
38}
39
40static int daemon_read(int fd, struct sk_buff **skb,
41 struct uml_net_private *lp)
42{
43 *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
44 if(*skb == NULL) return(-ENOMEM);
45 return(net_recvfrom(fd, (*skb)->mac.raw,
46 (*skb)->dev->mtu + ETH_HEADER_OTHER));
47}
48
49static int daemon_write(int fd, struct sk_buff **skb,
50 struct uml_net_private *lp)
51{
52 return(daemon_user_write(fd, (*skb)->data, (*skb)->len,
53 (struct daemon_data *) &lp->user));
54}
55
56static struct net_kern_info daemon_kern_info = {
57 .init = daemon_init,
58 .protocol = eth_protocol,
59 .read = daemon_read,
60 .write = daemon_write,
61};
62
63int daemon_setup(char *str, char **mac_out, void *data)
64{
65 struct daemon_init *init = data;
66 char *remain;
67
68 *init = ((struct daemon_init)
69 { .sock_type = "unix",
70 .ctl_sock = "/tmp/uml.ctl" });
71
72 remain = split_if_spec(str, mac_out, &init->sock_type, &init->ctl_sock,
73 NULL);
74 if(remain != NULL)
75 printk(KERN_WARNING "daemon_setup : Ignoring data socket "
76 "specification\n");
77
78 return(1);
79}
80
81static struct transport daemon_transport = {
82 .list = LIST_HEAD_INIT(daemon_transport.list),
83 .name = "daemon",
84 .setup = daemon_setup,
85 .user = &daemon_user_info,
86 .kern = &daemon_kern_info,
87 .private_size = sizeof(struct daemon_data),
88 .setup_size = sizeof(struct daemon_init),
89};
90
91static int register_daemon(void)
92{
93 register_transport(&daemon_transport);
94 return(1);
95}
96
97__initcall(register_daemon);
98
99/*
100 * Overrides for Emacs so that we follow Linus's tabbing style.
101 * Emacs will notice this stuff at the end of the file and automatically
102 * adjust the settings for this buffer only. This must remain at the end
103 * of the file.
104 * ---------------------------------------------------------------------------
105 * Local variables:
106 * c-file-style: "linux"
107 * End:
108 */
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
new file mode 100644
index 000000000000..cf15b4a8b517
--- /dev/null
+++ b/arch/um/drivers/daemon_user.c
@@ -0,0 +1,197 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
3 * James Leu (jleu@mindspring.net).
4 * Copyright (C) 2001 by various other people who didn't put their name here.
5 * Licensed under the GPL.
6 */
7
8#include <errno.h>
9#include <unistd.h>
10#include <stdint.h>
11#include <sys/socket.h>
12#include <sys/un.h>
13#include <sys/time.h>
14#include "net_user.h"
15#include "daemon.h"
16#include "kern_util.h"
17#include "user_util.h"
18#include "user.h"
19#include "os.h"
20
21#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
22
23enum request_type { REQ_NEW_CONTROL };
24
25#define SWITCH_MAGIC 0xfeedface
26
27struct request_v3 {
28 uint32_t magic;
29 uint32_t version;
30 enum request_type type;
31 struct sockaddr_un sock;
32};
33
34static struct sockaddr_un *new_addr(void *name, int len)
35{
36 struct sockaddr_un *sun;
37
38 sun = um_kmalloc(sizeof(struct sockaddr_un));
39 if(sun == NULL){
40 printk("new_addr: allocation of sockaddr_un failed\n");
41 return(NULL);
42 }
43 sun->sun_family = AF_UNIX;
44 memcpy(sun->sun_path, name, len);
45 return(sun);
46}
47
48static int connect_to_switch(struct daemon_data *pri)
49{
50 struct sockaddr_un *ctl_addr = pri->ctl_addr;
51 struct sockaddr_un *local_addr = pri->local_addr;
52 struct sockaddr_un *sun;
53 struct request_v3 req;
54 int fd, n, err;
55
56 pri->control = socket(AF_UNIX, SOCK_STREAM, 0);
57 if(pri->control < 0){
58 printk("daemon_open : control socket failed, errno = %d\n",
59 errno);
60 return(-errno);
61 }
62
63 if(connect(pri->control, (struct sockaddr *) ctl_addr,
64 sizeof(*ctl_addr)) < 0){
65 printk("daemon_open : control connect failed, errno = %d\n",
66 errno);
67 err = -errno;
68 goto out;
69 }
70
71 fd = socket(AF_UNIX, SOCK_DGRAM, 0);
72 if(fd < 0){
73 printk("daemon_open : data socket failed, errno = %d\n",
74 errno);
75 err = -errno;
76 goto out;
77 }
78 if(bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0){
79 printk("daemon_open : data bind failed, errno = %d\n",
80 errno);
81 err = -errno;
82 goto out_close;
83 }
84
85 sun = um_kmalloc(sizeof(struct sockaddr_un));
86 if(sun == NULL){
87 printk("new_addr: allocation of sockaddr_un failed\n");
88 err = -ENOMEM;
89 goto out_close;
90 }
91
92 req.magic = SWITCH_MAGIC;
93 req.version = SWITCH_VERSION;
94 req.type = REQ_NEW_CONTROL;
95 req.sock = *local_addr;
96 n = os_write_file(pri->control, &req, sizeof(req));
97 if(n != sizeof(req)){
98 printk("daemon_open : control setup request failed, err = %d\n",
99 -n);
100 err = -ENOTCONN;
101 goto out;
102 }
103
104 n = os_read_file(pri->control, sun, sizeof(*sun));
105 if(n != sizeof(*sun)){
106 printk("daemon_open : read of data socket failed, err = %d\n",
107 -n);
108 err = -ENOTCONN;
109 goto out_close;
110 }
111
112 pri->data_addr = sun;
113 return(fd);
114
115 out_close:
116 os_close_file(fd);
117 out:
118 os_close_file(pri->control);
119 return(err);
120}
121
122static void daemon_user_init(void *data, void *dev)
123{
124 struct daemon_data *pri = data;
125 struct timeval tv;
126 struct {
127 char zero;
128 int pid;
129 int usecs;
130 } name;
131
132 if(!strcmp(pri->sock_type, "unix"))
133 pri->ctl_addr = new_addr(pri->ctl_sock,
134 strlen(pri->ctl_sock) + 1);
135 name.zero = 0;
136 name.pid = os_getpid();
137 gettimeofday(&tv, NULL);
138 name.usecs = tv.tv_usec;
139 pri->local_addr = new_addr(&name, sizeof(name));
140 pri->dev = dev;
141 pri->fd = connect_to_switch(pri);
142 if(pri->fd < 0){
143 kfree(pri->local_addr);
144 pri->local_addr = NULL;
145 }
146}
147
148static int daemon_open(void *data)
149{
150 struct daemon_data *pri = data;
151 return(pri->fd);
152}
153
154static void daemon_remove(void *data)
155{
156 struct daemon_data *pri = data;
157
158 os_close_file(pri->fd);
159 os_close_file(pri->control);
160 if(pri->data_addr != NULL) kfree(pri->data_addr);
161 if(pri->ctl_addr != NULL) kfree(pri->ctl_addr);
162 if(pri->local_addr != NULL) kfree(pri->local_addr);
163}
164
165int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
166{
167 struct sockaddr_un *data_addr = pri->data_addr;
168
169 return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
170}
171
172static int daemon_set_mtu(int mtu, void *data)
173{
174 return(mtu);
175}
176
177struct net_user_info daemon_user_info = {
178 .init = daemon_user_init,
179 .open = daemon_open,
180 .close = NULL,
181 .remove = daemon_remove,
182 .set_mtu = daemon_set_mtu,
183 .add_address = NULL,
184 .delete_address = NULL,
185 .max_packet = MAX_PACKET - ETH_HEADER_OTHER
186};
187
188/*
189 * Overrides for Emacs so that we follow Linus's tabbing style.
190 * Emacs will notice this stuff at the end of the file and automatically
191 * adjust the settings for this buffer only. This must remain at the end
192 * of the file.
193 * ---------------------------------------------------------------------------
194 * Local variables:
195 * c-file-style: "linux"
196 * End:
197 */
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
new file mode 100644
index 000000000000..f0b888f66e05
--- /dev/null
+++ b/arch/um/drivers/fd.c
@@ -0,0 +1,108 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <termios.h>
10#include <errno.h>
11#include "user.h"
12#include "user_util.h"
13#include "chan_user.h"
14
15struct fd_chan {
16 int fd;
17 int raw;
18 struct termios tt;
19 char str[sizeof("1234567890\0")];
20};
21
22static void *fd_init(char *str, int device, struct chan_opts *opts)
23{
24 struct fd_chan *data;
25 char *end;
26 int n;
27
28 if(*str != ':'){
29 printk("fd_init : channel type 'fd' must specify a file "
30 "descriptor\n");
31 return(NULL);
32 }
33 str++;
34 n = strtoul(str, &end, 0);
35 if((*end != '\0') || (end == str)){
36 printk("fd_init : couldn't parse file descriptor '%s'\n", str);
37 return(NULL);
38 }
39 data = um_kmalloc(sizeof(*data));
40 if(data == NULL) return(NULL);
41 *data = ((struct fd_chan) { .fd = n,
42 .raw = opts->raw });
43 return(data);
44}
45
46static int fd_open(int input, int output, int primary, void *d, char **dev_out)
47{
48 struct fd_chan *data = d;
49 int err;
50
51 if(data->raw && isatty(data->fd)){
52 CATCH_EINTR(err = tcgetattr(data->fd, &data->tt));
53 if(err)
54 return(err);
55
56 err = raw(data->fd);
57 if(err)
58 return(err);
59 }
60 sprintf(data->str, "%d", data->fd);
61 *dev_out = data->str;
62 return(data->fd);
63}
64
65static void fd_close(int fd, void *d)
66{
67 struct fd_chan *data = d;
68 int err;
69
70 if(data->raw && isatty(fd)){
71 CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt));
72 if(err)
73 printk("Failed to restore terminal state - "
74 "errno = %d\n", -err);
75 data->raw = 0;
76 }
77}
78
79static int fd_console_write(int fd, const char *buf, int n, void *d)
80{
81 struct fd_chan *data = d;
82
83 return(generic_console_write(fd, buf, n, &data->tt));
84}
85
86struct chan_ops fd_ops = {
87 .type = "fd",
88 .init = fd_init,
89 .open = fd_open,
90 .close = fd_close,
91 .read = generic_read,
92 .write = generic_write,
93 .console_write = fd_console_write,
94 .window_size = generic_window_size,
95 .free = generic_free,
96 .winch = 1,
97};
98
99/*
100 * Overrides for Emacs so that we follow Linus's tabbing style.
101 * Emacs will notice this stuff at the end of the file and automatically
102 * adjust the settings for this buffer only. This must remain at the end
103 * of the file.
104 * ---------------------------------------------------------------------------
105 * Local variables:
106 * c-file-style: "linux"
107 * End:
108 */
diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c
new file mode 100644
index 000000000000..147ec19f6bb9
--- /dev/null
+++ b/arch/um/drivers/harddog_kern.c
@@ -0,0 +1,190 @@
1/* UML hardware watchdog, shamelessly stolen from:
2 *
3 * SoftDog 0.05: A Software Watchdog Device
4 *
5 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
6 * http://www.redhat.com
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
14 * warranty for any of this software. This material is provided
15 * "AS-IS" and at no charge.
16 *
17 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
18 *
19 * Software only watchdog driver. Unlike its big brother the WDT501P
20 * driver this won't always recover a failed machine.
21 *
22 * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
23 * Modularised.
24 * Added soft_margin; use upon insmod to change the timer delay.
25 * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
26 * minors.
27 *
28 * 19980911 Alan Cox
29 * Made SMP safe for 2.3.x
30 *
31 * 20011127 Joel Becker (jlbec@evilplan.org>
32 * Added soft_noboot; Allows testing the softdog trigger without
33 * requiring a recompile.
34 * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
35 */
36
37#include <linux/module.h>
38#include <linux/config.h>
39#include <linux/types.h>
40#include <linux/kernel.h>
41#include <linux/fs.h>
42#include <linux/mm.h>
43#include <linux/miscdevice.h>
44#include <linux/watchdog.h>
45#include <linux/reboot.h>
46#include <linux/smp_lock.h>
47#include <linux/init.h>
48#include <asm/uaccess.h>
49#include "helper.h"
50#include "mconsole.h"
51
52MODULE_LICENSE("GPL");
53
54/* Locked by the BKL in harddog_open and harddog_release */
55static int timer_alive;
56static int harddog_in_fd = -1;
57static int harddog_out_fd = -1;
58
59/*
60 * Allow only one person to hold it open
61 */
62
63extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock);
64
65static int harddog_open(struct inode *inode, struct file *file)
66{
67 int err;
68 char *sock = NULL;
69
70 lock_kernel();
71 if(timer_alive)
72 return -EBUSY;
73#ifdef CONFIG_HARDDOG_NOWAYOUT
74 __module_get(THIS_MODULE);
75#endif
76
77#ifdef CONFIG_MCONSOLE
78 sock = mconsole_notify_socket();
79#endif
80 err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock);
81 if(err) return(err);
82
83 timer_alive = 1;
84 unlock_kernel();
85 return nonseekable_open(inode, file);
86}
87
88extern void stop_watchdog(int in_fd, int out_fd);
89
90static int harddog_release(struct inode *inode, struct file *file)
91{
92 /*
93 * Shut off the timer.
94 */
95 lock_kernel();
96
97 stop_watchdog(harddog_in_fd, harddog_out_fd);
98 harddog_in_fd = -1;
99 harddog_out_fd = -1;
100
101 timer_alive=0;
102 unlock_kernel();
103 return 0;
104}
105
106extern int ping_watchdog(int fd);
107
108static ssize_t harddog_write(struct file *file, const char *data, size_t len,
109 loff_t *ppos)
110{
111 /*
112 * Refresh the timer.
113 */
114 if(len)
115 return(ping_watchdog(harddog_out_fd));
116 return 0;
117}
118
119static int harddog_ioctl(struct inode *inode, struct file *file,
120 unsigned int cmd, unsigned long arg)
121{
122 static struct watchdog_info ident = {
123 WDIOC_SETTIMEOUT,
124 0,
125 "UML Hardware Watchdog"
126 };
127 switch (cmd) {
128 default:
129 return -ENOTTY;
130 case WDIOC_GETSUPPORT:
131 if(copy_to_user((struct harddog_info *)arg, &ident,
132 sizeof(ident)))
133 return -EFAULT;
134 return 0;
135 case WDIOC_GETSTATUS:
136 case WDIOC_GETBOOTSTATUS:
137 return put_user(0,(int *)arg);
138 case WDIOC_KEEPALIVE:
139 return(ping_watchdog(harddog_out_fd));
140 }
141}
142
143static struct file_operations harddog_fops = {
144 .owner = THIS_MODULE,
145 .write = harddog_write,
146 .ioctl = harddog_ioctl,
147 .open = harddog_open,
148 .release = harddog_release,
149};
150
151static struct miscdevice harddog_miscdev = {
152 .minor = WATCHDOG_MINOR,
153 .name = "watchdog",
154 .fops = &harddog_fops,
155};
156
157static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n";
158
159static int __init harddog_init(void)
160{
161 int ret;
162
163 ret = misc_register(&harddog_miscdev);
164
165 if (ret)
166 return ret;
167
168 printk(banner);
169
170 return(0);
171}
172
173static void __exit harddog_exit(void)
174{
175 misc_deregister(&harddog_miscdev);
176}
177
178module_init(harddog_init);
179module_exit(harddog_exit);
180
181/*
182 * Overrides for Emacs so that we follow Linus's tabbing style.
183 * Emacs will notice this stuff at the end of the file and automatically
184 * adjust the settings for this buffer only. This must remain at the end
185 * of the file.
186 * ---------------------------------------------------------------------------
187 * Local variables:
188 * c-file-style: "linux"
189 * End:
190 */
diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c
new file mode 100644
index 000000000000..d934181b8d4c
--- /dev/null
+++ b/arch/um/drivers/harddog_user.c
@@ -0,0 +1,143 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <unistd.h>
8#include <errno.h>
9#include "user_util.h"
10#include "user.h"
11#include "helper.h"
12#include "mconsole.h"
13#include "os.h"
14#include "choose-mode.h"
15#include "mode.h"
16
17struct dog_data {
18 int stdin;
19 int stdout;
20 int close_me[2];
21};
22
23static void pre_exec(void *d)
24{
25 struct dog_data *data = d;
26
27 dup2(data->stdin, 0);
28 dup2(data->stdout, 1);
29 dup2(data->stdout, 2);
30 os_close_file(data->stdin);
31 os_close_file(data->stdout);
32 os_close_file(data->close_me[0]);
33 os_close_file(data->close_me[1]);
34}
35
36int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
37{
38 struct dog_data data;
39 int in_fds[2], out_fds[2], pid, n, err;
40 char pid_buf[sizeof("nnnnn\0")], c;
41 char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL };
42 char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL,
43 NULL };
44 char **args = NULL;
45
46 err = os_pipe(in_fds, 1, 0);
47 if(err < 0){
48 printk("harddog_open - os_pipe failed, err = %d\n", -err);
49 goto out;
50 }
51
52 err = os_pipe(out_fds, 1, 0);
53 if(err < 0){
54 printk("harddog_open - os_pipe failed, err = %d\n", -err);
55 goto out_close_in;
56 }
57
58 data.stdin = out_fds[0];
59 data.stdout = in_fds[1];
60 data.close_me[0] = out_fds[1];
61 data.close_me[1] = in_fds[0];
62
63 if(sock != NULL){
64 mconsole_args[2] = sock;
65 args = mconsole_args;
66 }
67 else {
68 /* XXX The os_getpid() is not SMP correct */
69 sprintf(pid_buf, "%d", CHOOSE_MODE(tracing_pid, os_getpid()));
70 args = pid_args;
71 }
72
73 pid = run_helper(pre_exec, &data, args, NULL);
74
75 os_close_file(out_fds[0]);
76 os_close_file(in_fds[1]);
77
78 if(pid < 0){
79 err = -pid;
80 printk("harddog_open - run_helper failed, errno = %d\n", -err);
81 goto out_close_out;
82 }
83
84 n = os_read_file(in_fds[0], &c, sizeof(c));
85 if(n == 0){
86 printk("harddog_open - EOF on watchdog pipe\n");
87 helper_wait(pid);
88 err = -EIO;
89 goto out_close_out;
90 }
91 else if(n < 0){
92 printk("harddog_open - read of watchdog pipe failed, "
93 "err = %d\n", -n);
94 helper_wait(pid);
95 err = n;
96 goto out_close_out;
97 }
98 *in_fd_ret = in_fds[0];
99 *out_fd_ret = out_fds[1];
100 return(0);
101
102 out_close_in:
103 os_close_file(in_fds[0]);
104 os_close_file(in_fds[1]);
105 out_close_out:
106 os_close_file(out_fds[0]);
107 os_close_file(out_fds[1]);
108 out:
109 return(err);
110}
111
112void stop_watchdog(int in_fd, int out_fd)
113{
114 os_close_file(in_fd);
115 os_close_file(out_fd);
116}
117
118int ping_watchdog(int fd)
119{
120 int n;
121 char c = '\n';
122
123 n = os_write_file(fd, &c, sizeof(c));
124 if(n != sizeof(c)){
125 printk("ping_watchdog - write failed, err = %d\n", -n);
126 if(n < 0)
127 return(n);
128 return(-EIO);
129 }
130 return 1;
131
132}
133
134/*
135 * Overrides for Emacs so that we follow Linus's tabbing style.
136 * Emacs will notice this stuff at the end of the file and automatically
137 * adjust the settings for this buffer only. This must remain at the end
138 * of the file.
139 * ---------------------------------------------------------------------------
140 * Local variables:
141 * c-file-style: "linux"
142 * End:
143 */
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
new file mode 100644
index 000000000000..d5742783e19d
--- /dev/null
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -0,0 +1,352 @@
1/*
2 * Copyright (C) 2002 Steve Schmidtke
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/module.h"
8#include "linux/init.h"
9#include "linux/slab.h"
10#include "linux/fs.h"
11#include "linux/sound.h"
12#include "linux/soundcard.h"
13#include "asm/uaccess.h"
14#include "kern_util.h"
15#include "init.h"
16#include "os.h"
17
18struct hostaudio_state {
19 int fd;
20};
21
22struct hostmixer_state {
23 int fd;
24};
25
26#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
27#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
28
29/* Only changed from linux_main at boot time */
30char *dsp = HOSTAUDIO_DEV_DSP;
31char *mixer = HOSTAUDIO_DEV_MIXER;
32
33#define DSP_HELP \
34" This is used to specify the host dsp device to the hostaudio driver.\n" \
35" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
36
37#define MIXER_HELP \
38" This is used to specify the host mixer device to the hostaudio driver.\n"\
39" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
40
41#ifndef MODULE
42static int set_dsp(char *name, int *add)
43{
44 dsp = name;
45 return(0);
46}
47
48__uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP);
49
50static int set_mixer(char *name, int *add)
51{
52 mixer = name;
53 return(0);
54}
55
56__uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
57
58#else /*MODULE*/
59
60MODULE_PARM(dsp, "s");
61MODULE_PARM_DESC(dsp, DSP_HELP);
62
63MODULE_PARM(mixer, "s");
64MODULE_PARM_DESC(mixer, MIXER_HELP);
65
66#endif
67
68/* /dev/dsp file operations */
69
70static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count,
71 loff_t *ppos)
72{
73 struct hostaudio_state *state = file->private_data;
74 void *kbuf;
75 int err;
76
77#ifdef DEBUG
78 printk("hostaudio: read called, count = %d\n", count);
79#endif
80
81 kbuf = kmalloc(count, GFP_KERNEL);
82 if(kbuf == NULL)
83 return(-ENOMEM);
84
85 err = os_read_file(state->fd, kbuf, count);
86 if(err < 0)
87 goto out;
88
89 if(copy_to_user(buffer, kbuf, err))
90 err = -EFAULT;
91
92 out:
93 kfree(kbuf);
94 return(err);
95}
96
97static ssize_t hostaudio_write(struct file *file, const char *buffer,
98 size_t count, loff_t *ppos)
99{
100 struct hostaudio_state *state = file->private_data;
101 void *kbuf;
102 int err;
103
104#ifdef DEBUG
105 printk("hostaudio: write called, count = %d\n", count);
106#endif
107
108 kbuf = kmalloc(count, GFP_KERNEL);
109 if(kbuf == NULL)
110 return(-ENOMEM);
111
112 err = -EFAULT;
113 if(copy_from_user(kbuf, buffer, count))
114 goto out;
115
116 err = os_write_file(state->fd, kbuf, count);
117 if(err < 0)
118 goto out;
119 *ppos += err;
120
121 out:
122 kfree(kbuf);
123 return(err);
124}
125
126static unsigned int hostaudio_poll(struct file *file,
127 struct poll_table_struct *wait)
128{
129 unsigned int mask = 0;
130
131#ifdef DEBUG
132 printk("hostaudio: poll called (unimplemented)\n");
133#endif
134
135 return(mask);
136}
137
138static int hostaudio_ioctl(struct inode *inode, struct file *file,
139 unsigned int cmd, unsigned long arg)
140{
141 struct hostaudio_state *state = file->private_data;
142 unsigned long data = 0;
143 int err;
144
145#ifdef DEBUG
146 printk("hostaudio: ioctl called, cmd = %u\n", cmd);
147#endif
148 switch(cmd){
149 case SNDCTL_DSP_SPEED:
150 case SNDCTL_DSP_STEREO:
151 case SNDCTL_DSP_GETBLKSIZE:
152 case SNDCTL_DSP_CHANNELS:
153 case SNDCTL_DSP_SUBDIVIDE:
154 case SNDCTL_DSP_SETFRAGMENT:
155 if(get_user(data, (int *) arg))
156 return(-EFAULT);
157 break;
158 default:
159 break;
160 }
161
162 err = os_ioctl_generic(state->fd, cmd, (unsigned long) &data);
163
164 switch(cmd){
165 case SNDCTL_DSP_SPEED:
166 case SNDCTL_DSP_STEREO:
167 case SNDCTL_DSP_GETBLKSIZE:
168 case SNDCTL_DSP_CHANNELS:
169 case SNDCTL_DSP_SUBDIVIDE:
170 case SNDCTL_DSP_SETFRAGMENT:
171 if(put_user(data, (int *) arg))
172 return(-EFAULT);
173 break;
174 default:
175 break;
176 }
177
178 return(err);
179}
180
181static int hostaudio_open(struct inode *inode, struct file *file)
182{
183 struct hostaudio_state *state;
184 int r = 0, w = 0;
185 int ret;
186
187#ifdef DEBUG
188 printk("hostaudio: open called (host: %s)\n", dsp);
189#endif
190
191 state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
192 if(state == NULL)
193 return(-ENOMEM);
194
195 if(file->f_mode & FMODE_READ) r = 1;
196 if(file->f_mode & FMODE_WRITE) w = 1;
197
198 ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
199 if(ret < 0){
200 kfree(state);
201 return(ret);
202 }
203
204 state->fd = ret;
205 file->private_data = state;
206 return(0);
207}
208
209static int hostaudio_release(struct inode *inode, struct file *file)
210{
211 struct hostaudio_state *state = file->private_data;
212
213#ifdef DEBUG
214 printk("hostaudio: release called\n");
215#endif
216
217 os_close_file(state->fd);
218 kfree(state);
219
220 return(0);
221}
222
223/* /dev/mixer file operations */
224
225static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file,
226 unsigned int cmd, unsigned long arg)
227{
228 struct hostmixer_state *state = file->private_data;
229
230#ifdef DEBUG
231 printk("hostmixer: ioctl called\n");
232#endif
233
234 return(os_ioctl_generic(state->fd, cmd, arg));
235}
236
237static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
238{
239 struct hostmixer_state *state;
240 int r = 0, w = 0;
241 int ret;
242
243#ifdef DEBUG
244 printk("hostmixer: open called (host: %s)\n", mixer);
245#endif
246
247 state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL);
248 if(state == NULL) return(-ENOMEM);
249
250 if(file->f_mode & FMODE_READ) r = 1;
251 if(file->f_mode & FMODE_WRITE) w = 1;
252
253 ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
254
255 if(ret < 0){
256 printk("hostaudio_open_mixdev failed to open '%s', err = %d\n",
257 dsp, -ret);
258 kfree(state);
259 return(ret);
260 }
261
262 file->private_data = state;
263 return(0);
264}
265
266static int hostmixer_release(struct inode *inode, struct file *file)
267{
268 struct hostmixer_state *state = file->private_data;
269
270#ifdef DEBUG
271 printk("hostmixer: release called\n");
272#endif
273
274 os_close_file(state->fd);
275 kfree(state);
276
277 return(0);
278}
279
280
281/* kernel module operations */
282
283static struct file_operations hostaudio_fops = {
284 .owner = THIS_MODULE,
285 .llseek = no_llseek,
286 .read = hostaudio_read,
287 .write = hostaudio_write,
288 .poll = hostaudio_poll,
289 .ioctl = hostaudio_ioctl,
290 .mmap = NULL,
291 .open = hostaudio_open,
292 .release = hostaudio_release,
293};
294
295static struct file_operations hostmixer_fops = {
296 .owner = THIS_MODULE,
297 .llseek = no_llseek,
298 .ioctl = hostmixer_ioctl_mixdev,
299 .open = hostmixer_open_mixdev,
300 .release = hostmixer_release,
301};
302
303struct {
304 int dev_audio;
305 int dev_mixer;
306} module_data;
307
308MODULE_AUTHOR("Steve Schmidtke");
309MODULE_DESCRIPTION("UML Audio Relay");
310MODULE_LICENSE("GPL");
311
312static int __init hostaudio_init_module(void)
313{
314 printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
315 dsp, mixer);
316
317 module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
318 if(module_data.dev_audio < 0){
319 printk(KERN_ERR "hostaudio: couldn't register DSP device!\n");
320 return -ENODEV;
321 }
322
323 module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1);
324 if(module_data.dev_mixer < 0){
325 printk(KERN_ERR "hostmixer: couldn't register mixer "
326 "device!\n");
327 unregister_sound_dsp(module_data.dev_audio);
328 return -ENODEV;
329 }
330
331 return 0;
332}
333
334static void __exit hostaudio_cleanup_module (void)
335{
336 unregister_sound_mixer(module_data.dev_mixer);
337 unregister_sound_dsp(module_data.dev_audio);
338}
339
340module_init(hostaudio_init_module);
341module_exit(hostaudio_cleanup_module);
342
343/*
344 * Overrides for Emacs so that we follow Linus's tabbing style.
345 * Emacs will notice this stuff at the end of the file and automatically
346 * adjust the settings for this buffer only. This must remain at the end
347 * of the file.
348 * ---------------------------------------------------------------------------
349 * Local variables:
350 * c-file-style: "linux"
351 * End:
352 */
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
new file mode 100644
index 000000000000..6924f273ced9
--- /dev/null
+++ b/arch/um/drivers/line.c
@@ -0,0 +1,681 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/slab.h"
8#include "linux/list.h"
9#include "linux/kd.h"
10#include "linux/interrupt.h"
11#include "linux/devfs_fs_kernel.h"
12#include "asm/uaccess.h"
13#include "chan_kern.h"
14#include "irq_user.h"
15#include "line.h"
16#include "kern.h"
17#include "user_util.h"
18#include "kern_util.h"
19#include "os.h"
20#include "irq_kern.h"
21
22#define LINE_BUFSIZE 4096
23
24static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused)
25{
26 struct tty_struct *tty = data;
27 struct line *line = tty->driver_data;
28
29 if (line)
30 chan_interrupt(&line->chan_list, &line->task, tty, irq);
31 return IRQ_HANDLED;
32}
33
34static void line_timer_cb(void *arg)
35{
36 struct tty_struct *tty = arg;
37 struct line *line = tty->driver_data;
38
39 line_interrupt(line->driver->read_irq, arg, NULL);
40}
41
42static int write_room(struct line *dev)
43{
44 int n;
45
46 if (dev->buffer == NULL)
47 return (LINE_BUFSIZE - 1);
48
49 n = dev->head - dev->tail;
50 if (n <= 0)
51 n = LINE_BUFSIZE + n;
52 return (n - 1);
53}
54
55static int buffer_data(struct line *line, const char *buf, int len)
56{
57 int end, room;
58
59 if(line->buffer == NULL){
60 line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
61 if (line->buffer == NULL) {
62 printk("buffer_data - atomic allocation failed\n");
63 return(0);
64 }
65 line->head = line->buffer;
66 line->tail = line->buffer;
67 }
68
69 room = write_room(line);
70 len = (len > room) ? room : len;
71
72 end = line->buffer + LINE_BUFSIZE - line->tail;
73 if(len < end){
74 memcpy(line->tail, buf, len);
75 line->tail += len;
76 }
77 else {
78 memcpy(line->tail, buf, end);
79 buf += end;
80 memcpy(line->buffer, buf, len - end);
81 line->tail = line->buffer + len - end;
82 }
83
84 return(len);
85}
86
87static int flush_buffer(struct line *line)
88{
89 int n, count;
90
91 if ((line->buffer == NULL) || (line->head == line->tail))
92 return(1);
93
94 if (line->tail < line->head) {
95 count = line->buffer + LINE_BUFSIZE - line->head;
96 n = write_chan(&line->chan_list, line->head, count,
97 line->driver->write_irq);
98 if (n < 0)
99 return(n);
100 if (n == count)
101 line->head = line->buffer;
102 else {
103 line->head += n;
104 return(0);
105 }
106 }
107
108 count = line->tail - line->head;
109 n = write_chan(&line->chan_list, line->head, count,
110 line->driver->write_irq);
111 if(n < 0) return(n);
112
113 line->head += n;
114 return(line->head == line->tail);
115}
116
117int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
118{
119 struct line *line = tty->driver_data;
120 unsigned long flags;
121 int n, err, ret = 0;
122
123 if(tty->stopped) return 0;
124
125 down(&line->sem);
126 if(line->head != line->tail){
127 local_irq_save(flags);
128 ret = buffer_data(line, buf, len);
129 err = flush_buffer(line);
130 local_irq_restore(flags);
131 if(err <= 0 && (err != -EAGAIN || !ret))
132 ret = err;
133 }
134 else {
135 n = write_chan(&line->chan_list, buf, len,
136 line->driver->write_irq);
137 if(n < 0){
138 ret = n;
139 goto out_up;
140 }
141
142 len -= n;
143 ret += n;
144 if(len > 0)
145 ret += buffer_data(line, buf + n, len);
146 }
147 out_up:
148 up(&line->sem);
149 return(ret);
150}
151
152void line_put_char(struct tty_struct *tty, unsigned char ch)
153{
154 line_write(tty, &ch, sizeof(ch));
155}
156
157void line_set_termios(struct tty_struct *tty, struct termios * old)
158{
159 /* nothing */
160}
161
162int line_chars_in_buffer(struct tty_struct *tty)
163{
164 return 0;
165}
166
167static struct {
168 int cmd;
169 char *level;
170 char *name;
171} tty_ioctls[] = {
172 /* don't print these, they flood the log ... */
173 { TCGETS, NULL, "TCGETS" },
174 { TCSETS, NULL, "TCSETS" },
175 { TCSETSW, NULL, "TCSETSW" },
176 { TCFLSH, NULL, "TCFLSH" },
177 { TCSBRK, NULL, "TCSBRK" },
178
179 /* general tty stuff */
180 { TCSETSF, KERN_DEBUG, "TCSETSF" },
181 { TCGETA, KERN_DEBUG, "TCGETA" },
182 { TIOCMGET, KERN_DEBUG, "TIOCMGET" },
183 { TCSBRKP, KERN_DEBUG, "TCSBRKP" },
184 { TIOCMSET, KERN_DEBUG, "TIOCMSET" },
185
186 /* linux-specific ones */
187 { TIOCLINUX, KERN_INFO, "TIOCLINUX" },
188 { KDGKBMODE, KERN_INFO, "KDGKBMODE" },
189 { KDGKBTYPE, KERN_INFO, "KDGKBTYPE" },
190 { KDSIGACCEPT, KERN_INFO, "KDSIGACCEPT" },
191};
192
193int line_ioctl(struct tty_struct *tty, struct file * file,
194 unsigned int cmd, unsigned long arg)
195{
196 int ret;
197 int i;
198
199 ret = 0;
200 switch(cmd) {
201#ifdef TIOCGETP
202 case TIOCGETP:
203 case TIOCSETP:
204 case TIOCSETN:
205#endif
206#ifdef TIOCGETC
207 case TIOCGETC:
208 case TIOCSETC:
209#endif
210#ifdef TIOCGLTC
211 case TIOCGLTC:
212 case TIOCSLTC:
213#endif
214 case TCGETS:
215 case TCSETSF:
216 case TCSETSW:
217 case TCSETS:
218 case TCGETA:
219 case TCSETAF:
220 case TCSETAW:
221 case TCSETA:
222 case TCXONC:
223 case TCFLSH:
224 case TIOCOUTQ:
225 case TIOCINQ:
226 case TIOCGLCKTRMIOS:
227 case TIOCSLCKTRMIOS:
228 case TIOCPKT:
229 case TIOCGSOFTCAR:
230 case TIOCSSOFTCAR:
231 return -ENOIOCTLCMD;
232#if 0
233 case TCwhatever:
234 /* do something */
235 break;
236#endif
237 default:
238 for (i = 0; i < ARRAY_SIZE(tty_ioctls); i++)
239 if (cmd == tty_ioctls[i].cmd)
240 break;
241 if (i < ARRAY_SIZE(tty_ioctls)) {
242 if (NULL != tty_ioctls[i].level)
243 printk("%s%s: %s: ioctl %s called\n",
244 tty_ioctls[i].level, __FUNCTION__,
245 tty->name, tty_ioctls[i].name);
246 } else {
247 printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n",
248 __FUNCTION__, tty->name, cmd);
249 }
250 ret = -ENOIOCTLCMD;
251 break;
252 }
253 return(ret);
254}
255
256static irqreturn_t line_write_interrupt(int irq, void *data,
257 struct pt_regs *unused)
258{
259 struct tty_struct *tty = data;
260 struct line *line = tty->driver_data;
261 int err;
262
263 err = flush_buffer(line);
264 if(err == 0)
265 return(IRQ_NONE);
266 else if(err < 0){
267 line->head = line->buffer;
268 line->tail = line->buffer;
269 }
270
271 if(tty == NULL)
272 return(IRQ_NONE);
273
274 if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
275 (tty->ldisc.write_wakeup != NULL))
276 (tty->ldisc.write_wakeup)(tty);
277
278 /* BLOCKING mode
279 * In blocking mode, everything sleeps on tty->write_wait.
280 * Sleeping in the console driver would break non-blocking
281 * writes.
282 */
283
284 if(waitqueue_active(&tty->write_wait))
285 wake_up_interruptible(&tty->write_wait);
286 return(IRQ_HANDLED);
287}
288
289int line_setup_irq(int fd, int input, int output, struct tty_struct *tty)
290{
291 struct line *line = tty->driver_data;
292 struct line_driver *driver = line->driver;
293 int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM;
294
295 if(input) err = um_request_irq(driver->read_irq, fd, IRQ_READ,
296 line_interrupt, flags,
297 driver->read_irq_name, tty);
298 if(err) return(err);
299 if(output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
300 line_write_interrupt, flags,
301 driver->write_irq_name, tty);
302 line->have_irq = 1;
303 return(err);
304}
305
306void line_disable(struct tty_struct *tty, int current_irq)
307{
308 struct line *line = tty->driver_data;
309
310 if(!line->have_irq)
311 return;
312
313 if(line->driver->read_irq == current_irq)
314 free_irq_later(line->driver->read_irq, tty);
315 else {
316 free_irq_by_irq_and_dev(line->driver->read_irq, tty);
317 free_irq(line->driver->read_irq, tty);
318 }
319
320 if(line->driver->write_irq == current_irq)
321 free_irq_later(line->driver->write_irq, tty);
322 else {
323 free_irq_by_irq_and_dev(line->driver->write_irq, tty);
324 free_irq(line->driver->write_irq, tty);
325 }
326
327 line->have_irq = 0;
328}
329
330int line_open(struct line *lines, struct tty_struct *tty,
331 struct chan_opts *opts)
332{
333 struct line *line;
334 int err = 0;
335
336 line = &lines[tty->index];
337 tty->driver_data = line;
338
339 down(&line->sem);
340 if (tty->count == 1) {
341 if (!line->valid) {
342 err = -ENODEV;
343 goto out;
344 }
345 if (list_empty(&line->chan_list)) {
346 err = parse_chan_pair(line->init_str, &line->chan_list,
347 line->init_pri, tty->index, opts);
348 if(err) goto out;
349 err = open_chan(&line->chan_list);
350 if(err) goto out;
351 }
352 enable_chan(&line->chan_list, tty);
353 INIT_WORK(&line->task, line_timer_cb, tty);
354 }
355
356 if(!line->sigio){
357 chan_enable_winch(&line->chan_list, tty);
358 line->sigio = 1;
359 }
360 chan_window_size(&line->chan_list, &tty->winsize.ws_row,
361 &tty->winsize.ws_col);
362 line->count++;
363
364out:
365 up(&line->sem);
366 return(err);
367}
368
369void line_close(struct tty_struct *tty, struct file * filp)
370{
371 struct line *line = tty->driver_data;
372
373 down(&line->sem);
374 line->count--;
375 if (tty->count == 1) {
376 line_disable(tty, -1);
377 tty->driver_data = NULL;
378 }
379 up(&line->sem);
380}
381
382void close_lines(struct line *lines, int nlines)
383{
384 int i;
385
386 for(i = 0; i < nlines; i++)
387 close_chan(&lines[i].chan_list);
388}
389
390int line_setup(struct line *lines, int num, char *init, int all_allowed)
391{
392 int i, n;
393 char *end;
394
395 if(*init == '=') n = -1;
396 else {
397 n = simple_strtoul(init, &end, 0);
398 if(*end != '='){
399 printk(KERN_ERR "line_setup failed to parse \"%s\"\n",
400 init);
401 return(0);
402 }
403 init = end;
404 }
405 init++;
406 if((n >= 0) && (n >= num)){
407 printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
408 n, num - 1);
409 return(0);
410 }
411 else if (n >= 0){
412 if (lines[n].count > 0) {
413 printk("line_setup - device %d is open\n", n);
414 return(0);
415 }
416 if (lines[n].init_pri <= INIT_ONE){
417 lines[n].init_pri = INIT_ONE;
418 if (!strcmp(init, "none"))
419 lines[n].valid = 0;
420 else {
421 lines[n].init_str = init;
422 lines[n].valid = 1;
423 }
424 }
425 }
426 else if(!all_allowed){
427 printk("line_setup - can't configure all devices from "
428 "mconsole\n");
429 return(0);
430 }
431 else {
432 for(i = 0; i < num; i++){
433 if(lines[i].init_pri <= INIT_ALL){
434 lines[i].init_pri = INIT_ALL;
435 if(!strcmp(init, "none")) lines[i].valid = 0;
436 else {
437 lines[i].init_str = init;
438 lines[i].valid = 1;
439 }
440 }
441 }
442 }
443 return(1);
444}
445
446int line_config(struct line *lines, int num, char *str)
447{
448 char *new = uml_strdup(str);
449
450 if(new == NULL){
451 printk("line_config - uml_strdup failed\n");
452 return(-ENOMEM);
453 }
454 return(!line_setup(lines, num, new, 0));
455}
456
457int line_get_config(char *name, struct line *lines, int num, char *str,
458 int size, char **error_out)
459{
460 struct line *line;
461 char *end;
462 int dev, n = 0;
463
464 dev = simple_strtoul(name, &end, 0);
465 if((*end != '\0') || (end == name)){
466 *error_out = "line_get_config failed to parse device number";
467 return(0);
468 }
469
470 if((dev < 0) || (dev >= num)){
471 *error_out = "device number of of range";
472 return(0);
473 }
474
475 line = &lines[dev];
476
477 down(&line->sem);
478 if(!line->valid)
479 CONFIG_CHUNK(str, size, n, "none", 1);
480 else if(line->count == 0)
481 CONFIG_CHUNK(str, size, n, line->init_str, 1);
482 else n = chan_config_string(&line->chan_list, str, size, error_out);
483 up(&line->sem);
484
485 return(n);
486}
487
488int line_remove(struct line *lines, int num, char *str)
489{
490 char config[sizeof("conxxxx=none\0")];
491
492 sprintf(config, "%s=none", str);
493 return(!line_setup(lines, num, config, 0));
494}
495
496int line_write_room(struct tty_struct *tty)
497{
498 struct line *dev = tty->driver_data;
499 int room;
500
501 if (tty->stopped)
502 return 0;
503 room = write_room(dev);
504 if (0 == room)
505 printk(KERN_DEBUG "%s: %s: no room left in buffer\n",
506 __FUNCTION__,tty->name);
507 return room;
508}
509
510struct tty_driver *line_register_devfs(struct lines *set,
511 struct line_driver *line_driver,
512 struct tty_operations *ops, struct line *lines,
513 int nlines)
514{
515 int i;
516 struct tty_driver *driver = alloc_tty_driver(nlines);
517
518 if (!driver)
519 return NULL;
520
521 driver->driver_name = line_driver->name;
522 driver->name = line_driver->device_name;
523 driver->devfs_name = line_driver->devfs_name;
524 driver->major = line_driver->major;
525 driver->minor_start = line_driver->minor_start;
526 driver->type = line_driver->type;
527 driver->subtype = line_driver->subtype;
528 driver->flags = TTY_DRIVER_REAL_RAW;
529 driver->init_termios = tty_std_termios;
530 tty_set_operations(driver, ops);
531
532 if (tty_register_driver(driver)) {
533 printk("%s: can't register %s driver\n",
534 __FUNCTION__,line_driver->name);
535 put_tty_driver(driver);
536 return NULL;
537 }
538
539 for(i = 0; i < nlines; i++){
540 if(!lines[i].valid)
541 tty_unregister_device(driver, i);
542 }
543
544 mconsole_register_dev(&line_driver->mc);
545 return driver;
546}
547
548void lines_init(struct line *lines, int nlines)
549{
550 struct line *line;
551 int i;
552
553 for(i = 0; i < nlines; i++){
554 line = &lines[i];
555 INIT_LIST_HEAD(&line->chan_list);
556 sema_init(&line->sem, 1);
557 if(line->init_str != NULL){
558 line->init_str = uml_strdup(line->init_str);
559 if(line->init_str == NULL)
560 printk("lines_init - uml_strdup returned "
561 "NULL\n");
562 }
563 }
564}
565
566struct winch {
567 struct list_head list;
568 int fd;
569 int tty_fd;
570 int pid;
571 struct tty_struct *tty;
572};
573
574irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
575{
576 struct winch *winch = data;
577 struct tty_struct *tty;
578 struct line *line;
579 int err;
580 char c;
581
582 if(winch->fd != -1){
583 err = generic_read(winch->fd, &c, NULL);
584 if(err < 0){
585 if(err != -EAGAIN){
586 printk("winch_interrupt : read failed, "
587 "errno = %d\n", -err);
588 printk("fd %d is losing SIGWINCH support\n",
589 winch->tty_fd);
590 return(IRQ_HANDLED);
591 }
592 goto out;
593 }
594 }
595 tty = winch->tty;
596 if (tty != NULL) {
597 line = tty->driver_data;
598 chan_window_size(&line->chan_list,
599 &tty->winsize.ws_row,
600 &tty->winsize.ws_col);
601 kill_pg(tty->pgrp, SIGWINCH, 1);
602 }
603 out:
604 if(winch->fd != -1)
605 reactivate_fd(winch->fd, WINCH_IRQ);
606 return(IRQ_HANDLED);
607}
608
609DECLARE_MUTEX(winch_handler_sem);
610LIST_HEAD(winch_handlers);
611
612void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
613{
614 struct winch *winch;
615
616 down(&winch_handler_sem);
617 winch = kmalloc(sizeof(*winch), GFP_KERNEL);
618 if (winch == NULL) {
619 printk("register_winch_irq - kmalloc failed\n");
620 goto out;
621 }
622 *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
623 .fd = fd,
624 .tty_fd = tty_fd,
625 .pid = pid,
626 .tty = tty });
627 list_add(&winch->list, &winch_handlers);
628 if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
629 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
630 "winch", winch) < 0)
631 printk("register_winch_irq - failed to register IRQ\n");
632 out:
633 up(&winch_handler_sem);
634}
635
636static void winch_cleanup(void)
637{
638 struct list_head *ele;
639 struct winch *winch;
640
641 list_for_each(ele, &winch_handlers){
642 winch = list_entry(ele, struct winch, list);
643 if(winch->fd != -1){
644 deactivate_fd(winch->fd, WINCH_IRQ);
645 os_close_file(winch->fd);
646 }
647 if(winch->pid != -1)
648 os_kill_process(winch->pid, 1);
649 }
650}
651__uml_exitcall(winch_cleanup);
652
653char *add_xterm_umid(char *base)
654{
655 char *umid, *title;
656 int len;
657
658 umid = get_umid(1);
659 if(umid == NULL) return(base);
660
661 len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
662 title = kmalloc(len, GFP_KERNEL);
663 if(title == NULL){
664 printk("Failed to allocate buffer for xterm title\n");
665 return(base);
666 }
667
668 snprintf(title, len, "%s (%s)", base, umid);
669 return(title);
670}
671
672/*
673 * Overrides for Emacs so that we follow Linus's tabbing style.
674 * Emacs will notice this stuff at the end of the file and automatically
675 * adjust the settings for this buffer only. This must remain at the end
676 * of the file.
677 * ---------------------------------------------------------------------------
678 * Local variables:
679 * c-file-style: "linux"
680 * End:
681 */
diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h
new file mode 100644
index 000000000000..a2c6db243458
--- /dev/null
+++ b/arch/um/drivers/mcast.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "net_user.h"
7
8struct mcast_data {
9 char *addr;
10 unsigned short port;
11 void *mcast_addr;
12 int ttl;
13 void *dev;
14};
15
16extern struct net_user_info mcast_user_info;
17
18extern int mcast_user_write(int fd, void *buf, int len,
19 struct mcast_data *pri);
20
21/*
22 * Overrides for Emacs so that we follow Linus's tabbing style.
23 * Emacs will notice this stuff at the end of the file and automatically
24 * adjust the settings for this buffer only. This must remain at the end
25 * of the file.
26 * ---------------------------------------------------------------------------
27 * Local variables:
28 * c-file-style: "linux"
29 * End:
30 */
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
new file mode 100644
index 000000000000..faf714e87b5b
--- /dev/null
+++ b/arch/um/drivers/mcast_kern.c
@@ -0,0 +1,143 @@
1/*
2 * user-mode-linux networking multicast transport
3 * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
4 *
5 * based on the existing uml-networking code, which is
6 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
7 * James Leu (jleu@mindspring.net).
8 * Copyright (C) 2001 by various other people who didn't put their name here.
9 *
10 * Licensed under the GPL.
11 */
12
13#include "linux/kernel.h"
14#include "linux/init.h"
15#include "linux/netdevice.h"
16#include "linux/etherdevice.h"
17#include "linux/in.h"
18#include "linux/inet.h"
19#include "net_kern.h"
20#include "net_user.h"
21#include "mcast.h"
22
23struct mcast_init {
24 char *addr;
25 int port;
26 int ttl;
27};
28
29void mcast_init(struct net_device *dev, void *data)
30{
31 struct uml_net_private *pri;
32 struct mcast_data *dpri;
33 struct mcast_init *init = data;
34
35 pri = dev->priv;
36 dpri = (struct mcast_data *) pri->user;
37 dpri->addr = init->addr;
38 dpri->port = init->port;
39 dpri->ttl = init->ttl;
40 dpri->dev = dev;
41
42 printk("mcast backend ");
43 printk("multicast adddress: %s:%u, TTL:%u ",
44 dpri->addr, dpri->port, dpri->ttl);
45
46 printk("\n");
47}
48
49static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
50{
51 *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
52 if(*skb == NULL) return(-ENOMEM);
53 return(net_recvfrom(fd, (*skb)->mac.raw,
54 (*skb)->dev->mtu + ETH_HEADER_OTHER));
55}
56
57static int mcast_write(int fd, struct sk_buff **skb,
58 struct uml_net_private *lp)
59{
60 return mcast_user_write(fd, (*skb)->data, (*skb)->len,
61 (struct mcast_data *) &lp->user);
62}
63
64static struct net_kern_info mcast_kern_info = {
65 .init = mcast_init,
66 .protocol = eth_protocol,
67 .read = mcast_read,
68 .write = mcast_write,
69};
70
71int mcast_setup(char *str, char **mac_out, void *data)
72{
73 struct mcast_init *init = data;
74 char *port_str = NULL, *ttl_str = NULL, *remain;
75 char *last;
76 int n;
77
78 *init = ((struct mcast_init)
79 { .addr = "239.192.168.1",
80 .port = 1102,
81 .ttl = 1 });
82
83 remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
84 NULL);
85 if(remain != NULL){
86 printk(KERN_ERR "mcast_setup - Extra garbage on "
87 "specification : '%s'\n", remain);
88 return(0);
89 }
90
91 if(port_str != NULL){
92 n = simple_strtoul(port_str, &last, 10);
93 if((*last != '\0') || (last == port_str)){
94 printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
95 port_str);
96 return(0);
97 }
98 init->port = htons(n);
99 }
100
101 if(ttl_str != NULL){
102 init->ttl = simple_strtoul(ttl_str, &last, 10);
103 if((*last != '\0') || (last == ttl_str)){
104 printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
105 ttl_str);
106 return(0);
107 }
108 }
109
110 printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
111 init->port, init->ttl);
112
113 return(1);
114}
115
116static struct transport mcast_transport = {
117 .list = LIST_HEAD_INIT(mcast_transport.list),
118 .name = "mcast",
119 .setup = mcast_setup,
120 .user = &mcast_user_info,
121 .kern = &mcast_kern_info,
122 .private_size = sizeof(struct mcast_data),
123 .setup_size = sizeof(struct mcast_init),
124};
125
126static int register_mcast(void)
127{
128 register_transport(&mcast_transport);
129 return(1);
130}
131
132__initcall(register_mcast);
133
134/*
135 * Overrides for Emacs so that we follow Linus's tabbing style.
136 * Emacs will notice this stuff at the end of the file and automatically
137 * adjust the settings for this buffer only. This must remain at the end
138 * of the file.
139 * ---------------------------------------------------------------------------
140 * Local variables:
141 * c-file-style: "linux"
142 * End:
143 */
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
new file mode 100644
index 000000000000..0fe1d9fa9139
--- /dev/null
+++ b/arch/um/drivers/mcast_user.c
@@ -0,0 +1,177 @@
1/*
2 * user-mode-linux networking multicast transport
3 * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
4 *
5 * based on the existing uml-networking code, which is
6 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
7 * James Leu (jleu@mindspring.net).
8 * Copyright (C) 2001 by various other people who didn't put their name here.
9 *
10 * Licensed under the GPL.
11 *
12 */
13
14#include <errno.h>
15#include <unistd.h>
16#include <linux/inet.h>
17#include <sys/socket.h>
18#include <sys/un.h>
19#include <sys/time.h>
20#include <netinet/in.h>
21#include "net_user.h"
22#include "mcast.h"
23#include "kern_util.h"
24#include "user_util.h"
25#include "user.h"
26#include "os.h"
27
28#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
29
30static struct sockaddr_in *new_addr(char *addr, unsigned short port)
31{
32 struct sockaddr_in *sin;
33
34 sin = um_kmalloc(sizeof(struct sockaddr_in));
35 if(sin == NULL){
36 printk("new_addr: allocation of sockaddr_in failed\n");
37 return(NULL);
38 }
39 sin->sin_family = AF_INET;
40 sin->sin_addr.s_addr = in_aton(addr);
41 sin->sin_port = port;
42 return(sin);
43}
44
45static void mcast_user_init(void *data, void *dev)
46{
47 struct mcast_data *pri = data;
48
49 pri->mcast_addr = new_addr(pri->addr, pri->port);
50 pri->dev = dev;
51}
52
53static int mcast_open(void *data)
54{
55 struct mcast_data *pri = data;
56 struct sockaddr_in *sin = pri->mcast_addr;
57 struct ip_mreq mreq;
58 int fd, yes = 1;
59
60
61 if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) {
62 fd = -EINVAL;
63 goto out;
64 }
65
66 fd = socket(AF_INET, SOCK_DGRAM, 0);
67 if (fd < 0){
68 printk("mcast_open : data socket failed, errno = %d\n",
69 errno);
70 fd = -ENOMEM;
71 goto out;
72 }
73
74 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
75 printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
76 errno);
77 os_close_file(fd);
78 fd = -EINVAL;
79 goto out;
80 }
81
82 /* set ttl according to config */
83 if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
84 sizeof(pri->ttl)) < 0) {
85 printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
86 errno);
87 os_close_file(fd);
88 fd = -EINVAL;
89 goto out;
90 }
91
92 /* set LOOP, so data does get fed back to local sockets */
93 if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
94 printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
95 errno);
96 os_close_file(fd);
97 fd = -EINVAL;
98 goto out;
99 }
100
101 /* bind socket to mcast address */
102 if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
103 printk("mcast_open : data bind failed, errno = %d\n", errno);
104 os_close_file(fd);
105 fd = -EINVAL;
106 goto out;
107 }
108
109 /* subscribe to the multicast group */
110 mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
111 mreq.imr_interface.s_addr = 0;
112 if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
113 &mreq, sizeof(mreq)) < 0) {
114 printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n",
115 errno);
116 printk("There appears not to be a multicast-capable network "
117 "interface on the host.\n");
118 printk("eth0 should be configured in order to use the "
119 "multicast transport.\n");
120 os_close_file(fd);
121 fd = -EINVAL;
122 }
123
124 out:
125 return(fd);
126}
127
128static void mcast_close(int fd, void *data)
129{
130 struct ip_mreq mreq;
131 struct mcast_data *pri = data;
132 struct sockaddr_in *sin = pri->mcast_addr;
133
134 mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
135 mreq.imr_interface.s_addr = 0;
136 if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
137 &mreq, sizeof(mreq)) < 0) {
138 printk("mcast_open: IP_DROP_MEMBERSHIP failed, error = %d\n",
139 errno);
140 }
141
142 os_close_file(fd);
143}
144
145int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
146{
147 struct sockaddr_in *data_addr = pri->mcast_addr;
148
149 return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
150}
151
152static int mcast_set_mtu(int mtu, void *data)
153{
154 return(mtu);
155}
156
157struct net_user_info mcast_user_info = {
158 .init = mcast_user_init,
159 .open = mcast_open,
160 .close = mcast_close,
161 .remove = NULL,
162 .set_mtu = mcast_set_mtu,
163 .add_address = NULL,
164 .delete_address = NULL,
165 .max_packet = MAX_PACKET - ETH_HEADER_OTHER
166};
167
168/*
169 * Overrides for Emacs so that we follow Linus's tabbing style.
170 * Emacs will notice this stuff at the end of the file and automatically
171 * adjust the settings for this buffer only. This must remain at the end
172 * of the file.
173 * ---------------------------------------------------------------------------
174 * Local variables:
175 * c-file-style: "linux"
176 * End:
177 */
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
new file mode 100644
index 000000000000..d7c7adcc0a67
--- /dev/null
+++ b/arch/um/drivers/mconsole_kern.c
@@ -0,0 +1,619 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
3 * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
4 * Licensed under the GPL
5 */
6
7#include "linux/kernel.h"
8#include "linux/slab.h"
9#include "linux/init.h"
10#include "linux/notifier.h"
11#include "linux/reboot.h"
12#include "linux/utsname.h"
13#include "linux/ctype.h"
14#include "linux/interrupt.h"
15#include "linux/sysrq.h"
16#include "linux/workqueue.h"
17#include "linux/module.h"
18#include "linux/file.h"
19#include "linux/fs.h"
20#include "linux/namei.h"
21#include "linux/proc_fs.h"
22#include "linux/syscalls.h"
23#include "asm/irq.h"
24#include "asm/uaccess.h"
25#include "user_util.h"
26#include "kern_util.h"
27#include "kern.h"
28#include "mconsole.h"
29#include "mconsole_kern.h"
30#include "irq_user.h"
31#include "init.h"
32#include "os.h"
33#include "umid.h"
34#include "irq_kern.h"
35
36static int do_unlink_socket(struct notifier_block *notifier,
37 unsigned long what, void *data)
38{
39 return(mconsole_unlink_socket());
40}
41
42
43static struct notifier_block reboot_notifier = {
44 .notifier_call = do_unlink_socket,
45 .priority = 0,
46};
47
48/* Safe without explicit locking for now. Tasklets provide their own
49 * locking, and the interrupt handler is safe because it can't interrupt
50 * itself and it can only happen on CPU 0.
51 */
52
53LIST_HEAD(mc_requests);
54
55static void mc_work_proc(void *unused)
56{
57 struct mconsole_entry *req;
58 unsigned long flags;
59
60 while(!list_empty(&mc_requests)){
61 local_save_flags(flags);
62 req = list_entry(mc_requests.next, struct mconsole_entry,
63 list);
64 list_del(&req->list);
65 local_irq_restore(flags);
66 req->request.cmd->handler(&req->request);
67 kfree(req);
68 }
69}
70
71DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
72
73static irqreturn_t mconsole_interrupt(int irq, void *dev_id,
74 struct pt_regs *regs)
75{
76 /* long to avoid size mismatch warnings from gcc */
77 long fd;
78 struct mconsole_entry *new;
79 struct mc_request req;
80
81 fd = (long) dev_id;
82 while (mconsole_get_request(fd, &req)){
83 if(req.cmd->context == MCONSOLE_INTR)
84 (*req.cmd->handler)(&req);
85 else {
86 new = kmalloc(sizeof(*new), GFP_ATOMIC);
87 if(new == NULL)
88 mconsole_reply(&req, "Out of memory", 1, 0);
89 else {
90 new->request = req;
91 list_add(&new->list, &mc_requests);
92 }
93 }
94 }
95 if(!list_empty(&mc_requests))
96 schedule_work(&mconsole_work);
97 reactivate_fd(fd, MCONSOLE_IRQ);
98 return(IRQ_HANDLED);
99}
100
101void mconsole_version(struct mc_request *req)
102{
103 char version[256];
104
105 sprintf(version, "%s %s %s %s %s", system_utsname.sysname,
106 system_utsname.nodename, system_utsname.release,
107 system_utsname.version, system_utsname.machine);
108 mconsole_reply(req, version, 0, 0);
109}
110
111void mconsole_log(struct mc_request *req)
112{
113 int len;
114 char *ptr = req->request.data;
115
116 ptr += strlen("log ");
117
118 len = req->len - (ptr - req->request.data);
119 printk("%.*s", len, ptr);
120 mconsole_reply(req, "", 0, 0);
121}
122
123/* This is a more convoluted version of mconsole_proc, which has some stability
124 * problems; however, we need it fixed, because it is expected that UML users
125 * mount HPPFS instead of procfs on /proc. And we want mconsole_proc to still
126 * show the real procfs content, not the ones from hppfs.*/
127#if 0
128void mconsole_proc(struct mc_request *req)
129{
130 struct nameidata nd;
131 struct file_system_type *proc;
132 struct super_block *super;
133 struct file *file;
134 int n, err;
135 char *ptr = req->request.data, *buf;
136
137 ptr += strlen("proc");
138 while(isspace(*ptr)) ptr++;
139
140 proc = get_fs_type("proc");
141 if(proc == NULL){
142 mconsole_reply(req, "procfs not registered", 1, 0);
143 goto out;
144 }
145
146 super = (*proc->get_sb)(proc, 0, NULL, NULL);
147 put_filesystem(proc);
148 if(super == NULL){
149 mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
150 goto out;
151 }
152 up_write(&super->s_umount);
153
154 nd.dentry = super->s_root;
155 nd.mnt = NULL;
156 nd.flags = O_RDONLY + 1;
157 nd.last_type = LAST_ROOT;
158
159 /* START: it was experienced that the stability problems are closed
160 * if commenting out these two calls + the below read cycle. To
161 * make UML crash again, it was enough to readd either one.*/
162 err = link_path_walk(ptr, &nd);
163 if(err){
164 mconsole_reply(req, "Failed to look up file", 1, 0);
165 goto out_kill;
166 }
167
168 file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
169 if(IS_ERR(file)){
170 mconsole_reply(req, "Failed to open file", 1, 0);
171 goto out_kill;
172 }
173 /*END*/
174
175 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
176 if(buf == NULL){
177 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
178 goto out_fput;
179 }
180
181 if((file->f_op != NULL) && (file->f_op->read != NULL)){
182 do {
183 n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
184 &file->f_pos);
185 if(n >= 0){
186 buf[n] = '\0';
187 mconsole_reply(req, buf, 0, (n > 0));
188 }
189 else {
190 mconsole_reply(req, "Read of file failed",
191 1, 0);
192 goto out_free;
193 }
194 } while(n > 0);
195 }
196 else mconsole_reply(req, "", 0, 0);
197
198 out_free:
199 kfree(buf);
200 out_fput:
201 fput(file);
202 out_kill:
203 deactivate_super(super);
204 out: ;
205}
206#endif
207
208void mconsole_proc(struct mc_request *req)
209{
210 char path[64];
211 char *buf;
212 int len;
213 int fd;
214 int first_chunk = 1;
215 char *ptr = req->request.data;
216
217 ptr += strlen("proc");
218 while(isspace(*ptr)) ptr++;
219 snprintf(path, sizeof(path), "/proc/%s", ptr);
220
221 fd = sys_open(path, 0, 0);
222 if (fd < 0) {
223 mconsole_reply(req, "Failed to open file", 1, 0);
224 printk("open %s: %d\n",path,fd);
225 goto out;
226 }
227
228 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
229 if(buf == NULL){
230 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
231 goto out_close;
232 }
233
234 for (;;) {
235 len = sys_read(fd, buf, PAGE_SIZE-1);
236 if (len < 0) {
237 mconsole_reply(req, "Read of file failed", 1, 0);
238 goto out_free;
239 }
240 /*Begin the file content on his own line.*/
241 if (first_chunk) {
242 mconsole_reply(req, "\n", 0, 1);
243 first_chunk = 0;
244 }
245 if (len == PAGE_SIZE-1) {
246 buf[len] = '\0';
247 mconsole_reply(req, buf, 0, 1);
248 } else {
249 buf[len] = '\0';
250 mconsole_reply(req, buf, 0, 0);
251 break;
252 }
253 }
254
255 out_free:
256 kfree(buf);
257 out_close:
258 sys_close(fd);
259 out:
260 /* nothing */;
261}
262
263#define UML_MCONSOLE_HELPTEXT \
264"Commands: \n\
265 version - Get kernel version \n\
266 help - Print this message \n\
267 halt - Halt UML \n\
268 reboot - Reboot UML \n\
269 config <dev>=<config> - Add a new device to UML; \n\
270 same syntax as command line \n\
271 config <dev> - Query the configuration of a device \n\
272 remove <dev> - Remove a device from UML \n\
273 sysrq <letter> - Performs the SysRq action controlled by the letter \n\
274 cad - invoke the Ctl-Alt-Del handler \n\
275 stop - pause the UML; it will do nothing until it receives a 'go' \n\
276 go - continue the UML after a 'stop' \n\
277 log <string> - make UML enter <string> into the kernel log\n\
278 proc <file> - returns the contents of the UML's /proc/<file>\n\
279"
280
281void mconsole_help(struct mc_request *req)
282{
283 mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
284}
285
286void mconsole_halt(struct mc_request *req)
287{
288 mconsole_reply(req, "", 0, 0);
289 machine_halt();
290}
291
292void mconsole_reboot(struct mc_request *req)
293{
294 mconsole_reply(req, "", 0, 0);
295 machine_restart(NULL);
296}
297
298extern void ctrl_alt_del(void);
299
300void mconsole_cad(struct mc_request *req)
301{
302 mconsole_reply(req, "", 0, 0);
303 ctrl_alt_del();
304}
305
306void mconsole_go(struct mc_request *req)
307{
308 mconsole_reply(req, "Not stopped", 1, 0);
309}
310
311void mconsole_stop(struct mc_request *req)
312{
313 deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
314 os_set_fd_block(req->originating_fd, 1);
315 mconsole_reply(req, "", 0, 0);
316 while(mconsole_get_request(req->originating_fd, req)){
317 if(req->cmd->handler == mconsole_go) break;
318 (*req->cmd->handler)(req);
319 }
320 os_set_fd_block(req->originating_fd, 0);
321 reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
322 mconsole_reply(req, "", 0, 0);
323}
324
325/* This list is populated by __initcall routines. */
326
327LIST_HEAD(mconsole_devices);
328
329void mconsole_register_dev(struct mc_device *new)
330{
331 list_add(&new->list, &mconsole_devices);
332}
333
334static struct mc_device *mconsole_find_dev(char *name)
335{
336 struct list_head *ele;
337 struct mc_device *dev;
338
339 list_for_each(ele, &mconsole_devices){
340 dev = list_entry(ele, struct mc_device, list);
341 if(!strncmp(name, dev->name, strlen(dev->name)))
342 return(dev);
343 }
344 return(NULL);
345}
346
347#define CONFIG_BUF_SIZE 64
348
349static void mconsole_get_config(int (*get_config)(char *, char *, int,
350 char **),
351 struct mc_request *req, char *name)
352{
353 char default_buf[CONFIG_BUF_SIZE], *error, *buf;
354 int n, size;
355
356 if(get_config == NULL){
357 mconsole_reply(req, "No get_config routine defined", 1, 0);
358 return;
359 }
360
361 error = NULL;
362 size = sizeof(default_buf)/sizeof(default_buf[0]);
363 buf = default_buf;
364
365 while(1){
366 n = (*get_config)(name, buf, size, &error);
367 if(error != NULL){
368 mconsole_reply(req, error, 1, 0);
369 goto out;
370 }
371
372 if(n <= size){
373 mconsole_reply(req, buf, 0, 0);
374 goto out;
375 }
376
377 if(buf != default_buf)
378 kfree(buf);
379
380 size = n;
381 buf = kmalloc(size, GFP_KERNEL);
382 if(buf == NULL){
383 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
384 return;
385 }
386 }
387 out:
388 if(buf != default_buf)
389 kfree(buf);
390
391}
392
393void mconsole_config(struct mc_request *req)
394{
395 struct mc_device *dev;
396 char *ptr = req->request.data, *name;
397 int err;
398
399 ptr += strlen("config");
400 while(isspace(*ptr)) ptr++;
401 dev = mconsole_find_dev(ptr);
402 if(dev == NULL){
403 mconsole_reply(req, "Bad configuration option", 1, 0);
404 return;
405 }
406
407 name = &ptr[strlen(dev->name)];
408 ptr = name;
409 while((*ptr != '=') && (*ptr != '\0'))
410 ptr++;
411
412 if(*ptr == '='){
413 err = (*dev->config)(name);
414 mconsole_reply(req, "", err, 0);
415 }
416 else mconsole_get_config(dev->get_config, req, name);
417}
418
419void mconsole_remove(struct mc_request *req)
420{
421 struct mc_device *dev;
422 char *ptr = req->request.data;
423 int err;
424
425 ptr += strlen("remove");
426 while(isspace(*ptr)) ptr++;
427 dev = mconsole_find_dev(ptr);
428 if(dev == NULL){
429 mconsole_reply(req, "Bad remove option", 1, 0);
430 return;
431 }
432 err = (*dev->remove)(&ptr[strlen(dev->name)]);
433 mconsole_reply(req, "", err, 0);
434}
435
436#ifdef CONFIG_MAGIC_SYSRQ
437void mconsole_sysrq(struct mc_request *req)
438{
439 char *ptr = req->request.data;
440
441 ptr += strlen("sysrq");
442 while(isspace(*ptr)) ptr++;
443
444 mconsole_reply(req, "", 0, 0);
445 handle_sysrq(*ptr, &current->thread.regs, NULL);
446}
447#else
448void mconsole_sysrq(struct mc_request *req)
449{
450 mconsole_reply(req, "Sysrq not compiled in", 1, 0);
451}
452#endif
453
454/* Changed by mconsole_setup, which is __setup, and called before SMP is
455 * active.
456 */
457static char *notify_socket = NULL;
458
459int mconsole_init(void)
460{
461 /* long to avoid size mismatch warnings from gcc */
462 long sock;
463 int err;
464 char file[256];
465
466 if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
467 snprintf(mconsole_socket_name, sizeof(file), "%s", file);
468
469 sock = os_create_unix_socket(file, sizeof(file), 1);
470 if (sock < 0){
471 printk("Failed to initialize management console\n");
472 return(1);
473 }
474
475 register_reboot_notifier(&reboot_notifier);
476
477 err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
478 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
479 "mconsole", (void *)sock);
480 if (err){
481 printk("Failed to get IRQ for management console\n");
482 return(1);
483 }
484
485 if(notify_socket != NULL){
486 notify_socket = uml_strdup(notify_socket);
487 if(notify_socket != NULL)
488 mconsole_notify(notify_socket, MCONSOLE_SOCKET,
489 mconsole_socket_name,
490 strlen(mconsole_socket_name) + 1);
491 else printk(KERN_ERR "mconsole_setup failed to strdup "
492 "string\n");
493 }
494
495 printk("mconsole (version %d) initialized on %s\n",
496 MCONSOLE_VERSION, mconsole_socket_name);
497 return(0);
498}
499
500__initcall(mconsole_init);
501
502static int write_proc_mconsole(struct file *file, const char __user *buffer,
503 unsigned long count, void *data)
504{
505 char *buf;
506
507 buf = kmalloc(count + 1, GFP_KERNEL);
508 if(buf == NULL)
509 return(-ENOMEM);
510
511 if(copy_from_user(buf, buffer, count)){
512 count = -EFAULT;
513 goto out;
514 }
515
516 buf[count] = '\0';
517
518 mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
519 out:
520 kfree(buf);
521 return(count);
522}
523
524static int create_proc_mconsole(void)
525{
526 struct proc_dir_entry *ent;
527
528 if(notify_socket == NULL) return(0);
529
530 ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
531 if(ent == NULL){
532 printk("create_proc_mconsole : create_proc_entry failed\n");
533 return(0);
534 }
535
536 ent->read_proc = NULL;
537 ent->write_proc = write_proc_mconsole;
538 return(0);
539}
540
541static DEFINE_SPINLOCK(notify_spinlock);
542
543void lock_notify(void)
544{
545 spin_lock(&notify_spinlock);
546}
547
548void unlock_notify(void)
549{
550 spin_unlock(&notify_spinlock);
551}
552
553__initcall(create_proc_mconsole);
554
555#define NOTIFY "=notify:"
556
557static int mconsole_setup(char *str)
558{
559 if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
560 str += strlen(NOTIFY);
561 notify_socket = str;
562 }
563 else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
564 return(1);
565}
566
567__setup("mconsole", mconsole_setup);
568
569__uml_help(mconsole_setup,
570"mconsole=notify:<socket>\n"
571" Requests that the mconsole driver send a message to the named Unix\n"
572" socket containing the name of the mconsole socket. This also serves\n"
573" to notify outside processes when UML has booted far enough to respond\n"
574" to mconsole requests.\n\n"
575);
576
577static int notify_panic(struct notifier_block *self, unsigned long unused1,
578 void *ptr)
579{
580 char *message = ptr;
581
582 if(notify_socket == NULL) return(0);
583
584 mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
585 strlen(message) + 1);
586 return(0);
587}
588
589static struct notifier_block panic_exit_notifier = {
590 .notifier_call = notify_panic,
591 .next = NULL,
592 .priority = 1
593};
594
595static int add_notifier(void)
596{
597 notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
598 return(0);
599}
600
601__initcall(add_notifier);
602
603char *mconsole_notify_socket(void)
604{
605 return(notify_socket);
606}
607
608EXPORT_SYMBOL(mconsole_notify_socket);
609
610/*
611 * Overrides for Emacs so that we follow Linus's tabbing style.
612 * Emacs will notice this stuff at the end of the file and automatically
613 * adjust the settings for this buffer only. This must remain at the end
614 * of the file.
615 * ---------------------------------------------------------------------------
616 * Local variables:
617 * c-file-style: "linux"
618 * End:
619 */
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
new file mode 100644
index 000000000000..fe5afb13252c
--- /dev/null
+++ b/arch/um/drivers/mconsole_user.c
@@ -0,0 +1,215 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
3 * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
4 * Licensed under the GPL
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <errno.h>
10#include <signal.h>
11#include <sys/socket.h>
12#include <sys/types.h>
13#include <sys/uio.h>
14#include <sys/un.h>
15#include <unistd.h>
16#include "user.h"
17#include "mconsole.h"
18#include "umid.h"
19
20static struct mconsole_command commands[] = {
21 { "version", mconsole_version, MCONSOLE_INTR },
22 { "halt", mconsole_halt, MCONSOLE_PROC },
23 { "reboot", mconsole_reboot, MCONSOLE_PROC },
24 { "config", mconsole_config, MCONSOLE_PROC },
25 { "remove", mconsole_remove, MCONSOLE_PROC },
26 { "sysrq", mconsole_sysrq, MCONSOLE_INTR },
27 { "help", mconsole_help, MCONSOLE_INTR },
28 { "cad", mconsole_cad, MCONSOLE_INTR },
29 { "stop", mconsole_stop, MCONSOLE_PROC },
30 { "go", mconsole_go, MCONSOLE_INTR },
31 { "log", mconsole_log, MCONSOLE_INTR },
32 { "proc", mconsole_proc, MCONSOLE_PROC },
33};
34
35/* Initialized in mconsole_init, which is an initcall */
36char mconsole_socket_name[256];
37
38int mconsole_reply_v0(struct mc_request *req, char *reply)
39{
40 struct iovec iov;
41 struct msghdr msg;
42
43 iov.iov_base = reply;
44 iov.iov_len = strlen(reply);
45
46 msg.msg_name = &(req->origin);
47 msg.msg_namelen = req->originlen;
48 msg.msg_iov = &iov;
49 msg.msg_iovlen = 1;
50 msg.msg_control = NULL;
51 msg.msg_controllen = 0;
52 msg.msg_flags = 0;
53
54 return sendmsg(req->originating_fd, &msg, 0);
55}
56
57static struct mconsole_command *mconsole_parse(struct mc_request *req)
58{
59 struct mconsole_command *cmd;
60 int i;
61
62 for(i=0;i<sizeof(commands)/sizeof(commands[0]);i++){
63 cmd = &commands[i];
64 if(!strncmp(req->request.data, cmd->command,
65 strlen(cmd->command))){
66 return(cmd);
67 }
68 }
69 return(NULL);
70}
71
72#define MIN(a,b) ((a)<(b) ? (a):(b))
73
74#define STRINGX(x) #x
75#define STRING(x) STRINGX(x)
76
77int mconsole_get_request(int fd, struct mc_request *req)
78{
79 int len;
80
81 req->originlen = sizeof(req->origin);
82 req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
83 (struct sockaddr *) req->origin, &req->originlen);
84 if (req->len < 0)
85 return 0;
86
87 req->originating_fd = fd;
88
89 if(req->request.magic != MCONSOLE_MAGIC){
90 /* Unversioned request */
91 len = MIN(sizeof(req->request.data) - 1,
92 strlen((char *) &req->request));
93 memmove(req->request.data, &req->request, len);
94 req->request.data[len] = '\0';
95
96 req->request.magic = MCONSOLE_MAGIC;
97 req->request.version = 0;
98 req->request.len = len;
99
100 mconsole_reply_v0(req, "ERR Version 0 mconsole clients are "
101 "not supported by this driver");
102 return(0);
103 }
104
105 if(req->request.len >= MCONSOLE_MAX_DATA){
106 mconsole_reply(req, "Request too large", 1, 0);
107 return(0);
108 }
109 if(req->request.version != MCONSOLE_VERSION){
110 mconsole_reply(req, "This driver only supports version "
111 STRING(MCONSOLE_VERSION) " clients", 1, 0);
112 }
113
114 req->request.data[req->request.len] = '\0';
115 req->cmd = mconsole_parse(req);
116 if(req->cmd == NULL){
117 mconsole_reply(req, "Unknown command", 1, 0);
118 return(0);
119 }
120
121 return(1);
122}
123
124int mconsole_reply(struct mc_request *req, char *str, int err, int more)
125{
126 struct mconsole_reply reply;
127 int total, len, n;
128
129 total = strlen(str);
130 do {
131 reply.err = err;
132
133 /* err can only be true on the first packet */
134 err = 0;
135
136 len = MIN(total, MCONSOLE_MAX_DATA - 1);
137
138 if(len == total) reply.more = more;
139 else reply.more = 1;
140
141 memcpy(reply.data, str, len);
142 reply.data[len] = '\0';
143 total -= len;
144 str += len;
145 reply.len = len + 1;
146
147 len = sizeof(reply) + reply.len - sizeof(reply.data);
148
149 n = sendto(req->originating_fd, &reply, len, 0,
150 (struct sockaddr *) req->origin, req->originlen);
151
152 if(n < 0) return(-errno);
153 } while(total > 0);
154 return(0);
155}
156
157int mconsole_unlink_socket(void)
158{
159 unlink(mconsole_socket_name);
160 return 0;
161}
162
163static int notify_sock = -1;
164
165int mconsole_notify(char *sock_name, int type, const void *data, int len)
166{
167 struct sockaddr_un target;
168 struct mconsole_notify packet;
169 int n, err = 0;
170
171 lock_notify();
172 if(notify_sock < 0){
173 notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0);
174 if(notify_sock < 0){
175 printk("mconsole_notify - socket failed, errno = %d\n",
176 errno);
177 err = -errno;
178 }
179 }
180 unlock_notify();
181
182 if(err)
183 return(err);
184
185 target.sun_family = AF_UNIX;
186 strcpy(target.sun_path, sock_name);
187
188 packet.magic = MCONSOLE_MAGIC;
189 packet.version = MCONSOLE_VERSION;
190 packet.type = type;
191 len = (len > sizeof(packet.data)) ? sizeof(packet.data) : len;
192 packet.len = len;
193 memcpy(packet.data, data, len);
194
195 err = 0;
196 len = sizeof(packet) + packet.len - sizeof(packet.data);
197 n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target,
198 sizeof(target));
199 if(n < 0){
200 printk("mconsole_notify - sendto failed, errno = %d\n", errno);
201 err = -errno;
202 }
203 return(err);
204}
205
206/*
207 * Overrides for Emacs so that we follow Linus's tabbing style.
208 * Emacs will notice this stuff at the end of the file and automatically
209 * adjust the settings for this buffer only. This must remain at the end
210 * of the file.
211 * ---------------------------------------------------------------------------
212 * Local variables:
213 * c-file-style: "linux"
214 * End:
215 */
diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
new file mode 100644
index 000000000000..a63231dffe05
--- /dev/null
+++ b/arch/um/drivers/mmapper_kern.c
@@ -0,0 +1,150 @@
1/*
2 * arch/um/drivers/mmapper_kern.c
3 *
4 * BRIEF MODULE DESCRIPTION
5 *
6 * Copyright (C) 2000 RidgeRun, Inc.
7 * Author: RidgeRun, Inc.
8 * Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
9 *
10 */
11
12#include <linux/types.h>
13#include <linux/kdev_t.h>
14#include <linux/time.h>
15#include <linux/devfs_fs_kernel.h>
16#include <linux/module.h>
17#include <linux/mm.h>
18#include <linux/slab.h>
19#include <linux/init.h>
20#include <linux/smp_lock.h>
21#include <asm/uaccess.h>
22#include <asm/irq.h>
23#include <asm/pgtable.h>
24#include "mem_user.h"
25#include "user_util.h"
26
27/* These are set in mmapper_init, which is called at boot time */
28static unsigned long mmapper_size;
29static unsigned long p_buf = 0;
30static char *v_buf = NULL;
31
32static ssize_t
33mmapper_read(struct file *file, char *buf, size_t count, loff_t *ppos)
34{
35 if(*ppos > mmapper_size)
36 return -EINVAL;
37
38 if(count + *ppos > mmapper_size)
39 count = count + *ppos - mmapper_size;
40
41 if(count < 0)
42 return -EINVAL;
43
44 copy_to_user(buf,&v_buf[*ppos],count);
45
46 return count;
47}
48
49static ssize_t
50mmapper_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
51{
52 if(*ppos > mmapper_size)
53 return -EINVAL;
54
55 if(count + *ppos > mmapper_size)
56 count = count + *ppos - mmapper_size;
57
58 if(count < 0)
59 return -EINVAL;
60
61 copy_from_user(&v_buf[*ppos],buf,count);
62
63 return count;
64}
65
66static int
67mmapper_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
68 unsigned long arg)
69{
70 return(-ENOIOCTLCMD);
71}
72
73static int
74mmapper_mmap(struct file *file, struct vm_area_struct * vma)
75{
76 int ret = -EINVAL;
77 int size;
78
79 lock_kernel();
80 if (vma->vm_pgoff != 0)
81 goto out;
82
83 size = vma->vm_end - vma->vm_start;
84 if(size > mmapper_size) return(-EFAULT);
85
86 /* XXX A comment above remap_pfn_range says it should only be
87 * called when the mm semaphore is held
88 */
89 if (remap_pfn_range(vma, vma->vm_start, p_buf >> PAGE_SHIFT, size,
90 vma->vm_page_prot))
91 goto out;
92 ret = 0;
93out:
94 unlock_kernel();
95 return ret;
96}
97
98static int
99mmapper_open(struct inode *inode, struct file *file)
100{
101 return 0;
102}
103
104static int
105mmapper_release(struct inode *inode, struct file *file)
106{
107 return 0;
108}
109
110static struct file_operations mmapper_fops = {
111 .owner = THIS_MODULE,
112 .read = mmapper_read,
113 .write = mmapper_write,
114 .ioctl = mmapper_ioctl,
115 .mmap = mmapper_mmap,
116 .open = mmapper_open,
117 .release = mmapper_release,
118};
119
120static int __init mmapper_init(void)
121{
122 printk(KERN_INFO "Mapper v0.1\n");
123
124 v_buf = (char *) find_iomem("mmapper", &mmapper_size);
125 if(mmapper_size == 0){
126 printk(KERN_ERR "mmapper_init - find_iomem failed\n");
127 return(0);
128 }
129
130 p_buf = __pa(v_buf);
131
132 devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUGO|S_IWUGO, "mmapper");
133 return(0);
134}
135
136static void mmapper_exit(void)
137{
138}
139
140module_init(mmapper_init);
141module_exit(mmapper_exit);
142
143MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>");
144MODULE_DESCRIPTION("DSPLinux simulator mmapper driver");
145/*
146 * ---------------------------------------------------------------------------
147 * Local variables:
148 * c-file-style: "linux"
149 * End:
150 */
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
new file mode 100644
index 000000000000..4eeaf88c1e97
--- /dev/null
+++ b/arch/um/drivers/net_kern.c
@@ -0,0 +1,896 @@
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
3 * James Leu (jleu@mindspring.net).
4 * Copyright (C) 2001 by various other people who didn't put their name here.
5 * Licensed under the GPL.
6 */
7
8#include "linux/config.h"
9#include "linux/kernel.h"
10#include "linux/netdevice.h"
11#include "linux/rtnetlink.h"
12#include "linux/skbuff.h"
13#include "linux/socket.h"
14#include "linux/spinlock.h"
15#include "linux/module.h"
16#include "linux/init.h"
17#include "linux/etherdevice.h"
18#include "linux/list.h"
19#include "linux/inetdevice.h"
20#include "linux/ctype.h"
21#include "linux/bootmem.h"
22#include "linux/ethtool.h"
23#include "asm/uaccess.h"
24#include "user_util.h"
25#include "kern_util.h"
26#include "net_kern.h"
27#include "net_user.h"
28#include "mconsole_kern.h"
29#include "init.h"
30#include "irq_user.h"
31#include "irq_kern.h"
32
33#define DRIVER_NAME "uml-netdev"
34
35static DEFINE_SPINLOCK(opened_lock);
36LIST_HEAD(opened);
37
38static int uml_net_rx(struct net_device *dev)
39{
40 struct uml_net_private *lp = dev->priv;
41 int pkt_len;
42 struct sk_buff *skb;
43
44 /* If we can't allocate memory, try again next round. */
45 skb = dev_alloc_skb(dev->mtu);
46 if (skb == NULL) {
47 lp->stats.rx_dropped++;
48 return 0;
49 }
50
51 skb->dev = dev;
52 skb_put(skb, dev->mtu);
53 skb->mac.raw = skb->data;
54 pkt_len = (*lp->read)(lp->fd, &skb, lp);
55
56 if (pkt_len > 0) {
57 skb_trim(skb, pkt_len);
58 skb->protocol = (*lp->protocol)(skb);
59 netif_rx(skb);
60
61 lp->stats.rx_bytes += skb->len;
62 lp->stats.rx_packets++;
63 return pkt_len;
64 }
65
66 kfree_skb(skb);
67 return pkt_len;
68}
69
70irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
71{
72 struct net_device *dev = dev_id;
73 struct uml_net_private *lp = dev->priv;
74 int err;
75
76 if(!netif_running(dev))
77 return(IRQ_NONE);
78
79 spin_lock(&lp->lock);
80 while((err = uml_net_rx(dev)) > 0) ;
81 if(err < 0) {
82 printk(KERN_ERR
83 "Device '%s' read returned %d, shutting it down\n",
84 dev->name, err);
85 dev_close(dev);
86 goto out;
87 }
88 reactivate_fd(lp->fd, UM_ETH_IRQ);
89
90 out:
91 spin_unlock(&lp->lock);
92 return(IRQ_HANDLED);
93}
94
95static int uml_net_open(struct net_device *dev)
96{
97 struct uml_net_private *lp = dev->priv;
98 char addr[sizeof("255.255.255.255\0")];
99 int err;
100
101 spin_lock(&lp->lock);
102
103 if(lp->fd >= 0){
104 err = -ENXIO;
105 goto out;
106 }
107
108 if(!lp->have_mac){
109 dev_ip_addr(dev, addr, &lp->mac[2]);
110 set_ether_mac(dev, lp->mac);
111 }
112
113 lp->fd = (*lp->open)(&lp->user);
114 if(lp->fd < 0){
115 err = lp->fd;
116 goto out;
117 }
118
119 err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,
120 SA_INTERRUPT | SA_SHIRQ, dev->name, dev);
121 if(err != 0){
122 printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);
123 if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
124 lp->fd = -1;
125 err = -ENETUNREACH;
126 }
127
128 lp->tl.data = (unsigned long) &lp->user;
129 netif_start_queue(dev);
130
131 /* clear buffer - it can happen that the host side of the interface
132 * is full when we get here. In this case, new data is never queued,
133 * SIGIOs never arrive, and the net never works.
134 */
135 while((err = uml_net_rx(dev)) > 0) ;
136
137 out:
138 spin_unlock(&lp->lock);
139 return(err);
140}
141
142static int uml_net_close(struct net_device *dev)
143{
144 struct uml_net_private *lp = dev->priv;
145
146 netif_stop_queue(dev);
147 spin_lock(&lp->lock);
148
149 free_irq_by_irq_and_dev(dev->irq, dev);
150 free_irq(dev->irq, dev);
151 if(lp->close != NULL)
152 (*lp->close)(lp->fd, &lp->user);
153 lp->fd = -1;
154
155 spin_unlock(&lp->lock);
156 return 0;
157}
158
159static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
160{
161 struct uml_net_private *lp = dev->priv;
162 unsigned long flags;
163 int len;
164
165 netif_stop_queue(dev);
166
167 spin_lock_irqsave(&lp->lock, flags);
168
169 len = (*lp->write)(lp->fd, &skb, lp);
170
171 if(len == skb->len) {
172 lp->stats.tx_packets++;
173 lp->stats.tx_bytes += skb->len;
174 dev->trans_start = jiffies;
175 netif_start_queue(dev);
176
177 /* this is normally done in the interrupt when tx finishes */
178 netif_wake_queue(dev);
179 }
180 else if(len == 0){
181 netif_start_queue(dev);
182 lp->stats.tx_dropped++;
183 }
184 else {
185 netif_start_queue(dev);
186 printk(KERN_ERR "uml_net_start_xmit: failed(%d)\n", len);
187 }
188
189 spin_unlock_irqrestore(&lp->lock, flags);
190
191 dev_kfree_skb(skb);
192
193 return 0;
194}
195
196static struct net_device_stats *uml_net_get_stats(struct net_device *dev)
197{
198 struct uml_net_private *lp = dev->priv;
199 return &lp->stats;
200}
201
202static void uml_net_set_multicast_list(struct net_device *dev)
203{
204 if (dev->flags & IFF_PROMISC) return;
205 else if (dev->mc_count) dev->flags |= IFF_ALLMULTI;
206 else dev->flags &= ~IFF_ALLMULTI;
207}
208
209static void uml_net_tx_timeout(struct net_device *dev)
210{
211 dev->trans_start = jiffies;
212 netif_wake_queue(dev);
213}
214
215static int uml_net_set_mac(struct net_device *dev, void *addr)
216{
217 struct uml_net_private *lp = dev->priv;
218 struct sockaddr *hwaddr = addr;
219
220 spin_lock(&lp->lock);
221 memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
222 spin_unlock(&lp->lock);
223
224 return(0);
225}
226
227static int uml_net_change_mtu(struct net_device *dev, int new_mtu)
228{
229 struct uml_net_private *lp = dev->priv;
230 int err = 0;
231
232 spin_lock(&lp->lock);
233
234 new_mtu = (*lp->set_mtu)(new_mtu, &lp->user);
235 if(new_mtu < 0){
236 err = new_mtu;
237 goto out;
238 }
239
240 dev->mtu = new_mtu;
241
242 out:
243 spin_unlock(&lp->lock);
244 return err;
245}
246
247static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
248{
249 static const struct ethtool_drvinfo info = {
250 .cmd = ETHTOOL_GDRVINFO,
251 .driver = DRIVER_NAME,
252 .version = "42",
253 };
254 void *useraddr;
255 u32 ethcmd;
256
257 switch (cmd) {
258 case SIOCETHTOOL:
259 useraddr = ifr->ifr_data;
260 if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
261 return -EFAULT;
262 switch (ethcmd) {
263 case ETHTOOL_GDRVINFO:
264 if (copy_to_user(useraddr, &info, sizeof(info)))
265 return -EFAULT;
266 return 0;
267 default:
268 return -EOPNOTSUPP;
269 }
270 default:
271 return -EINVAL;
272 }
273}
274
275void uml_net_user_timer_expire(unsigned long _conn)
276{
277#ifdef undef
278 struct connection *conn = (struct connection *)_conn;
279
280 dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn);
281 do_connect(conn);
282#endif
283}
284
285static DEFINE_SPINLOCK(devices_lock);
286static struct list_head devices = LIST_HEAD_INIT(devices);
287
288static struct device_driver uml_net_driver = {
289 .name = DRIVER_NAME,
290 .bus = &platform_bus_type,
291};
292static int driver_registered;
293
294static int eth_configure(int n, void *init, char *mac,
295 struct transport *transport)
296{
297 struct uml_net *device;
298 struct net_device *dev;
299 struct uml_net_private *lp;
300 int save, err, size;
301
302 size = transport->private_size + sizeof(struct uml_net_private) +
303 sizeof(((struct uml_net_private *) 0)->user);
304
305 device = kmalloc(sizeof(*device), GFP_KERNEL);
306 if (device == NULL) {
307 printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
308 return(1);
309 }
310
311 memset(device, 0, sizeof(*device));
312 INIT_LIST_HEAD(&device->list);
313 device->index = n;
314
315 spin_lock(&devices_lock);
316 list_add(&device->list, &devices);
317 spin_unlock(&devices_lock);
318
319 if (setup_etheraddr(mac, device->mac))
320 device->have_mac = 1;
321
322 printk(KERN_INFO "Netdevice %d ", n);
323 if (device->have_mac)
324 printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
325 device->mac[0], device->mac[1],
326 device->mac[2], device->mac[3],
327 device->mac[4], device->mac[5]);
328 printk(": ");
329 dev = alloc_etherdev(size);
330 if (dev == NULL) {
331 printk(KERN_ERR "eth_configure: failed to allocate device\n");
332 return 1;
333 }
334
335 /* sysfs register */
336 if (!driver_registered) {
337 driver_register(&uml_net_driver);
338 driver_registered = 1;
339 }
340 device->pdev.id = n;
341 device->pdev.name = DRIVER_NAME;
342 platform_device_register(&device->pdev);
343 SET_NETDEV_DEV(dev,&device->pdev.dev);
344
345 /* If this name ends up conflicting with an existing registered
346 * netdevice, that is OK, register_netdev{,ice}() will notice this
347 * and fail.
348 */
349 snprintf(dev->name, sizeof(dev->name), "eth%d", n);
350 device->dev = dev;
351
352 (*transport->kern->init)(dev, init);
353
354 dev->mtu = transport->user->max_packet;
355 dev->open = uml_net_open;
356 dev->hard_start_xmit = uml_net_start_xmit;
357 dev->stop = uml_net_close;
358 dev->get_stats = uml_net_get_stats;
359 dev->set_multicast_list = uml_net_set_multicast_list;
360 dev->tx_timeout = uml_net_tx_timeout;
361 dev->set_mac_address = uml_net_set_mac;
362 dev->change_mtu = uml_net_change_mtu;
363 dev->do_ioctl = uml_net_ioctl;
364 dev->watchdog_timeo = (HZ >> 1);
365 dev->irq = UM_ETH_IRQ;
366
367 rtnl_lock();
368 err = register_netdevice(dev);
369 rtnl_unlock();
370 if (err) {
371 device->dev = NULL;
372 /* XXX: should we call ->remove() here? */
373 free_netdev(dev);
374 return 1;
375 }
376 lp = dev->priv;
377
378 /* lp.user is the first four bytes of the transport data, which
379 * has already been initialized. This structure assignment will
380 * overwrite that, so we make sure that .user gets overwritten with
381 * what it already has.
382 */
383 save = lp->user[0];
384 *lp = ((struct uml_net_private)
385 { .list = LIST_HEAD_INIT(lp->list),
386 .dev = dev,
387 .fd = -1,
388 .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
389 .have_mac = device->have_mac,
390 .protocol = transport->kern->protocol,
391 .open = transport->user->open,
392 .close = transport->user->close,
393 .remove = transport->user->remove,
394 .read = transport->kern->read,
395 .write = transport->kern->write,
396 .add_address = transport->user->add_address,
397 .delete_address = transport->user->delete_address,
398 .set_mtu = transport->user->set_mtu,
399 .user = { save } });
400
401 init_timer(&lp->tl);
402 spin_lock_init(&lp->lock);
403 lp->tl.function = uml_net_user_timer_expire;
404 if (lp->have_mac)
405 memcpy(lp->mac, device->mac, sizeof(lp->mac));
406
407 if (transport->user->init)
408 (*transport->user->init)(&lp->user, dev);
409
410 if (device->have_mac)
411 set_ether_mac(dev, device->mac);
412
413 spin_lock(&opened_lock);
414 list_add(&lp->list, &opened);
415 spin_unlock(&opened_lock);
416
417 return(0);
418}
419
420static struct uml_net *find_device(int n)
421{
422 struct uml_net *device;
423 struct list_head *ele;
424
425 spin_lock(&devices_lock);
426 list_for_each(ele, &devices){
427 device = list_entry(ele, struct uml_net, list);
428 if(device->index == n)
429 goto out;
430 }
431 device = NULL;
432 out:
433 spin_unlock(&devices_lock);
434 return(device);
435}
436
437static int eth_parse(char *str, int *index_out, char **str_out)
438{
439 char *end;
440 int n;
441
442 n = simple_strtoul(str, &end, 0);
443 if(end == str){
444 printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str);
445 return(1);
446 }
447 if(n < 0){
448 printk(KERN_ERR "eth_setup: device %d is negative\n", n);
449 return(1);
450 }
451 str = end;
452 if(*str != '='){
453 printk(KERN_ERR
454 "eth_setup: expected '=' after device number\n");
455 return(1);
456 }
457 str++;
458 if(find_device(n)){
459 printk(KERN_ERR "eth_setup: Device %d already configured\n",
460 n);
461 return(1);
462 }
463 if(index_out) *index_out = n;
464 *str_out = str;
465 return(0);
466}
467
468struct eth_init {
469 struct list_head list;
470 char *init;
471 int index;
472};
473
474/* Filled in at boot time. Will need locking if the transports become
475 * modular.
476 */
477struct list_head transports = LIST_HEAD_INIT(transports);
478
479/* Filled in during early boot */
480struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
481
482static int check_transport(struct transport *transport, char *eth, int n,
483 void **init_out, char **mac_out)
484{
485 int len;
486
487 len = strlen(transport->name);
488 if(strncmp(eth, transport->name, len))
489 return(0);
490
491 eth += len;
492 if(*eth == ',')
493 eth++;
494 else if(*eth != '\0')
495 return(0);
496
497 *init_out = kmalloc(transport->setup_size, GFP_KERNEL);
498 if(*init_out == NULL)
499 return(1);
500
501 if(!transport->setup(eth, mac_out, *init_out)){
502 kfree(*init_out);
503 *init_out = NULL;
504 }
505 return(1);
506}
507
508void register_transport(struct transport *new)
509{
510 struct list_head *ele, *next;
511 struct eth_init *eth;
512 void *init;
513 char *mac = NULL;
514 int match;
515
516 list_add(&new->list, &transports);
517
518 list_for_each_safe(ele, next, &eth_cmd_line){
519 eth = list_entry(ele, struct eth_init, list);
520 match = check_transport(new, eth->init, eth->index, &init,
521 &mac);
522 if(!match)
523 continue;
524 else if(init != NULL){
525 eth_configure(eth->index, init, mac, new);
526 kfree(init);
527 }
528 list_del(&eth->list);
529 }
530}
531
532static int eth_setup_common(char *str, int index)
533{
534 struct list_head *ele;
535 struct transport *transport;
536 void *init;
537 char *mac = NULL;
538
539 list_for_each(ele, &transports){
540 transport = list_entry(ele, struct transport, list);
541 if(!check_transport(transport, str, index, &init, &mac))
542 continue;
543 if(init != NULL){
544 eth_configure(index, init, mac, transport);
545 kfree(init);
546 }
547 return(1);
548 }
549 return(0);
550}
551
552static int eth_setup(char *str)
553{
554 struct eth_init *new;
555 int n, err;
556
557 err = eth_parse(str, &n, &str);
558 if(err) return(1);
559
560 new = alloc_bootmem(sizeof(new));
561 if (new == NULL){
562 printk("eth_init : alloc_bootmem failed\n");
563 return(1);
564 }
565
566 INIT_LIST_HEAD(&new->list);
567 new->index = n;
568 new->init = str;
569
570 list_add_tail(&new->list, &eth_cmd_line);
571 return(1);
572}
573
574__setup("eth", eth_setup);
575__uml_help(eth_setup,
576"eth[0-9]+=<transport>,<options>\n"
577" Configure a network device.\n\n"
578);
579
580#if 0
581static int eth_init(void)
582{
583 struct list_head *ele, *next;
584 struct eth_init *eth;
585
586 list_for_each_safe(ele, next, &eth_cmd_line){
587 eth = list_entry(ele, struct eth_init, list);
588
589 if(eth_setup_common(eth->init, eth->index))
590 list_del(&eth->list);
591 }
592
593 return(1);
594}
595__initcall(eth_init);
596#endif
597
598static int net_config(char *str)
599{
600 int n, err;
601
602 err = eth_parse(str, &n, &str);
603 if(err) return(err);
604
605 str = uml_strdup(str);
606 if(str == NULL){
607 printk(KERN_ERR "net_config failed to strdup string\n");
608 return(-1);
609 }
610 err = !eth_setup_common(str, n);
611 if(err)
612 kfree(str);
613 return(err);
614}
615
616static int net_remove(char *str)
617{
618 struct uml_net *device;
619 struct net_device *dev;
620 struct uml_net_private *lp;
621 char *end;
622 int n;
623
624 n = simple_strtoul(str, &end, 0);
625 if((*end != '\0') || (end == str))
626 return(-1);
627
628 device = find_device(n);
629 if(device == NULL)
630 return(0);
631
632 dev = device->dev;
633 lp = dev->priv;
634 if(lp->fd > 0) return(-1);
635 if(lp->remove != NULL) (*lp->remove)(&lp->user);
636 unregister_netdev(dev);
637 platform_device_unregister(&device->pdev);
638
639 list_del(&device->list);
640 kfree(device);
641 free_netdev(dev);
642 return(0);
643}
644
645static struct mc_device net_mc = {
646 .name = "eth",
647 .config = net_config,
648 .get_config = NULL,
649 .remove = net_remove,
650};
651
652static int uml_inetaddr_event(struct notifier_block *this, unsigned long event,
653 void *ptr)
654{
655 struct in_ifaddr *ifa = ptr;
656 u32 addr = ifa->ifa_address;
657 u32 netmask = ifa->ifa_mask;
658 struct net_device *dev = ifa->ifa_dev->dev;
659 struct uml_net_private *lp;
660 void (*proc)(unsigned char *, unsigned char *, void *);
661 unsigned char addr_buf[4], netmask_buf[4];
662
663 if(dev->open != uml_net_open) return(NOTIFY_DONE);
664
665 lp = dev->priv;
666
667 proc = NULL;
668 switch (event){
669 case NETDEV_UP:
670 proc = lp->add_address;
671 break;
672 case NETDEV_DOWN:
673 proc = lp->delete_address;
674 break;
675 }
676 if(proc != NULL){
677 addr_buf[0] = addr & 0xff;
678 addr_buf[1] = (addr >> 8) & 0xff;
679 addr_buf[2] = (addr >> 16) & 0xff;
680 addr_buf[3] = addr >> 24;
681 netmask_buf[0] = netmask & 0xff;
682 netmask_buf[1] = (netmask >> 8) & 0xff;
683 netmask_buf[2] = (netmask >> 16) & 0xff;
684 netmask_buf[3] = netmask >> 24;
685 (*proc)(addr_buf, netmask_buf, &lp->user);
686 }
687 return(NOTIFY_DONE);
688}
689
690struct notifier_block uml_inetaddr_notifier = {
691 .notifier_call = uml_inetaddr_event,
692};
693
694static int uml_net_init(void)
695{
696 struct list_head *ele;
697 struct uml_net_private *lp;
698 struct in_device *ip;
699 struct in_ifaddr *in;
700
701 mconsole_register_dev(&net_mc);
702 register_inetaddr_notifier(&uml_inetaddr_notifier);
703
704 /* Devices may have been opened already, so the uml_inetaddr_notifier
705 * didn't get a chance to run for them. This fakes it so that
706 * addresses which have already been set up get handled properly.
707 */
708 list_for_each(ele, &opened){
709 lp = list_entry(ele, struct uml_net_private, list);
710 ip = lp->dev->ip_ptr;
711 if(ip == NULL) continue;
712 in = ip->ifa_list;
713 while(in != NULL){
714 uml_inetaddr_event(NULL, NETDEV_UP, in);
715 in = in->ifa_next;
716 }
717 }
718
719 return(0);
720}
721
722__initcall(uml_net_init);
723
724static void close_devices(void)
725{
726 struct list_head *ele;
727 struct uml_net_private *lp;
728
729 list_for_each(ele, &opened){
730 lp = list_entry(ele, struct uml_net_private, list);
731 if((lp->close != NULL) && (lp->fd >= 0))
732 (*lp->close)(lp->fd, &lp->user);
733 if(lp->remove != NULL) (*lp->remove)(&lp->user);
734 }
735}
736
737__uml_exitcall(close_devices);
738
739int setup_etheraddr(char *str, unsigned char *addr)
740{
741 char *end;
742 int i;
743
744 if(str == NULL)
745 return(0);
746 for(i=0;i<6;i++){
747 addr[i] = simple_strtoul(str, &end, 16);
748 if((end == str) ||
749 ((*end != ':') && (*end != ',') && (*end != '\0'))){
750 printk(KERN_ERR
751 "setup_etheraddr: failed to parse '%s' "
752 "as an ethernet address\n", str);
753 return(0);
754 }
755 str = end + 1;
756 }
757 if(addr[0] & 1){
758 printk(KERN_ERR
759 "Attempt to assign a broadcast ethernet address to a "
760 "device disallowed\n");
761 return(0);
762 }
763 return(1);
764}
765
766void dev_ip_addr(void *d, char *buf, char *bin_buf)
767{
768 struct net_device *dev = d;
769 struct in_device *ip = dev->ip_ptr;
770 struct in_ifaddr *in;
771 u32 addr;
772
773 if((ip == NULL) || ((in = ip->ifa_list) == NULL)){
774 printk(KERN_WARNING "dev_ip_addr - device not assigned an "
775 "IP address\n");
776 return;
777 }
778 addr = in->ifa_address;
779 sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff,
780 (addr >> 16) & 0xff, addr >> 24);
781 if(bin_buf){
782 bin_buf[0] = addr & 0xff;
783 bin_buf[1] = (addr >> 8) & 0xff;
784 bin_buf[2] = (addr >> 16) & 0xff;
785 bin_buf[3] = addr >> 24;
786 }
787}
788
789void set_ether_mac(void *d, unsigned char *addr)
790{
791 struct net_device *dev = d;
792
793 memcpy(dev->dev_addr, addr, ETH_ALEN);
794}
795
796struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
797{
798 if((skb != NULL) && (skb_tailroom(skb) < extra)){
799 struct sk_buff *skb2;
800
801 skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
802 dev_kfree_skb(skb);
803 skb = skb2;
804 }
805 if(skb != NULL) skb_put(skb, extra);
806 return(skb);
807}
808
809void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *,
810 void *),
811 void *arg)
812{
813 struct net_device *dev = d;
814 struct in_device *ip = dev->ip_ptr;
815 struct in_ifaddr *in;
816 unsigned char address[4], netmask[4];
817
818 if(ip == NULL) return;
819 in = ip->ifa_list;
820 while(in != NULL){
821 address[0] = in->ifa_address & 0xff;
822 address[1] = (in->ifa_address >> 8) & 0xff;
823 address[2] = (in->ifa_address >> 16) & 0xff;
824 address[3] = in->ifa_address >> 24;
825 netmask[0] = in->ifa_mask & 0xff;
826 netmask[1] = (in->ifa_mask >> 8) & 0xff;
827 netmask[2] = (in->ifa_mask >> 16) & 0xff;
828 netmask[3] = in->ifa_mask >> 24;
829 (*cb)(address, netmask, arg);
830 in = in->ifa_next;
831 }
832}
833
834int dev_netmask(void *d, void *m)
835{
836 struct net_device *dev = d;
837 struct in_device *ip = dev->ip_ptr;
838 struct in_ifaddr *in;
839 __u32 *mask_out = m;
840
841 if(ip == NULL)
842 return(1);
843
844 in = ip->ifa_list;
845 if(in == NULL)
846 return(1);
847
848 *mask_out = in->ifa_mask;
849 return(0);
850}
851
852void *get_output_buffer(int *len_out)
853{
854 void *ret;
855
856 ret = (void *) __get_free_pages(GFP_KERNEL, 0);
857 if(ret) *len_out = PAGE_SIZE;
858 else *len_out = 0;
859 return(ret);
860}
861
862void free_output_buffer(void *buffer)
863{
864 free_pages((unsigned long) buffer, 0);
865}
866
867int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out,
868 char **gate_addr)
869{
870 char *remain;
871
872 remain = split_if_spec(str, dev_name, mac_out, gate_addr, NULL);
873 if(remain != NULL){
874 printk("tap_setup_common - Extra garbage on specification : "
875 "'%s'\n", remain);
876 return(1);
877 }
878
879 return(0);
880}
881
882unsigned short eth_protocol(struct sk_buff *skb)
883{
884 return(eth_type_trans(skb, skb->dev));
885}
886
887/*
888 * Overrides for Emacs so that we follow Linus's tabbing style.
889 * Emacs will notice this stuff at the end of the file and automatically
890 * adjust the settings for this buffer only. This must remain at the end
891 * of the file.
892 * ---------------------------------------------------------------------------
893 * Local variables:
894 * c-file-style: "linux"
895 * End:
896 */
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
new file mode 100644
index 000000000000..47229fe4a813
--- /dev/null
+++ b/arch/um/drivers/net_user.c
@@ -0,0 +1,255 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stddef.h>
7#include <stdarg.h>
8#include <unistd.h>
9#include <stdio.h>
10#include <errno.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/socket.h>
14#include <sys/wait.h>
15#include "user.h"
16#include "user_util.h"
17#include "kern_util.h"
18#include "net_user.h"
19#include "helper.h"
20#include "os.h"
21
22int tap_open_common(void *dev, char *gate_addr)
23{
24 int tap_addr[4];
25
26 if(gate_addr == NULL) return(0);
27 if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0],
28 &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){
29 printk("Invalid tap IP address - '%s'\n", gate_addr);
30 return(-EINVAL);
31 }
32 return(0);
33}
34
35void tap_check_ips(char *gate_addr, char *eth_addr)
36{
37 int tap_addr[4];
38
39 if((gate_addr != NULL) &&
40 (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0],
41 &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) &&
42 (eth_addr[0] == tap_addr[0]) &&
43 (eth_addr[1] == tap_addr[1]) &&
44 (eth_addr[2] == tap_addr[2]) &&
45 (eth_addr[3] == tap_addr[3])){
46 printk("The tap IP address and the UML eth IP address"
47 " must be different\n");
48 }
49}
50
51void read_output(int fd, char *output, int len)
52{
53 int remain, n, actual;
54 char c;
55
56 if(output == NULL){
57 output = &c;
58 len = sizeof(c);
59 }
60
61 *output = '\0';
62 n = os_read_file(fd, &remain, sizeof(remain));
63 if(n != sizeof(remain)){
64 printk("read_output - read of length failed, err = %d\n", -n);
65 return;
66 }
67
68 while(remain != 0){
69 n = (remain < len) ? remain : len;
70 actual = os_read_file(fd, output, n);
71 if(actual != n){
72 printk("read_output - read of data failed, "
73 "err = %d\n", -actual);
74 return;
75 }
76 remain -= actual;
77 }
78 return;
79}
80
81int net_read(int fd, void *buf, int len)
82{
83 int n;
84
85 n = os_read_file(fd, buf, len);
86
87 if(n == -EAGAIN)
88 return(0);
89 else if(n == 0)
90 return(-ENOTCONN);
91 return(n);
92}
93
94int net_recvfrom(int fd, void *buf, int len)
95{
96 int n;
97
98 while(((n = recvfrom(fd, buf, len, 0, NULL, NULL)) < 0) &&
99 (errno == EINTR)) ;
100
101 if(n < 0){
102 if(errno == EAGAIN) return(0);
103 return(-errno);
104 }
105 else if(n == 0) return(-ENOTCONN);
106 return(n);
107}
108
109int net_write(int fd, void *buf, int len)
110{
111 int n;
112
113 n = os_write_file(fd, buf, len);
114
115 if(n == -EAGAIN)
116 return(0);
117 else if(n == 0)
118 return(-ENOTCONN);
119 return(n);
120}
121
122int net_send(int fd, void *buf, int len)
123{
124 int n;
125
126 while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ;
127 if(n < 0){
128 if(errno == EAGAIN) return(0);
129 return(-errno);
130 }
131 else if(n == 0) return(-ENOTCONN);
132 return(n);
133}
134
135int net_sendto(int fd, void *buf, int len, void *to, int sock_len)
136{
137 int n;
138
139 while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to,
140 sock_len)) < 0) && (errno == EINTR)) ;
141 if(n < 0){
142 if(errno == EAGAIN) return(0);
143 return(-errno);
144 }
145 else if(n == 0) return(-ENOTCONN);
146 return(n);
147}
148
149struct change_pre_exec_data {
150 int close_me;
151 int stdout;
152};
153
154static void change_pre_exec(void *arg)
155{
156 struct change_pre_exec_data *data = arg;
157
158 os_close_file(data->close_me);
159 dup2(data->stdout, 1);
160}
161
162static int change_tramp(char **argv, char *output, int output_len)
163{
164 int pid, fds[2], err;
165 struct change_pre_exec_data pe_data;
166
167 err = os_pipe(fds, 1, 0);
168 if(err < 0){
169 printk("change_tramp - pipe failed, err = %d\n", -err);
170 return(err);
171 }
172 pe_data.close_me = fds[0];
173 pe_data.stdout = fds[1];
174 pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
175
176 read_output(fds[0], output, output_len);
177 os_close_file(fds[0]);
178 os_close_file(fds[1]);
179
180 if (pid > 0)
181 CATCH_EINTR(err = waitpid(pid, NULL, 0));
182 return(pid);
183}
184
185static void change(char *dev, char *what, unsigned char *addr,
186 unsigned char *netmask)
187{
188 char addr_buf[sizeof("255.255.255.255\0")];
189 char netmask_buf[sizeof("255.255.255.255\0")];
190 char version[sizeof("nnnnn\0")];
191 char *argv[] = { "uml_net", version, what, dev, addr_buf,
192 netmask_buf, NULL };
193 char *output;
194 int output_len, pid;
195
196 sprintf(version, "%d", UML_NET_VERSION);
197 sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
198 sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1],
199 netmask[2], netmask[3]);
200
201 output_len = page_size();
202 output = um_kmalloc(output_len);
203 if(output == NULL)
204 printk("change : failed to allocate output buffer\n");
205
206 pid = change_tramp(argv, output, output_len);
207 if(pid < 0) return;
208
209 if(output != NULL){
210 printk("%s", output);
211 kfree(output);
212 }
213}
214
215void open_addr(unsigned char *addr, unsigned char *netmask, void *arg)
216{
217 change(arg, "add", addr, netmask);
218}
219
220void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
221{
222 change(arg, "del", addr, netmask);
223}
224
225char *split_if_spec(char *str, ...)
226{
227 char **arg, *end;
228 va_list ap;
229
230 va_start(ap, str);
231 while((arg = va_arg(ap, char **)) != NULL){
232 if(*str == '\0')
233 return(NULL);
234 end = strchr(str, ',');
235 if(end != str)
236 *arg = str;
237 if(end == NULL)
238 return(NULL);
239 *end++ = '\0';
240 str = end;
241 }
242 va_end(ap);
243 return(str);
244}
245
246/*
247 * Overrides for Emacs so that we follow Linus's tabbing style.
248 * Emacs will notice this stuff at the end of the file and automatically
249 * adjust the settings for this buffer only. This must remain at the end
250 * of the file.
251 * ---------------------------------------------------------------------------
252 * Local variables:
253 * c-file-style: "linux"
254 * End:
255 */
diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c
new file mode 100644
index 000000000000..14cc5f78398a
--- /dev/null
+++ b/arch/um/drivers/null.c
@@ -0,0 +1,56 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdlib.h>
7#include <errno.h>
8#include "chan_user.h"
9#include "os.h"
10
11static int null_chan;
12
13static void *null_init(char *str, int device, struct chan_opts *opts)
14{
15 return(&null_chan);
16}
17
18static int null_open(int input, int output, int primary, void *d,
19 char **dev_out)
20{
21 *dev_out = NULL;
22 return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0));
23}
24
25static int null_read(int fd, char *c_out, void *unused)
26{
27 return(-ENODEV);
28}
29
30static void null_free(void *data)
31{
32}
33
34struct chan_ops null_ops = {
35 .type = "null",
36 .init = null_init,
37 .open = null_open,
38 .close = generic_close,
39 .read = null_read,
40 .write = generic_write,
41 .console_write = generic_console_write,
42 .window_size = generic_window_size,
43 .free = null_free,
44 .winch = 0,
45};
46
47/*
48 * Overrides for Emacs so that we follow Linus's tabbing style.
49 * Emacs will notice this stuff at the end of the file and automatically
50 * adjust the settings for this buffer only. This must remain at the end
51 * of the file.
52 * ---------------------------------------------------------------------------
53 * Local variables:
54 * c-file-style: "linux"
55 * End:
56 */
diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c
new file mode 100644
index 000000000000..07c80f2156ef
--- /dev/null
+++ b/arch/um/drivers/pcap_kern.c
@@ -0,0 +1,123 @@
1/*
2 * Copyright (C) 2002 Jeff Dike <jdike@karaya.com>
3 * Licensed under the GPL.
4 */
5
6#include "linux/init.h"
7#include "linux/netdevice.h"
8#include "linux/etherdevice.h"
9#include "net_kern.h"
10#include "net_user.h"
11#include "pcap_user.h"
12
13struct pcap_init {
14 char *host_if;
15 int promisc;
16 int optimize;
17 char *filter;
18};
19
20void pcap_init(struct net_device *dev, void *data)
21{
22 struct uml_net_private *pri;
23 struct pcap_data *ppri;
24 struct pcap_init *init = data;
25
26 pri = dev->priv;
27 ppri = (struct pcap_data *) pri->user;
28 ppri->host_if = init->host_if;
29 ppri->promisc = init->promisc;
30 ppri->optimize = init->optimize;
31 ppri->filter = init->filter;
32}
33
34static int pcap_read(int fd, struct sk_buff **skb,
35 struct uml_net_private *lp)
36{
37 *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
38 if(*skb == NULL) return(-ENOMEM);
39 return(pcap_user_read(fd, (*skb)->mac.raw,
40 (*skb)->dev->mtu + ETH_HEADER_OTHER,
41 (struct pcap_data *) &lp->user));
42}
43
44static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
45{
46 return(-EPERM);
47}
48
49static struct net_kern_info pcap_kern_info = {
50 .init = pcap_init,
51 .protocol = eth_protocol,
52 .read = pcap_read,
53 .write = pcap_write,
54};
55
56int pcap_setup(char *str, char **mac_out, void *data)
57{
58 struct pcap_init *init = data;
59 char *remain, *host_if = NULL, *options[2] = { NULL, NULL };
60 int i;
61
62 *init = ((struct pcap_init)
63 { .host_if = "eth0",
64 .promisc = 1,
65 .optimize = 0,
66 .filter = NULL });
67
68 remain = split_if_spec(str, &host_if, &init->filter,
69 &options[0], &options[1], NULL);
70 if(remain != NULL){
71 printk(KERN_ERR "pcap_setup - Extra garbage on "
72 "specification : '%s'\n", remain);
73 return(0);
74 }
75
76 if(host_if != NULL)
77 init->host_if = host_if;
78
79 for(i = 0; i < sizeof(options)/sizeof(options[0]); i++){
80 if(options[i] == NULL)
81 continue;
82 if(!strcmp(options[i], "promisc"))
83 init->promisc = 1;
84 else if(!strcmp(options[i], "nopromisc"))
85 init->promisc = 0;
86 else if(!strcmp(options[i], "optimize"))
87 init->optimize = 1;
88 else if(!strcmp(options[i], "nooptimize"))
89 init->optimize = 0;
90 else printk("pcap_setup : bad option - '%s'\n", options[i]);
91 }
92
93 return(1);
94}
95
96static struct transport pcap_transport = {
97 .list = LIST_HEAD_INIT(pcap_transport.list),
98 .name = "pcap",
99 .setup = pcap_setup,
100 .user = &pcap_user_info,
101 .kern = &pcap_kern_info,
102 .private_size = sizeof(struct pcap_data),
103 .setup_size = sizeof(struct pcap_init),
104};
105
106static int register_pcap(void)
107{
108 register_transport(&pcap_transport);
109 return(1);
110}
111
112__initcall(register_pcap);
113
114/*
115 * Overrides for Emacs so that we follow Linus's tabbing style.
116 * Emacs will notice this stuff at the end of the file and automatically
117 * adjust the settings for this buffer only. This must remain at the end
118 * of the file.
119 * ---------------------------------------------------------------------------
120 * Local variables:
121 * c-file-style: "linux"
122 * End:
123 */
diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c
new file mode 100644
index 000000000000..edfcb29273e1
--- /dev/null
+++ b/arch/um/drivers/pcap_user.c
@@ -0,0 +1,143 @@
1/*
2 * Copyright (C) 2002 Jeff Dike <jdike@karaya.com>
3 * Licensed under the GPL.
4 */
5
6#include <unistd.h>
7#include <stdlib.h>
8#include <string.h>
9#include <errno.h>
10#include <pcap.h>
11#include <asm/types.h>
12#include "net_user.h"
13#include "pcap_user.h"
14#include "user.h"
15
16#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
17
18#define PCAP_FD(p) (*(int *)(p))
19
20static void pcap_user_init(void *data, void *dev)
21{
22 struct pcap_data *pri = data;
23 pcap_t *p;
24 char errors[PCAP_ERRBUF_SIZE];
25
26 p = pcap_open_live(pri->host_if, MAX_PACKET, pri->promisc, 0, errors);
27 if(p == NULL){
28 printk("pcap_user_init : pcap_open_live failed - '%s'\n",
29 errors);
30 return;
31 }
32
33 pri->dev = dev;
34 pri->pcap = p;
35}
36
37static int pcap_open(void *data)
38{
39 struct pcap_data *pri = data;
40 __u32 netmask;
41 int err;
42
43 if(pri->pcap == NULL)
44 return(-ENODEV);
45
46 if(pri->filter != NULL){
47 err = dev_netmask(pri->dev, &netmask);
48 if(err < 0){
49 printk("pcap_open : dev_netmask failed\n");
50 return(-EIO);
51 }
52
53 pri->compiled = um_kmalloc(sizeof(struct bpf_program));
54 if(pri->compiled == NULL){
55 printk("pcap_open : kmalloc failed\n");
56 return(-ENOMEM);
57 }
58
59 err = pcap_compile(pri->pcap,
60 (struct bpf_program *) pri->compiled,
61 pri->filter, pri->optimize, netmask);
62 if(err < 0){
63 printk("pcap_open : pcap_compile failed - '%s'\n",
64 pcap_geterr(pri->pcap));
65 return(-EIO);
66 }
67
68 err = pcap_setfilter(pri->pcap, pri->compiled);
69 if(err < 0){
70 printk("pcap_open : pcap_setfilter failed - '%s'\n",
71 pcap_geterr(pri->pcap));
72 return(-EIO);
73 }
74 }
75
76 return(PCAP_FD(pri->pcap));
77}
78
79static void pcap_remove(void *data)
80{
81 struct pcap_data *pri = data;
82
83 if(pri->compiled != NULL)
84 pcap_freecode(pri->compiled);
85
86 pcap_close(pri->pcap);
87}
88
89struct pcap_handler_data {
90 char *buffer;
91 int len;
92};
93
94static void handler(u_char *data, const struct pcap_pkthdr *header,
95 const u_char *packet)
96{
97 int len;
98
99 struct pcap_handler_data *hdata = (struct pcap_handler_data *) data;
100
101 len = hdata->len < header->caplen ? hdata->len : header->caplen;
102 memcpy(hdata->buffer, packet, len);
103 hdata->len = len;
104}
105
106int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri)
107{
108 struct pcap_handler_data hdata = ((struct pcap_handler_data)
109 { .buffer = buffer,
110 .len = len });
111 int n;
112
113 n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata);
114 if(n < 0){
115 printk("pcap_dispatch failed - %s\n", pcap_geterr(pri->pcap));
116 return(-EIO);
117 }
118 else if(n == 0)
119 return(0);
120 return(hdata.len);
121}
122
123struct net_user_info pcap_user_info = {
124 .init = pcap_user_init,
125 .open = pcap_open,
126 .close = NULL,
127 .remove = pcap_remove,
128 .set_mtu = NULL,
129 .add_address = NULL,
130 .delete_address = NULL,
131 .max_packet = MAX_PACKET - ETH_HEADER_OTHER
132};
133
134/*
135 * Overrides for Emacs so that we follow Linus's tabbing style.
136 * Emacs will notice this stuff at the end of the file and automatically
137 * adjust the settings for this buffer only. This must remain at the end
138 * of the file.
139 * ---------------------------------------------------------------------------
140 * Local variables:
141 * c-file-style: "linux"
142 * End:
143 */
diff --git a/arch/um/drivers/pcap_user.h b/arch/um/drivers/pcap_user.h
new file mode 100644
index 000000000000..58f9f6a1420f
--- /dev/null
+++ b/arch/um/drivers/pcap_user.h
@@ -0,0 +1,31 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "net_user.h"
7
8struct pcap_data {
9 char *host_if;
10 int promisc;
11 int optimize;
12 char *filter;
13 void *compiled;
14 void *pcap;
15 void *dev;
16};
17
18extern struct net_user_info pcap_user_info;
19
20extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri);
21
22/*
23 * Overrides for Emacs so that we follow Linus's tabbing style.
24 * Emacs will notice this stuff at the end of the file and automatically
25 * adjust the settings for this buffer only. This must remain at the end
26 * of the file.
27 * ---------------------------------------------------------------------------
28 * Local variables:
29 * c-file-style: "linux"
30 * End:
31 */
diff --git a/arch/um/drivers/port.h b/arch/um/drivers/port.h
new file mode 100644
index 000000000000..9117609a575d
--- /dev/null
+++ b/arch/um/drivers/port.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __PORT_H__
7#define __PORT_H__
8
9extern void *port_data(int port);
10extern int port_wait(void *data);
11extern void port_kern_close(void *d);
12extern int port_connection(int fd, int *socket_out, int *pid_out);
13extern int port_listen_fd(int port);
14extern void port_read(int fd, void *data);
15extern void port_kern_free(void *d);
16extern int port_rcv_fd(int fd);
17extern void port_remove_dev(void *d);
18
19#endif
20
21/*
22 * Overrides for Emacs so that we follow Linus's tabbing style.
23 * Emacs will notice this stuff at the end of the file and automatically
24 * adjust the settings for this buffer only. This must remain at the end
25 * of the file.
26 * ---------------------------------------------------------------------------
27 * Local variables:
28 * c-file-style: "linux"
29 * End:
30 */
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
new file mode 100644
index 000000000000..b5ee07472f79
--- /dev/null
+++ b/arch/um/drivers/port_kern.c
@@ -0,0 +1,309 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/list.h"
7#include "linux/sched.h"
8#include "linux/slab.h"
9#include "linux/interrupt.h"
10#include "linux/irq.h"
11#include "linux/spinlock.h"
12#include "linux/errno.h"
13#include "asm/atomic.h"
14#include "asm/semaphore.h"
15#include "asm/errno.h"
16#include "kern_util.h"
17#include "kern.h"
18#include "irq_user.h"
19#include "irq_kern.h"
20#include "port.h"
21#include "init.h"
22#include "os.h"
23
24struct port_list {
25 struct list_head list;
26 atomic_t wait_count;
27 int has_connection;
28 struct completion done;
29 int port;
30 int fd;
31 spinlock_t lock;
32 struct list_head pending;
33 struct list_head connections;
34};
35
36struct port_dev {
37 struct port_list *port;
38 int helper_pid;
39 int telnetd_pid;
40};
41
42struct connection {
43 struct list_head list;
44 int fd;
45 int helper_pid;
46 int socket[2];
47 int telnetd_pid;
48 struct port_list *port;
49};
50
51static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs)
52{
53 struct connection *conn = data;
54 int fd;
55
56 fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
57 if(fd < 0){
58 if(fd == -EAGAIN)
59 return(IRQ_NONE);
60
61 printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n",
62 -fd);
63 os_close_file(conn->fd);
64 }
65
66 list_del(&conn->list);
67
68 conn->fd = fd;
69 list_add(&conn->list, &conn->port->connections);
70
71 complete(&conn->port->done);
72 return(IRQ_HANDLED);
73}
74
75#define NO_WAITER_MSG \
76 "****\n" \
77 "There are currently no UML consoles waiting for port connections.\n" \
78 "Either disconnect from one to make it available or activate some more\n" \
79 "by enabling more consoles in the UML /etc/inittab.\n" \
80 "****\n"
81
82static int port_accept(struct port_list *port)
83{
84 struct connection *conn;
85 int fd, socket[2], pid, ret = 0;
86
87 fd = port_connection(port->fd, socket, &pid);
88 if(fd < 0){
89 if(fd != -EAGAIN)
90 printk(KERN_ERR "port_accept : port_connection "
91 "returned %d\n", -fd);
92 goto out;
93 }
94
95 conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
96 if(conn == NULL){
97 printk(KERN_ERR "port_accept : failed to allocate "
98 "connection\n");
99 goto out_close;
100 }
101 *conn = ((struct connection)
102 { .list = LIST_HEAD_INIT(conn->list),
103 .fd = fd,
104 .socket = { socket[0], socket[1] },
105 .telnetd_pid = pid,
106 .port = port });
107
108 if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt,
109 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
110 "telnetd", conn)){
111 printk(KERN_ERR "port_accept : failed to get IRQ for "
112 "telnetd\n");
113 goto out_free;
114 }
115
116 if(atomic_read(&port->wait_count) == 0){
117 os_write_file(fd, NO_WAITER_MSG, sizeof(NO_WAITER_MSG));
118 printk("No one waiting for port\n");
119 }
120 list_add(&conn->list, &port->pending);
121 return(1);
122
123 out_free:
124 kfree(conn);
125 out_close:
126 os_close_file(fd);
127 if(pid != -1)
128 os_kill_process(pid, 1);
129 out:
130 return(ret);
131}
132
133DECLARE_MUTEX(ports_sem);
134struct list_head ports = LIST_HEAD_INIT(ports);
135
136void port_work_proc(void *unused)
137{
138 struct port_list *port;
139 struct list_head *ele;
140 unsigned long flags;
141
142 local_irq_save(flags);
143 list_for_each(ele, &ports){
144 port = list_entry(ele, struct port_list, list);
145 if(!port->has_connection)
146 continue;
147 reactivate_fd(port->fd, ACCEPT_IRQ);
148 while(port_accept(port)) ;
149 port->has_connection = 0;
150 }
151 local_irq_restore(flags);
152}
153
154DECLARE_WORK(port_work, port_work_proc, NULL);
155
156static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs)
157{
158 struct port_list *port = data;
159
160 port->has_connection = 1;
161 schedule_work(&port_work);
162 return(IRQ_HANDLED);
163}
164
165void *port_data(int port_num)
166{
167 struct list_head *ele;
168 struct port_list *port;
169 struct port_dev *dev = NULL;
170 int fd;
171
172 down(&ports_sem);
173 list_for_each(ele, &ports){
174 port = list_entry(ele, struct port_list, list);
175 if(port->port == port_num) goto found;
176 }
177 port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
178 if(port == NULL){
179 printk(KERN_ERR "Allocation of port list failed\n");
180 goto out;
181 }
182
183 fd = port_listen_fd(port_num);
184 if(fd < 0){
185 printk(KERN_ERR "binding to port %d failed, errno = %d\n",
186 port_num, -fd);
187 goto out_free;
188 }
189 if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt,
190 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port",
191 port)){
192 printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
193 goto out_close;
194 }
195
196 *port = ((struct port_list)
197 { .list = LIST_HEAD_INIT(port->list),
198 .wait_count = ATOMIC_INIT(0),
199 .has_connection = 0,
200 .port = port_num,
201 .fd = fd,
202 .pending = LIST_HEAD_INIT(port->pending),
203 .connections = LIST_HEAD_INIT(port->connections) });
204 spin_lock_init(&port->lock);
205 init_completion(&port->done);
206 list_add(&port->list, &ports);
207
208 found:
209 dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
210 if(dev == NULL){
211 printk(KERN_ERR "Allocation of port device entry failed\n");
212 goto out;
213 }
214
215 *dev = ((struct port_dev) { .port = port,
216 .helper_pid = -1,
217 .telnetd_pid = -1 });
218 goto out;
219
220 out_free:
221 kfree(port);
222 out_close:
223 os_close_file(fd);
224 out:
225 up(&ports_sem);
226 return(dev);
227}
228
229int port_wait(void *data)
230{
231 struct port_dev *dev = data;
232 struct connection *conn;
233 struct port_list *port = dev->port;
234 int fd;
235
236 atomic_inc(&port->wait_count);
237 while(1){
238 fd = -ERESTARTSYS;
239 if(wait_for_completion_interruptible(&port->done))
240 goto out;
241
242 spin_lock(&port->lock);
243
244 conn = list_entry(port->connections.next, struct connection,
245 list);
246 list_del(&conn->list);
247 spin_unlock(&port->lock);
248
249 os_shutdown_socket(conn->socket[0], 1, 1);
250 os_close_file(conn->socket[0]);
251 os_shutdown_socket(conn->socket[1], 1, 1);
252 os_close_file(conn->socket[1]);
253
254 /* This is done here because freeing an IRQ can't be done
255 * within the IRQ handler. So, pipe_interrupt always ups
256 * the semaphore regardless of whether it got a successful
257 * connection. Then we loop here throwing out failed
258 * connections until a good one is found.
259 */
260 free_irq_by_irq_and_dev(TELNETD_IRQ, conn);
261 free_irq(TELNETD_IRQ, conn);
262
263 if(conn->fd >= 0) break;
264 os_close_file(conn->fd);
265 kfree(conn);
266 }
267
268 fd = conn->fd;
269 dev->helper_pid = conn->helper_pid;
270 dev->telnetd_pid = conn->telnetd_pid;
271 kfree(conn);
272 out:
273 atomic_dec(&port->wait_count);
274 return fd;
275}
276
277void port_remove_dev(void *d)
278{
279 struct port_dev *dev = d;
280
281 if(dev->helper_pid != -1)
282 os_kill_process(dev->helper_pid, 0);
283 if(dev->telnetd_pid != -1)
284 os_kill_process(dev->telnetd_pid, 1);
285 dev->helper_pid = -1;
286 dev->telnetd_pid = -1;
287}
288
289void port_kern_free(void *d)
290{
291 struct port_dev *dev = d;
292
293 port_remove_dev(dev);
294 kfree(dev);
295}
296
297static void free_port(void)
298{
299 struct list_head *ele;
300 struct port_list *port;
301
302 list_for_each(ele, &ports){
303 port = list_entry(ele, struct port_list, list);
304 free_irq_by_fd(port->fd);
305 os_close_file(port->fd);
306 }
307}
308
309__uml_exitcall(free_port);
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
new file mode 100644
index 000000000000..14dd2002d2da
--- /dev/null
+++ b/arch/um/drivers/port_user.c
@@ -0,0 +1,225 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stddef.h>
8#include <stdlib.h>
9#include <string.h>
10#include <errno.h>
11#include <unistd.h>
12#include <termios.h>
13#include <sys/socket.h>
14#include <sys/un.h>
15#include <netinet/in.h>
16#include "user_util.h"
17#include "kern_util.h"
18#include "user.h"
19#include "chan_user.h"
20#include "port.h"
21#include "helper.h"
22#include "os.h"
23
24struct port_chan {
25 int raw;
26 struct termios tt;
27 void *kernel_data;
28 char dev[sizeof("32768\0")];
29};
30
31static void *port_init(char *str, int device, struct chan_opts *opts)
32{
33 struct port_chan *data;
34 void *kern_data;
35 char *end;
36 int port;
37
38 if(*str != ':'){
39 printk("port_init : channel type 'port' must specify a "
40 "port number\n");
41 return(NULL);
42 }
43 str++;
44 port = strtoul(str, &end, 0);
45 if((*end != '\0') || (end == str)){
46 printk("port_init : couldn't parse port '%s'\n", str);
47 return(NULL);
48 }
49
50 kern_data = port_data(port);
51 if(kern_data == NULL)
52 return(NULL);
53
54 data = um_kmalloc(sizeof(*data));
55 if(data == NULL)
56 goto err;
57
58 *data = ((struct port_chan) { .raw = opts->raw,
59 .kernel_data = kern_data });
60 sprintf(data->dev, "%d", port);
61
62 return(data);
63 err:
64 port_kern_free(kern_data);
65 return(NULL);
66}
67
68static void port_free(void *d)
69{
70 struct port_chan *data = d;
71
72 port_kern_free(data->kernel_data);
73 kfree(data);
74}
75
76static int port_open(int input, int output, int primary, void *d,
77 char **dev_out)
78{
79 struct port_chan *data = d;
80 int fd, err;
81
82 fd = port_wait(data->kernel_data);
83 if((fd >= 0) && data->raw){
84 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
85 if(err)
86 return(err);
87
88 err = raw(fd);
89 if(err)
90 return(err);
91 }
92 *dev_out = data->dev;
93 return(fd);
94}
95
96static void port_close(int fd, void *d)
97{
98 struct port_chan *data = d;
99
100 port_remove_dev(data->kernel_data);
101 os_close_file(fd);
102}
103
104static int port_console_write(int fd, const char *buf, int n, void *d)
105{
106 struct port_chan *data = d;
107
108 return(generic_console_write(fd, buf, n, &data->tt));
109}
110
111struct chan_ops port_ops = {
112 .type = "port",
113 .init = port_init,
114 .open = port_open,
115 .close = port_close,
116 .read = generic_read,
117 .write = generic_write,
118 .console_write = port_console_write,
119 .window_size = generic_window_size,
120 .free = port_free,
121 .winch = 1,
122};
123
124int port_listen_fd(int port)
125{
126 struct sockaddr_in addr;
127 int fd, err, arg;
128
129 fd = socket(PF_INET, SOCK_STREAM, 0);
130 if(fd == -1)
131 return(-errno);
132
133 arg = 1;
134 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){
135 err = -errno;
136 goto out;
137 }
138
139 addr.sin_family = AF_INET;
140 addr.sin_port = htons(port);
141 addr.sin_addr.s_addr = htonl(INADDR_ANY);
142 if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0){
143 err = -errno;
144 goto out;
145 }
146
147 if(listen(fd, 1) < 0){
148 err = -errno;
149 goto out;
150 }
151
152 err = os_set_fd_block(fd, 0);
153 if(err < 0)
154 goto out;
155
156 return(fd);
157 out:
158 os_close_file(fd);
159 return(err);
160}
161
162struct port_pre_exec_data {
163 int sock_fd;
164 int pipe_fd;
165};
166
167void port_pre_exec(void *arg)
168{
169 struct port_pre_exec_data *data = arg;
170
171 dup2(data->sock_fd, 0);
172 dup2(data->sock_fd, 1);
173 dup2(data->sock_fd, 2);
174 os_close_file(data->sock_fd);
175 dup2(data->pipe_fd, 3);
176 os_shutdown_socket(3, 1, 0);
177 os_close_file(data->pipe_fd);
178}
179
180int port_connection(int fd, int *socket, int *pid_out)
181{
182 int new, err;
183 char *argv[] = { "/usr/sbin/in.telnetd", "-L",
184 "/usr/lib/uml/port-helper", NULL };
185 struct port_pre_exec_data data;
186
187 new = os_accept_connection(fd);
188 if(new < 0)
189 return(new);
190
191 err = os_pipe(socket, 0, 0);
192 if(err < 0)
193 goto out_close;
194
195 data = ((struct port_pre_exec_data)
196 { .sock_fd = new,
197 .pipe_fd = socket[1] });
198
199 err = run_helper(port_pre_exec, &data, argv, NULL);
200 if(err < 0)
201 goto out_shutdown;
202
203 *pid_out = err;
204 return(new);
205
206 out_shutdown:
207 os_shutdown_socket(socket[0], 1, 1);
208 os_close_file(socket[0]);
209 os_shutdown_socket(socket[1], 1, 1);
210 os_close_file(socket[1]);
211 out_close:
212 os_close_file(new);
213 return(err);
214}
215
216/*
217 * Overrides for Emacs so that we follow Linus's tabbing style.
218 * Emacs will notice this stuff at the end of the file and automatically
219 * adjust the settings for this buffer only. This must remain at the end
220 * of the file.
221 * ---------------------------------------------------------------------------
222 * Local variables:
223 * c-file-style: "linux"
224 * End:
225 */
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
new file mode 100644
index 000000000000..ed84d01df6cc
--- /dev/null
+++ b/arch/um/drivers/pty.c
@@ -0,0 +1,162 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <unistd.h>
8#include <string.h>
9#include <errno.h>
10#include <termios.h>
11#include "chan_user.h"
12#include "user.h"
13#include "user_util.h"
14#include "kern_util.h"
15#include "os.h"
16
17struct pty_chan {
18 void (*announce)(char *dev_name, int dev);
19 int dev;
20 int raw;
21 struct termios tt;
22 char dev_name[sizeof("/dev/pts/0123456\0")];
23};
24
25static void *pty_chan_init(char *str, int device, struct chan_opts *opts)
26{
27 struct pty_chan *data;
28
29 data = um_kmalloc(sizeof(*data));
30 if(data == NULL) return(NULL);
31 *data = ((struct pty_chan) { .announce = opts->announce,
32 .dev = device,
33 .raw = opts->raw });
34 return(data);
35}
36
37static int pts_open(int input, int output, int primary, void *d,
38 char **dev_out)
39{
40 struct pty_chan *data = d;
41 char *dev;
42 int fd, err;
43
44 fd = get_pty();
45 if(fd < 0){
46 printk("open_pts : Failed to open pts\n");
47 return(-errno);
48 }
49 if(data->raw){
50 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
51 if(err)
52 return(err);
53
54 err = raw(fd);
55 if(err)
56 return(err);
57 }
58
59 dev = ptsname(fd);
60 sprintf(data->dev_name, "%s", dev);
61 *dev_out = data->dev_name;
62 if (data->announce)
63 (*data->announce)(dev, data->dev);
64 return(fd);
65}
66
67static int getmaster(char *line)
68{
69 char *pty, *bank, *cp;
70 int master, err;
71
72 pty = &line[strlen("/dev/ptyp")];
73 for (bank = "pqrs"; *bank; bank++) {
74 line[strlen("/dev/pty")] = *bank;
75 *pty = '0';
76 if (os_stat_file(line, NULL) < 0)
77 break;
78 for (cp = "0123456789abcdef"; *cp; cp++) {
79 *pty = *cp;
80 master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
81 if (master >= 0) {
82 char *tp = &line[strlen("/dev/")];
83
84 /* verify slave side is usable */
85 *tp = 't';
86 err = os_access(line, OS_ACC_RW_OK);
87 *tp = 'p';
88 if(err == 0) return(master);
89 (void) os_close_file(master);
90 }
91 }
92 }
93 return(-1);
94}
95
96static int pty_open(int input, int output, int primary, void *d,
97 char **dev_out)
98{
99 struct pty_chan *data = d;
100 int fd, err;
101 char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
102
103 fd = getmaster(dev);
104 if(fd < 0)
105 return(-errno);
106
107 if(data->raw){
108 err = raw(fd);
109 if(err)
110 return(err);
111 }
112
113 if(data->announce) (*data->announce)(dev, data->dev);
114
115 sprintf(data->dev_name, "%s", dev);
116 *dev_out = data->dev_name;
117 return(fd);
118}
119
120static int pty_console_write(int fd, const char *buf, int n, void *d)
121{
122 struct pty_chan *data = d;
123
124 return(generic_console_write(fd, buf, n, &data->tt));
125}
126
127struct chan_ops pty_ops = {
128 .type = "pty",
129 .init = pty_chan_init,
130 .open = pty_open,
131 .close = generic_close,
132 .read = generic_read,
133 .write = generic_write,
134 .console_write = pty_console_write,
135 .window_size = generic_window_size,
136 .free = generic_free,
137 .winch = 0,
138};
139
140struct chan_ops pts_ops = {
141 .type = "pts",
142 .init = pty_chan_init,
143 .open = pts_open,
144 .close = generic_close,
145 .read = generic_read,
146 .write = generic_write,
147 .console_write = pty_console_write,
148 .window_size = generic_window_size,
149 .free = generic_free,
150 .winch = 0,
151};
152
153/*
154 * Overrides for Emacs so that we follow Linus's tabbing style.
155 * Emacs will notice this stuff at the end of the file and automatically
156 * adjust the settings for this buffer only. This must remain at the end
157 * of the file.
158 * ---------------------------------------------------------------------------
159 * Local variables:
160 * c-file-style: "linux"
161 * End:
162 */
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
new file mode 100644
index 000000000000..d43e9fab05a7
--- /dev/null
+++ b/arch/um/drivers/random.c
@@ -0,0 +1,122 @@
1/* Much of this ripped from hw_random.c */
2
3#include <linux/module.h>
4#include <linux/fs.h>
5#include <linux/miscdevice.h>
6#include <linux/delay.h>
7#include <asm/uaccess.h>
8#include "os.h"
9
10/*
11 * core module and version information
12 */
13#define RNG_VERSION "1.0.0"
14#define RNG_MODULE_NAME "random"
15#define RNG_DRIVER_NAME RNG_MODULE_NAME " virtual driver " RNG_VERSION
16#define PFX RNG_MODULE_NAME ": "
17
18#define RNG_MISCDEV_MINOR 183 /* official */
19
20static int random_fd = -1;
21
22static int rng_dev_open (struct inode *inode, struct file *filp)
23{
24 /* enforce read-only access to this chrdev */
25 if ((filp->f_mode & FMODE_READ) == 0)
26 return -EINVAL;
27 if (filp->f_mode & FMODE_WRITE)
28 return -EINVAL;
29
30 return 0;
31}
32
33static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
34 loff_t * offp)
35{
36 u32 data;
37 int n, ret = 0, have_data;
38
39 while(size){
40 n = os_read_file(random_fd, &data, sizeof(data));
41 if(n > 0){
42 have_data = n;
43 while (have_data && size) {
44 if (put_user((u8)data, buf++)) {
45 ret = ret ? : -EFAULT;
46 break;
47 }
48 size--;
49 ret++;
50 have_data--;
51 data>>=8;
52 }
53 }
54 else if(n == -EAGAIN){
55 if (filp->f_flags & O_NONBLOCK)
56 return ret ? : -EAGAIN;
57
58 if(need_resched()){
59 current->state = TASK_INTERRUPTIBLE;
60 schedule_timeout(1);
61 }
62 }
63 else return n;
64 if (signal_pending (current))
65 return ret ? : -ERESTARTSYS;
66 }
67 return ret;
68}
69
70static struct file_operations rng_chrdev_ops = {
71 .owner = THIS_MODULE,
72 .open = rng_dev_open,
73 .read = rng_dev_read,
74};
75
76static struct miscdevice rng_miscdev = {
77 RNG_MISCDEV_MINOR,
78 RNG_MODULE_NAME,
79 &rng_chrdev_ops,
80};
81
82/*
83 * rng_init - initialize RNG module
84 */
85static int __init rng_init (void)
86{
87 int err;
88
89 err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
90 if(err < 0)
91 goto out;
92
93 random_fd = err;
94
95 err = os_set_fd_block(random_fd, 0);
96 if(err)
97 goto err_out_cleanup_hw;
98
99 err = misc_register (&rng_miscdev);
100 if (err) {
101 printk (KERN_ERR PFX "misc device register failed\n");
102 goto err_out_cleanup_hw;
103 }
104
105 out:
106 return err;
107
108 err_out_cleanup_hw:
109 random_fd = -1;
110 goto out;
111}
112
113/*
114 * rng_cleanup - shutdown RNG module
115 */
116static void __exit rng_cleanup (void)
117{
118 misc_deregister (&rng_miscdev);
119}
120
121module_init (rng_init);
122module_exit (rng_cleanup);
diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h
new file mode 100644
index 000000000000..495f2f1b1420
--- /dev/null
+++ b/arch/um/drivers/slip.h
@@ -0,0 +1,39 @@
1#ifndef __UM_SLIP_H
2#define __UM_SLIP_H
3
4#define BUF_SIZE 1500
5 /* two bytes each for a (pathological) max packet of escaped chars + *
6 * terminating END char + initial END char */
7#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
8
9struct slip_data {
10 void *dev;
11 char name[sizeof("slnnnnn\0")];
12 char *addr;
13 char *gate_addr;
14 int slave;
15 char ibuf[ENC_BUF_SIZE];
16 char obuf[ENC_BUF_SIZE];
17 int more; /* more data: do not read fd until ibuf has been drained */
18 int pos;
19 int esc;
20};
21
22extern struct net_user_info slip_user_info;
23
24extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
25extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri);
26extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri);
27
28#endif
29
30/*
31 * Overrides for Emacs so that we follow Linus's tabbing style.
32 * Emacs will notice this stuff at the end of the file and automatically
33 * adjust the settings for this buffer only. This must remain at the end
34 * of the file.
35 * ---------------------------------------------------------------------------
36 * Local variables:
37 * c-file-style: "linux"
38 * End:
39 */
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
new file mode 100644
index 000000000000..0886eedba213
--- /dev/null
+++ b/arch/um/drivers/slip_kern.c
@@ -0,0 +1,109 @@
1#include "linux/config.h"
2#include "linux/kernel.h"
3#include "linux/stddef.h"
4#include "linux/init.h"
5#include "linux/netdevice.h"
6#include "linux/if_arp.h"
7#include "net_kern.h"
8#include "net_user.h"
9#include "kern.h"
10#include "slip.h"
11
12struct slip_init {
13 char *gate_addr;
14};
15
16void slip_init(struct net_device *dev, void *data)
17{
18 struct uml_net_private *private;
19 struct slip_data *spri;
20 struct slip_init *init = data;
21
22 private = dev->priv;
23 spri = (struct slip_data *) private->user;
24 *spri = ((struct slip_data)
25 { .name = { '\0' },
26 .addr = NULL,
27 .gate_addr = init->gate_addr,
28 .slave = -1,
29 .ibuf = { '\0' },
30 .obuf = { '\0' },
31 .pos = 0,
32 .esc = 0,
33 .dev = dev });
34
35 dev->init = NULL;
36 dev->hard_header_len = 0;
37 dev->addr_len = 4;
38 dev->type = ARPHRD_ETHER;
39 dev->tx_queue_len = 256;
40 dev->flags = IFF_NOARP;
41 printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
42}
43
44static unsigned short slip_protocol(struct sk_buff *skbuff)
45{
46 return(htons(ETH_P_IP));
47}
48
49static int slip_read(int fd, struct sk_buff **skb,
50 struct uml_net_private *lp)
51{
52 return(slip_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu,
53 (struct slip_data *) &lp->user));
54}
55
56static int slip_write(int fd, struct sk_buff **skb,
57 struct uml_net_private *lp)
58{
59 return(slip_user_write(fd, (*skb)->data, (*skb)->len,
60 (struct slip_data *) &lp->user));
61}
62
63struct net_kern_info slip_kern_info = {
64 .init = slip_init,
65 .protocol = slip_protocol,
66 .read = slip_read,
67 .write = slip_write,
68};
69
70static int slip_setup(char *str, char **mac_out, void *data)
71{
72 struct slip_init *init = data;
73
74 *init = ((struct slip_init)
75 { .gate_addr = NULL });
76
77 if(str[0] != '\0')
78 init->gate_addr = str;
79 return(1);
80}
81
82static struct transport slip_transport = {
83 .list = LIST_HEAD_INIT(slip_transport.list),
84 .name = "slip",
85 .setup = slip_setup,
86 .user = &slip_user_info,
87 .kern = &slip_kern_info,
88 .private_size = sizeof(struct slip_data),
89 .setup_size = sizeof(struct slip_init),
90};
91
92static int register_slip(void)
93{
94 register_transport(&slip_transport);
95 return(1);
96}
97
98__initcall(register_slip);
99
100/*
101 * Overrides for Emacs so that we follow Linus's tabbing style.
102 * Emacs will notice this stuff at the end of the file and automatically
103 * adjust the settings for this buffer only. This must remain at the end
104 * of the file.
105 * ---------------------------------------------------------------------------
106 * Local variables:
107 * c-file-style: "linux"
108 * End:
109 */
diff --git a/arch/um/drivers/slip_proto.h b/arch/um/drivers/slip_proto.h
new file mode 100644
index 000000000000..7206361ace45
--- /dev/null
+++ b/arch/um/drivers/slip_proto.h
@@ -0,0 +1,93 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __UM_SLIP_PROTO_H__
7#define __UM_SLIP_PROTO_H__
8
9/* SLIP protocol characters. */
10#define SLIP_END 0300 /* indicates end of frame */
11#define SLIP_ESC 0333 /* indicates byte stuffing */
12#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */
13#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
14
15static inline int slip_unesc(unsigned char c,char *buf,int *pos, int *esc)
16{
17 int ret;
18
19 switch(c){
20 case SLIP_END:
21 *esc = 0;
22 ret=*pos;
23 *pos=0;
24 return(ret);
25 case SLIP_ESC:
26 *esc = 1;
27 return(0);
28 case SLIP_ESC_ESC:
29 if(*esc){
30 *esc = 0;
31 c = SLIP_ESC;
32 }
33 break;
34 case SLIP_ESC_END:
35 if(*esc){
36 *esc = 0;
37 c = SLIP_END;
38 }
39 break;
40 }
41 buf[(*pos)++] = c;
42 return(0);
43}
44
45static inline int slip_esc(unsigned char *s, unsigned char *d, int len)
46{
47 unsigned char *ptr = d;
48 unsigned char c;
49
50 /*
51 * Send an initial END character to flush out any
52 * data that may have accumulated in the receiver
53 * due to line noise.
54 */
55
56 *ptr++ = SLIP_END;
57
58 /*
59 * For each byte in the packet, send the appropriate
60 * character sequence, according to the SLIP protocol.
61 */
62
63 while (len-- > 0) {
64 switch(c = *s++) {
65 case SLIP_END:
66 *ptr++ = SLIP_ESC;
67 *ptr++ = SLIP_ESC_END;
68 break;
69 case SLIP_ESC:
70 *ptr++ = SLIP_ESC;
71 *ptr++ = SLIP_ESC_ESC;
72 break;
73 default:
74 *ptr++ = c;
75 break;
76 }
77 }
78 *ptr++ = SLIP_END;
79 return (ptr - d);
80}
81
82#endif
83
84/*
85 * Overrides for Emacs so that we follow Linus's tabbing style.
86 * Emacs will notice this stuff at the end of the file and automatically
87 * adjust the settings for this buffer only. This must remain at the end
88 * of the file.
89 * ---------------------------------------------------------------------------
90 * Local variables:
91 * c-file-style: "linux"
92 * End:
93 */
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
new file mode 100644
index 000000000000..d94846b1b4cf
--- /dev/null
+++ b/arch/um/drivers/slip_user.c
@@ -0,0 +1,280 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <stddef.h>
5#include <sched.h>
6#include <string.h>
7#include <errno.h>
8#include <sys/termios.h>
9#include <sys/wait.h>
10#include <sys/signal.h>
11#include "user_util.h"
12#include "kern_util.h"
13#include "user.h"
14#include "net_user.h"
15#include "slip.h"
16#include "slip_proto.h"
17#include "helper.h"
18#include "os.h"
19
20void slip_user_init(void *data, void *dev)
21{
22 struct slip_data *pri = data;
23
24 pri->dev = dev;
25}
26
27static int set_up_tty(int fd)
28{
29 int i;
30 struct termios tios;
31
32 if (tcgetattr(fd, &tios) < 0) {
33 printk("could not get initial terminal attributes\n");
34 return(-1);
35 }
36
37 tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
38 tios.c_iflag = IGNBRK | IGNPAR;
39 tios.c_oflag = 0;
40 tios.c_lflag = 0;
41 for (i = 0; i < NCCS; i++)
42 tios.c_cc[i] = 0;
43 tios.c_cc[VMIN] = 1;
44 tios.c_cc[VTIME] = 0;
45
46 cfsetospeed(&tios, B38400);
47 cfsetispeed(&tios, B38400);
48
49 if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
50 printk("failed to set terminal attributes\n");
51 return(-1);
52 }
53 return(0);
54}
55
56struct slip_pre_exec_data {
57 int stdin;
58 int stdout;
59 int close_me;
60};
61
62static void slip_pre_exec(void *arg)
63{
64 struct slip_pre_exec_data *data = arg;
65
66 if(data->stdin >= 0) dup2(data->stdin, 0);
67 dup2(data->stdout, 1);
68 if(data->close_me >= 0) os_close_file(data->close_me);
69}
70
71static int slip_tramp(char **argv, int fd)
72{
73 struct slip_pre_exec_data pe_data;
74 char *output;
75 int status, pid, fds[2], err, output_len;
76
77 err = os_pipe(fds, 1, 0);
78 if(err < 0){
79 printk("slip_tramp : pipe failed, err = %d\n", -err);
80 return(err);
81 }
82
83 err = 0;
84 pe_data.stdin = fd;
85 pe_data.stdout = fds[1];
86 pe_data.close_me = fds[0];
87 pid = run_helper(slip_pre_exec, &pe_data, argv, NULL);
88
89 if(pid < 0) err = pid;
90 else {
91 output_len = page_size();
92 output = um_kmalloc(output_len);
93 if(output == NULL)
94 printk("slip_tramp : failed to allocate output "
95 "buffer\n");
96
97 os_close_file(fds[1]);
98 read_output(fds[0], output, output_len);
99 if(output != NULL){
100 printk("%s", output);
101 kfree(output);
102 }
103 CATCH_EINTR(err = waitpid(pid, &status, 0));
104 if(err < 0)
105 err = errno;
106 else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
107 printk("'%s' didn't exit with status 0\n", argv[0]);
108 err = -EINVAL;
109 }
110 }
111
112 os_close_file(fds[0]);
113
114 return(err);
115}
116
117static int slip_open(void *data)
118{
119 struct slip_data *pri = data;
120 char version_buf[sizeof("nnnnn\0")];
121 char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
122 char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf,
123 NULL };
124 int sfd, mfd, err;
125
126 mfd = get_pty();
127 if(mfd < 0){
128 printk("umn : Failed to open pty, err = %d\n", -mfd);
129 return(mfd);
130 }
131 sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0);
132 if(sfd < 0){
133 printk("Couldn't open tty for slip line, err = %d\n", -sfd);
134 os_close_file(mfd);
135 return(sfd);
136 }
137 if(set_up_tty(sfd)) return(-1);
138 pri->slave = sfd;
139 pri->pos = 0;
140 pri->esc = 0;
141 if(pri->gate_addr != NULL){
142 sprintf(version_buf, "%d", UML_NET_VERSION);
143 strcpy(gate_buf, pri->gate_addr);
144
145 err = slip_tramp(argv, sfd);
146
147 if(err < 0){
148 printk("slip_tramp failed - err = %d\n", -err);
149 return(err);
150 }
151 err = os_get_ifname(pri->slave, pri->name);
152 if(err < 0){
153 printk("get_ifname failed, err = %d\n", -err);
154 return(err);
155 }
156 iter_addresses(pri->dev, open_addr, pri->name);
157 }
158 else {
159 err = os_set_slip(sfd);
160 if(err < 0){
161 printk("Failed to set slip discipline encapsulation - "
162 "err = %d\n", -err);
163 return(err);
164 }
165 }
166 return(mfd);
167}
168
169static void slip_close(int fd, void *data)
170{
171 struct slip_data *pri = data;
172 char version_buf[sizeof("nnnnn\0")];
173 char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name,
174 NULL };
175 int err;
176
177 if(pri->gate_addr != NULL)
178 iter_addresses(pri->dev, close_addr, pri->name);
179
180 sprintf(version_buf, "%d", UML_NET_VERSION);
181
182 err = slip_tramp(argv, pri->slave);
183
184 if(err != 0)
185 printk("slip_tramp failed - errno = %d\n", -err);
186 os_close_file(fd);
187 os_close_file(pri->slave);
188 pri->slave = -1;
189}
190
191int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
192{
193 int i, n, size, start;
194
195 if(pri->more>0) {
196 i = 0;
197 while(i < pri->more) {
198 size = slip_unesc(pri->ibuf[i++],
199 pri->ibuf, &pri->pos, &pri->esc);
200 if(size){
201 memcpy(buf, pri->ibuf, size);
202 memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
203 pri->more=pri->more-i;
204 return(size);
205 }
206 }
207 pri->more=0;
208 }
209
210 n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
211 if(n <= 0) return(n);
212
213 start = pri->pos;
214 for(i = 0; i < n; i++){
215 size = slip_unesc(pri->ibuf[start + i],
216 pri->ibuf, &pri->pos, &pri->esc);
217 if(size){
218 memcpy(buf, pri->ibuf, size);
219 memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
220 pri->more=n-(i+1);
221 return(size);
222 }
223 }
224 return(0);
225}
226
227int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
228{
229 int actual, n;
230
231 actual = slip_esc(buf, pri->obuf, len);
232 n = net_write(fd, pri->obuf, actual);
233 if(n < 0) return(n);
234 else return(len);
235}
236
237static int slip_set_mtu(int mtu, void *data)
238{
239 return(mtu);
240}
241
242static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
243 void *data)
244{
245 struct slip_data *pri = data;
246
247 if(pri->slave < 0) return;
248 open_addr(addr, netmask, pri->name);
249}
250
251static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
252 void *data)
253{
254 struct slip_data *pri = data;
255
256 if(pri->slave < 0) return;
257 close_addr(addr, netmask, pri->name);
258}
259
260struct net_user_info slip_user_info = {
261 .init = slip_user_init,
262 .open = slip_open,
263 .close = slip_close,
264 .remove = NULL,
265 .set_mtu = slip_set_mtu,
266 .add_address = slip_add_addr,
267 .delete_address = slip_del_addr,
268 .max_packet = BUF_SIZE
269};
270
271/*
272 * Overrides for Emacs so that we follow Linus's tabbing style.
273 * Emacs will notice this stuff at the end of the file and automatically
274 * adjust the settings for this buffer only. This must remain at the end
275 * of the file.
276 * ---------------------------------------------------------------------------
277 * Local variables:
278 * c-file-style: "linux"
279 * End:
280 */
diff --git a/arch/um/drivers/slirp.h b/arch/um/drivers/slirp.h
new file mode 100644
index 000000000000..04e407d1e44a
--- /dev/null
+++ b/arch/um/drivers/slirp.h
@@ -0,0 +1,51 @@
1#ifndef __UM_SLIRP_H
2#define __UM_SLIRP_H
3
4#define BUF_SIZE 1500
5 /* two bytes each for a (pathological) max packet of escaped chars + *
6 * terminating END char + initial END char */
7#define ENC_BUF_SIZE (2 * BUF_SIZE + 2)
8
9#define SLIRP_MAX_ARGS 100
10/*
11 * XXX this next definition is here because I don't understand why this
12 * initializer doesn't work in slirp_kern.c:
13 *
14 * argv : { init->argv[ 0 ... SLIRP_MAX_ARGS-1 ] },
15 *
16 * or why I can't typecast like this:
17 *
18 * argv : (char* [SLIRP_MAX_ARGS])(init->argv),
19 */
20struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; };
21
22struct slirp_data {
23 void *dev;
24 struct arg_list_dummy_wrapper argw;
25 int pid;
26 int slave;
27 char ibuf[ENC_BUF_SIZE];
28 char obuf[ENC_BUF_SIZE];
29 int more; /* more data: do not read fd until ibuf has been drained */
30 int pos;
31 int esc;
32};
33
34extern struct net_user_info slirp_user_info;
35
36extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
37extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri);
38extern int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri);
39
40#endif
41
42/*
43 * Overrides for Emacs so that we follow Linus's tabbing style.
44 * Emacs will notice this stuff at the end of the file and automatically
45 * adjust the settings for this buffer only. This must remain at the end
46 * of the file.
47 * ---------------------------------------------------------------------------
48 * Local variables:
49 * c-file-style: "linux"
50 * End:
51 */
diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
new file mode 100644
index 000000000000..c9d6b52a831d
--- /dev/null
+++ b/arch/um/drivers/slirp_kern.c
@@ -0,0 +1,135 @@
1#include "linux/kernel.h"
2#include "linux/stddef.h"
3#include "linux/init.h"
4#include "linux/netdevice.h"
5#include "linux/if_arp.h"
6#include "net_kern.h"
7#include "net_user.h"
8#include "kern.h"
9#include "slirp.h"
10
11struct slirp_init {
12 struct arg_list_dummy_wrapper argw; /* XXX should be simpler... */
13};
14
15void slirp_init(struct net_device *dev, void *data)
16{
17 struct uml_net_private *private;
18 struct slirp_data *spri;
19 struct slirp_init *init = data;
20 int i;
21
22 private = dev->priv;
23 spri = (struct slirp_data *) private->user;
24 *spri = ((struct slirp_data)
25 { .argw = init->argw,
26 .pid = -1,
27 .slave = -1,
28 .ibuf = { '\0' },
29 .obuf = { '\0' },
30 .pos = 0,
31 .esc = 0,
32 .dev = dev });
33
34 dev->init = NULL;
35 dev->hard_header_len = 0;
36 dev->header_cache_update = NULL;
37 dev->hard_header_cache = NULL;
38 dev->hard_header = NULL;
39 dev->addr_len = 0;
40 dev->type = ARPHRD_SLIP;
41 dev->tx_queue_len = 256;
42 dev->flags = IFF_NOARP;
43 printk("SLIRP backend - command line:");
44 for(i=0;spri->argw.argv[i]!=NULL;i++) {
45 printk(" '%s'",spri->argw.argv[i]);
46 }
47 printk("\n");
48}
49
50static unsigned short slirp_protocol(struct sk_buff *skbuff)
51{
52 return(htons(ETH_P_IP));
53}
54
55static int slirp_read(int fd, struct sk_buff **skb,
56 struct uml_net_private *lp)
57{
58 return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu,
59 (struct slirp_data *) &lp->user));
60}
61
62static int slirp_write(int fd, struct sk_buff **skb,
63 struct uml_net_private *lp)
64{
65 return(slirp_user_write(fd, (*skb)->data, (*skb)->len,
66 (struct slirp_data *) &lp->user));
67}
68
69struct net_kern_info slirp_kern_info = {
70 .init = slirp_init,
71 .protocol = slirp_protocol,
72 .read = slirp_read,
73 .write = slirp_write,
74};
75
76static int slirp_setup(char *str, char **mac_out, void *data)
77{
78 struct slirp_init *init = data;
79 int i=0;
80
81 *init = ((struct slirp_init)
82 { argw : { { "slirp", NULL } } });
83
84 str = split_if_spec(str, mac_out, NULL);
85
86 if(str == NULL) { /* no command line given after MAC addr */
87 return(1);
88 }
89
90 do {
91 if(i>=SLIRP_MAX_ARGS-1) {
92 printk("slirp_setup: truncating slirp arguments\n");
93 break;
94 }
95 init->argw.argv[i++] = str;
96 while(*str && *str!=',') {
97 if(*str=='_') *str=' ';
98 str++;
99 }
100 if(*str!=',')
101 break;
102 *str++='\0';
103 } while(1);
104 init->argw.argv[i]=NULL;
105 return(1);
106}
107
108static struct transport slirp_transport = {
109 .list = LIST_HEAD_INIT(slirp_transport.list),
110 .name = "slirp",
111 .setup = slirp_setup,
112 .user = &slirp_user_info,
113 .kern = &slirp_kern_info,
114 .private_size = sizeof(struct slirp_data),
115 .setup_size = sizeof(struct slirp_init),
116};
117
118static int register_slirp(void)
119{
120 register_transport(&slirp_transport);
121 return(1);
122}
123
124__initcall(register_slirp);
125
126/*
127 * Overrides for Emacs so that we follow Linus's tabbing style.
128 * Emacs will notice this stuff at the end of the file and automatically
129 * adjust the settings for this buffer only. This must remain at the end
130 * of the file.
131 * ---------------------------------------------------------------------------
132 * Local variables:
133 * c-file-style: "linux"
134 * End:
135 */
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
new file mode 100644
index 000000000000..c322515c71cc
--- /dev/null
+++ b/arch/um/drivers/slirp_user.c
@@ -0,0 +1,201 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <stddef.h>
5#include <sched.h>
6#include <string.h>
7#include <errno.h>
8#include <sys/wait.h>
9#include <sys/signal.h>
10#include "user_util.h"
11#include "kern_util.h"
12#include "user.h"
13#include "net_user.h"
14#include "slirp.h"
15#include "slip_proto.h"
16#include "helper.h"
17#include "os.h"
18
19void slirp_user_init(void *data, void *dev)
20{
21 struct slirp_data *pri = data;
22
23 pri->dev = dev;
24}
25
26struct slirp_pre_exec_data {
27 int stdin;
28 int stdout;
29};
30
31static void slirp_pre_exec(void *arg)
32{
33 struct slirp_pre_exec_data *data = arg;
34
35 if(data->stdin != -1) dup2(data->stdin, 0);
36 if(data->stdout != -1) dup2(data->stdout, 1);
37}
38
39static int slirp_tramp(char **argv, int fd)
40{
41 struct slirp_pre_exec_data pe_data;
42 int pid;
43
44 pe_data.stdin = fd;
45 pe_data.stdout = fd;
46 pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL);
47
48 return(pid);
49}
50
51/* XXX This is just a trivial wrapper around os_pipe */
52static int slirp_datachan(int *mfd, int *sfd)
53{
54 int fds[2], err;
55
56 err = os_pipe(fds, 1, 1);
57 if(err < 0){
58 printk("slirp_datachan: Failed to open pipe, err = %d\n", -err);
59 return(err);
60 }
61
62 *mfd = fds[0];
63 *sfd = fds[1];
64 return(0);
65}
66
67static int slirp_open(void *data)
68{
69 struct slirp_data *pri = data;
70 int sfd, mfd, pid, err;
71
72 err = slirp_datachan(&mfd, &sfd);
73 if(err)
74 return(err);
75
76 pid = slirp_tramp(pri->argw.argv, sfd);
77
78 if(pid < 0){
79 printk("slirp_tramp failed - errno = %d\n", -pid);
80 os_close_file(sfd);
81 os_close_file(mfd);
82 return(pid);
83 }
84
85 pri->slave = sfd;
86 pri->pos = 0;
87 pri->esc = 0;
88
89 pri->pid = pid;
90
91 return(mfd);
92}
93
94static void slirp_close(int fd, void *data)
95{
96 struct slirp_data *pri = data;
97 int status,err;
98
99 os_close_file(fd);
100 os_close_file(pri->slave);
101
102 pri->slave = -1;
103
104 if(pri->pid<1) {
105 printk("slirp_close: no child process to shut down\n");
106 return;
107 }
108
109#if 0
110 if(kill(pri->pid, SIGHUP)<0) {
111 printk("slirp_close: sending hangup to %d failed (%d)\n",
112 pri->pid, errno);
113 }
114#endif
115
116 CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG));
117 if(err < 0) {
118 printk("slirp_close: waitpid returned %d\n", errno);
119 return;
120 }
121
122 if(err == 0) {
123 printk("slirp_close: process %d has not exited\n");
124 return;
125 }
126
127 pri->pid = -1;
128}
129
130int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
131{
132 int i, n, size, start;
133
134 if(pri->more>0) {
135 i = 0;
136 while(i < pri->more) {
137 size = slip_unesc(pri->ibuf[i++],
138 pri->ibuf,&pri->pos,&pri->esc);
139 if(size){
140 memcpy(buf, pri->ibuf, size);
141 memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
142 pri->more=pri->more-i;
143 return(size);
144 }
145 }
146 pri->more=0;
147 }
148
149 n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
150 if(n <= 0) return(n);
151
152 start = pri->pos;
153 for(i = 0; i < n; i++){
154 size = slip_unesc(pri->ibuf[start + i],
155 pri->ibuf,&pri->pos,&pri->esc);
156 if(size){
157 memcpy(buf, pri->ibuf, size);
158 memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
159 pri->more=n-(i+1);
160 return(size);
161 }
162 }
163 return(0);
164}
165
166int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri)
167{
168 int actual, n;
169
170 actual = slip_esc(buf, pri->obuf, len);
171 n = net_write(fd, pri->obuf, actual);
172 if(n < 0) return(n);
173 else return(len);
174}
175
176static int slirp_set_mtu(int mtu, void *data)
177{
178 return(mtu);
179}
180
181struct net_user_info slirp_user_info = {
182 .init = slirp_user_init,
183 .open = slirp_open,
184 .close = slirp_close,
185 .remove = NULL,
186 .set_mtu = slirp_set_mtu,
187 .add_address = NULL,
188 .delete_address = NULL,
189 .max_packet = BUF_SIZE
190};
191
192/*
193 * Overrides for Emacs so that we follow Linus's tabbing style.
194 * Emacs will notice this stuff at the end of the file and automatically
195 * adjust the settings for this buffer only. This must remain at the end
196 * of the file.
197 * ---------------------------------------------------------------------------
198 * Local variables:
199 * c-file-style: "linux"
200 * End:
201 */
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
new file mode 100644
index 000000000000..c5839c3141f8
--- /dev/null
+++ b/arch/um/drivers/ssl.c
@@ -0,0 +1,251 @@
1/*
2 * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/fs.h"
8#include "linux/tty.h"
9#include "linux/tty_driver.h"
10#include "linux/major.h"
11#include "linux/mm.h"
12#include "linux/init.h"
13#include "linux/console.h"
14#include "asm/termbits.h"
15#include "asm/irq.h"
16#include "line.h"
17#include "ssl.h"
18#include "chan_kern.h"
19#include "user_util.h"
20#include "kern_util.h"
21#include "kern.h"
22#include "init.h"
23#include "irq_user.h"
24#include "mconsole_kern.h"
25#include "2_5compat.h"
26
27static int ssl_version = 1;
28
29/* Referenced only by tty_driver below - presumably it's locked correctly
30 * by the tty driver.
31 */
32
33static struct tty_driver *ssl_driver;
34
35#define NR_PORTS 64
36
37void ssl_announce(char *dev_name, int dev)
38{
39 printk(KERN_INFO "Serial line %d assigned device '%s'\n", dev,
40 dev_name);
41}
42
43static struct chan_opts opts = {
44 .announce = ssl_announce,
45 .xterm_title = "Serial Line #%d",
46 .raw = 1,
47 .tramp_stack = 0,
48 .in_kernel = 1,
49};
50
51static int ssl_config(char *str);
52static int ssl_get_config(char *dev, char *str, int size, char **error_out);
53static int ssl_remove(char *str);
54
55static struct line_driver driver = {
56 .name = "UML serial line",
57 .device_name = "ttyS",
58 .devfs_name = "tts/",
59 .major = TTY_MAJOR,
60 .minor_start = 64,
61 .type = TTY_DRIVER_TYPE_SERIAL,
62 .subtype = 0,
63 .read_irq = SSL_IRQ,
64 .read_irq_name = "ssl",
65 .write_irq = SSL_WRITE_IRQ,
66 .write_irq_name = "ssl-write",
67 .symlink_from = "serial",
68 .symlink_to = "tts",
69 .mc = {
70 .name = "ssl",
71 .config = ssl_config,
72 .get_config = ssl_get_config,
73 .remove = ssl_remove,
74 },
75};
76
77/* The array is initialized by line_init, which is an initcall. The
78 * individual elements are protected by individual semaphores.
79 */
80static struct line serial_lines[NR_PORTS] =
81 { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) };
82
83static struct lines lines = LINES_INIT(NR_PORTS);
84
85static int ssl_config(char *str)
86{
87 return(line_config(serial_lines,
88 sizeof(serial_lines)/sizeof(serial_lines[0]), str));
89}
90
91static int ssl_get_config(char *dev, char *str, int size, char **error_out)
92{
93 return(line_get_config(dev, serial_lines,
94 sizeof(serial_lines)/sizeof(serial_lines[0]),
95 str, size, error_out));
96}
97
98static int ssl_remove(char *str)
99{
100 return(line_remove(serial_lines,
101 sizeof(serial_lines)/sizeof(serial_lines[0]), str));
102}
103
104int ssl_open(struct tty_struct *tty, struct file *filp)
105{
106 return line_open(serial_lines, tty, &opts);
107}
108
109#if 0
110static int ssl_chars_in_buffer(struct tty_struct *tty)
111{
112 return(0);
113}
114
115static void ssl_flush_buffer(struct tty_struct *tty)
116{
117 return;
118}
119
120static void ssl_throttle(struct tty_struct * tty)
121{
122 printk(KERN_ERR "Someone should implement ssl_throttle\n");
123}
124
125static void ssl_unthrottle(struct tty_struct * tty)
126{
127 printk(KERN_ERR "Someone should implement ssl_unthrottle\n");
128}
129
130static void ssl_stop(struct tty_struct *tty)
131{
132 printk(KERN_ERR "Someone should implement ssl_stop\n");
133}
134
135static void ssl_start(struct tty_struct *tty)
136{
137 printk(KERN_ERR "Someone should implement ssl_start\n");
138}
139
140void ssl_hangup(struct tty_struct *tty)
141{
142}
143#endif
144
145static struct tty_operations ssl_ops = {
146 .open = ssl_open,
147 .close = line_close,
148 .write = line_write,
149 .put_char = line_put_char,
150 .write_room = line_write_room,
151 .chars_in_buffer = line_chars_in_buffer,
152 .set_termios = line_set_termios,
153 .ioctl = line_ioctl,
154#if 0
155 .flush_chars = ssl_flush_chars,
156 .flush_buffer = ssl_flush_buffer,
157 .throttle = ssl_throttle,
158 .unthrottle = ssl_unthrottle,
159 .stop = ssl_stop,
160 .start = ssl_start,
161 .hangup = ssl_hangup,
162#endif
163};
164
165/* Changed by ssl_init and referenced by ssl_exit, which are both serialized
166 * by being an initcall and exitcall, respectively.
167 */
168static int ssl_init_done = 0;
169
170static void ssl_console_write(struct console *c, const char *string,
171 unsigned len)
172{
173 struct line *line = &serial_lines[c->index];
174
175 down(&line->sem);
176 console_write_chan(&line->chan_list, string, len);
177 up(&line->sem);
178}
179
180static struct tty_driver *ssl_console_device(struct console *c, int *index)
181{
182 *index = c->index;
183 return ssl_driver;
184}
185
186static int ssl_console_setup(struct console *co, char *options)
187{
188 struct line *line = &serial_lines[co->index];
189
190 return console_open_chan(line,co,&opts);
191}
192
193static struct console ssl_cons = {
194 .name = "ttyS",
195 .write = ssl_console_write,
196 .device = ssl_console_device,
197 .setup = ssl_console_setup,
198 .flags = CON_PRINTBUFFER,
199 .index = -1,
200};
201
202int ssl_init(void)
203{
204 char *new_title;
205
206 printk(KERN_INFO "Initializing software serial port version %d\n",
207 ssl_version);
208 ssl_driver = line_register_devfs(&lines, &driver, &ssl_ops,
209 serial_lines, ARRAY_SIZE(serial_lines));
210
211 lines_init(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]));
212
213 new_title = add_xterm_umid(opts.xterm_title);
214 if (new_title != NULL)
215 opts.xterm_title = new_title;
216
217 ssl_init_done = 1;
218 register_console(&ssl_cons);
219 return(0);
220}
221late_initcall(ssl_init);
222
223static void ssl_exit(void)
224{
225 if (!ssl_init_done)
226 return;
227 close_lines(serial_lines,
228 sizeof(serial_lines)/sizeof(serial_lines[0]));
229}
230__uml_exitcall(ssl_exit);
231
232static int ssl_chan_setup(char *str)
233{
234 return(line_setup(serial_lines,
235 sizeof(serial_lines)/sizeof(serial_lines[0]),
236 str, 1));
237}
238
239__setup("ssl", ssl_chan_setup);
240__channel_help(ssl_chan_setup, "ssl");
241
242/*
243 * Overrides for Emacs so that we follow Linus's tabbing style.
244 * Emacs will notice this stuff at the end of the file and automatically
245 * adjust the settings for this buffer only. This must remain at the end
246 * of the file.
247 * ---------------------------------------------------------------------------
248 * Local variables:
249 * c-file-style: "linux"
250 * End:
251 */
diff --git a/arch/um/drivers/ssl.h b/arch/um/drivers/ssl.h
new file mode 100644
index 000000000000..98412aa66607
--- /dev/null
+++ b/arch/um/drivers/ssl.h
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SSL_H__
7#define __SSL_H__
8
9extern int ssl_read(int fd, int line);
10extern void ssl_receive_char(int line, char ch);
11
12#endif
13
14/*
15 * Overrides for Emacs so that we follow Linus's tabbing style.
16 * Emacs will notice this stuff at the end of the file and automatically
17 * adjust the settings for this buffer only. This must remain at the end
18 * of the file.
19 * ---------------------------------------------------------------------------
20 * Local variables:
21 * c-file-style: "linux"
22 * End:
23 */
diff --git a/arch/um/drivers/stderr_console.c b/arch/um/drivers/stderr_console.c
new file mode 100644
index 000000000000..98565b53d170
--- /dev/null
+++ b/arch/um/drivers/stderr_console.c
@@ -0,0 +1,45 @@
1#include <linux/init.h>
2#include <linux/console.h>
3
4#include "chan_user.h"
5
6/* ----------------------------------------------------------------------------- */
7/* trivial console driver -- simply dump everything to stderr */
8
9/*
10 * Don't register by default -- as this registeres very early in the
11 * boot process it becomes the default console. And as this isn't a
12 * real tty driver init isn't able to open /dev/console then.
13 *
14 * In most cases this isn't what you want ...
15 */
16static int use_stderr_console = 0;
17
18static void stderr_console_write(struct console *console, const char *string,
19 unsigned len)
20{
21 generic_write(2 /* stderr */, string, len, NULL);
22}
23
24static struct console stderr_console = {
25 .name "stderr",
26 .write stderr_console_write,
27 .flags CON_PRINTBUFFER,
28};
29
30static int __init stderr_console_init(void)
31{
32 if (use_stderr_console)
33 register_console(&stderr_console);
34 return 0;
35}
36console_initcall(stderr_console_init);
37
38static int stderr_setup(char *str)
39{
40 if (!str)
41 return 0;
42 use_stderr_console = simple_strtoul(str,&str,0);
43 return 1;
44}
45__setup("stderr=", stderr_setup);
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
new file mode 100644
index 000000000000..e604d7c87695
--- /dev/null
+++ b/arch/um/drivers/stdio_console.c
@@ -0,0 +1,205 @@
1/*
2 * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/posix_types.h"
8#include "linux/tty.h"
9#include "linux/tty_flip.h"
10#include "linux/types.h"
11#include "linux/major.h"
12#include "linux/kdev_t.h"
13#include "linux/console.h"
14#include "linux/string.h"
15#include "linux/sched.h"
16#include "linux/list.h"
17#include "linux/init.h"
18#include "linux/interrupt.h"
19#include "linux/slab.h"
20#include "linux/hardirq.h"
21#include "asm/current.h"
22#include "asm/irq.h"
23#include "stdio_console.h"
24#include "line.h"
25#include "chan_kern.h"
26#include "user_util.h"
27#include "kern_util.h"
28#include "irq_user.h"
29#include "mconsole_kern.h"
30#include "init.h"
31#include "2_5compat.h"
32
33#define MAX_TTYS (16)
34
35/* ----------------------------------------------------------------------------- */
36
37/* Referenced only by tty_driver below - presumably it's locked correctly
38 * by the tty driver.
39 */
40
41static struct tty_driver *console_driver;
42
43void stdio_announce(char *dev_name, int dev)
44{
45 printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
46 dev_name);
47}
48
49static struct chan_opts opts = {
50 .announce = stdio_announce,
51 .xterm_title = "Virtual Console #%d",
52 .raw = 1,
53 .tramp_stack = 0,
54 .in_kernel = 1,
55};
56
57static int con_config(char *str);
58static int con_get_config(char *dev, char *str, int size, char **error_out);
59static int con_remove(char *str);
60
61static struct line_driver driver = {
62 .name = "UML console",
63 .device_name = "tty",
64 .devfs_name = "vc/",
65 .major = TTY_MAJOR,
66 .minor_start = 0,
67 .type = TTY_DRIVER_TYPE_CONSOLE,
68 .subtype = SYSTEM_TYPE_CONSOLE,
69 .read_irq = CONSOLE_IRQ,
70 .read_irq_name = "console",
71 .write_irq = CONSOLE_WRITE_IRQ,
72 .write_irq_name = "console-write",
73 .symlink_from = "ttys",
74 .symlink_to = "vc",
75 .mc = {
76 .name = "con",
77 .config = con_config,
78 .get_config = con_get_config,
79 .remove = con_remove,
80 },
81};
82
83static struct lines console_lines = LINES_INIT(MAX_TTYS);
84
85/* The array is initialized by line_init, which is an initcall. The
86 * individual elements are protected by individual semaphores.
87 */
88struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
89 [ 1 ... MAX_TTYS - 1 ] =
90 LINE_INIT(CONFIG_CON_CHAN, &driver) };
91
92static int con_config(char *str)
93{
94 return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str));
95}
96
97static int con_get_config(char *dev, char *str, int size, char **error_out)
98{
99 return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str,
100 size, error_out));
101}
102
103static int con_remove(char *str)
104{
105 return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str));
106}
107
108static int con_open(struct tty_struct *tty, struct file *filp)
109{
110 return line_open(vts, tty, &opts);
111}
112
113static int con_init_done = 0;
114
115static struct tty_operations console_ops = {
116 .open = con_open,
117 .close = line_close,
118 .write = line_write,
119 .write_room = line_write_room,
120 .chars_in_buffer = line_chars_in_buffer,
121 .set_termios = line_set_termios,
122 .ioctl = line_ioctl,
123};
124
125static void uml_console_write(struct console *console, const char *string,
126 unsigned len)
127{
128 struct line *line = &vts[console->index];
129
130 down(&line->sem);
131 console_write_chan(&line->chan_list, string, len);
132 up(&line->sem);
133}
134
135static struct tty_driver *uml_console_device(struct console *c, int *index)
136{
137 *index = c->index;
138 return console_driver;
139}
140
141static int uml_console_setup(struct console *co, char *options)
142{
143 struct line *line = &vts[co->index];
144
145 return console_open_chan(line,co,&opts);
146}
147
148static struct console stdiocons = {
149 .name = "tty",
150 .write = uml_console_write,
151 .device = uml_console_device,
152 .setup = uml_console_setup,
153 .flags = CON_PRINTBUFFER,
154 .index = -1,
155 .data = &vts,
156};
157
158int stdio_init(void)
159{
160 char *new_title;
161
162 console_driver = line_register_devfs(&console_lines, &driver,
163 &console_ops, vts,
164 ARRAY_SIZE(vts));
165 if (NULL == console_driver)
166 return -1;
167 printk(KERN_INFO "Initialized stdio console driver\n");
168
169 lines_init(vts, sizeof(vts)/sizeof(vts[0]));
170
171 new_title = add_xterm_umid(opts.xterm_title);
172 if(new_title != NULL)
173 opts.xterm_title = new_title;
174
175 con_init_done = 1;
176 register_console(&stdiocons);
177 return(0);
178}
179late_initcall(stdio_init);
180
181static void console_exit(void)
182{
183 if (!con_init_done)
184 return;
185 close_lines(vts, sizeof(vts)/sizeof(vts[0]));
186}
187__uml_exitcall(console_exit);
188
189static int console_chan_setup(char *str)
190{
191 return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1));
192}
193__setup("con", console_chan_setup);
194__channel_help(console_chan_setup, "con");
195
196/*
197 * Overrides for Emacs so that we follow Linus's tabbing style.
198 * Emacs will notice this stuff at the end of the file and automatically
199 * adjust the settings for this buffer only. This must remain at the end
200 * of the file.
201 * ---------------------------------------------------------------------------
202 * Local variables:
203 * c-file-style: "linux"
204 * End:
205 */
diff --git a/arch/um/drivers/stdio_console.h b/arch/um/drivers/stdio_console.h
new file mode 100644
index 000000000000..505a3d5bea5e
--- /dev/null
+++ b/arch/um/drivers/stdio_console.h
@@ -0,0 +1,21 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __STDIO_CONSOLE_H
7#define __STDIO_CONSOLE_H
8
9extern void save_console_flags(void);
10#endif
11
12/*
13 * Overrides for Emacs so that we follow Linus's tabbing style.
14 * Emacs will notice this stuff at the end of the file and automatically
15 * adjust the settings for this buffer only. This must remain at the end
16 * of the file.
17 * ---------------------------------------------------------------------------
18 * Local variables:
19 * c-file-style: "linux"
20 * End:
21 */
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
new file mode 100644
index 000000000000..6fbb670ee274
--- /dev/null
+++ b/arch/um/drivers/tty.c
@@ -0,0 +1,92 @@
1/*
2 * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <termios.h>
8#include <errno.h>
9#include <unistd.h>
10#include "chan_user.h"
11#include "user_util.h"
12#include "user.h"
13#include "os.h"
14
15struct tty_chan {
16 char *dev;
17 int raw;
18 struct termios tt;
19};
20
21static void *tty_chan_init(char *str, int device, struct chan_opts *opts)
22{
23 struct tty_chan *data;
24
25 if(*str != ':'){
26 printk("tty_init : channel type 'tty' must specify "
27 "a device\n");
28 return(NULL);
29 }
30 str++;
31
32 data = um_kmalloc(sizeof(*data));
33 if(data == NULL)
34 return(NULL);
35 *data = ((struct tty_chan) { .dev = str,
36 .raw = opts->raw });
37
38 return(data);
39}
40
41static int tty_open(int input, int output, int primary, void *d,
42 char **dev_out)
43{
44 struct tty_chan *data = d;
45 int fd, err;
46
47 fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0);
48 if(fd < 0) return(fd);
49 if(data->raw){
50 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
51 if(err)
52 return(err);
53
54 err = raw(fd);
55 if(err)
56 return(err);
57 }
58
59 *dev_out = data->dev;
60 return(fd);
61}
62
63static int tty_console_write(int fd, const char *buf, int n, void *d)
64{
65 struct tty_chan *data = d;
66
67 return(generic_console_write(fd, buf, n, &data->tt));
68}
69
70struct chan_ops tty_ops = {
71 .type = "tty",
72 .init = tty_chan_init,
73 .open = tty_open,
74 .close = generic_close,
75 .read = generic_read,
76 .write = generic_write,
77 .console_write = tty_console_write,
78 .window_size = generic_window_size,
79 .free = generic_free,
80 .winch = 0,
81};
82
83/*
84 * Overrides for Emacs so that we follow Linus's tabbing style.
85 * Emacs will notice this stuff at the end of the file and automatically
86 * adjust the settings for this buffer only. This must remain at the end
87 * of the file.
88 * ---------------------------------------------------------------------------
89 * Local variables:
90 * c-file-style: "linux"
91 * End:
92 */
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
new file mode 100644
index 000000000000..4d8b165bfa48
--- /dev/null
+++ b/arch/um/drivers/ubd_kern.c
@@ -0,0 +1,1669 @@
1/*
2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6/* 2001-09-28...2002-04-17
7 * Partition stuff by James_McMechan@hotmail.com
8 * old style ubd by setting UBD_SHIFT to 0
9 * 2002-09-27...2002-10-18 massive tinkering for 2.5
10 * partitions have changed in 2.5
11 * 2003-01-29 more tinkering for 2.5.59-1
12 * This should now address the sysfs problems and has
13 * the symlink for devfs to allow for booting with
14 * the common /dev/ubd/discX/... names rather than
15 * only /dev/ubdN/discN this version also has lots of
16 * clean ups preparing for ubd-many.
17 * James McMechan
18 */
19
20#define MAJOR_NR UBD_MAJOR
21#define UBD_SHIFT 4
22
23#include "linux/config.h"
24#include "linux/module.h"
25#include "linux/blkdev.h"
26#include "linux/hdreg.h"
27#include "linux/init.h"
28#include "linux/devfs_fs_kernel.h"
29#include "linux/cdrom.h"
30#include "linux/proc_fs.h"
31#include "linux/ctype.h"
32#include "linux/capability.h"
33#include "linux/mm.h"
34#include "linux/vmalloc.h"
35#include "linux/blkpg.h"
36#include "linux/genhd.h"
37#include "linux/spinlock.h"
38#include "asm/segment.h"
39#include "asm/uaccess.h"
40#include "asm/irq.h"
41#include "asm/types.h"
42#include "asm/tlbflush.h"
43#include "user_util.h"
44#include "mem_user.h"
45#include "kern_util.h"
46#include "kern.h"
47#include "mconsole_kern.h"
48#include "init.h"
49#include "irq_user.h"
50#include "irq_kern.h"
51#include "ubd_user.h"
52#include "2_5compat.h"
53#include "os.h"
54#include "mem.h"
55#include "mem_kern.h"
56#include "cow.h"
57
58enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP };
59
60struct io_thread_req {
61 enum ubd_req op;
62 int fds[2];
63 unsigned long offsets[2];
64 unsigned long long offset;
65 unsigned long length;
66 char *buffer;
67 int sectorsize;
68 unsigned long sector_mask;
69 unsigned long long cow_offset;
70 unsigned long bitmap_words[2];
71 int map_fd;
72 unsigned long long map_offset;
73 int error;
74};
75
76extern int open_ubd_file(char *file, struct openflags *openflags,
77 char **backing_file_out, int *bitmap_offset_out,
78 unsigned long *bitmap_len_out, int *data_offset_out,
79 int *create_cow_out);
80extern int create_cow_file(char *cow_file, char *backing_file,
81 struct openflags flags, int sectorsize,
82 int alignment, int *bitmap_offset_out,
83 unsigned long *bitmap_len_out,
84 int *data_offset_out);
85extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
86extern void do_io(struct io_thread_req *req);
87
88static inline int ubd_test_bit(__u64 bit, unsigned char *data)
89{
90 __u64 n;
91 int bits, off;
92
93 bits = sizeof(data[0]) * 8;
94 n = bit / bits;
95 off = bit % bits;
96 return((data[n] & (1 << off)) != 0);
97}
98
99static inline void ubd_set_bit(__u64 bit, unsigned char *data)
100{
101 __u64 n;
102 int bits, off;
103
104 bits = sizeof(data[0]) * 8;
105 n = bit / bits;
106 off = bit % bits;
107 data[n] |= (1 << off);
108}
109/*End stuff from ubd_user.h*/
110
111#define DRIVER_NAME "uml-blkdev"
112
113static DEFINE_SPINLOCK(ubd_io_lock);
114static DEFINE_SPINLOCK(ubd_lock);
115
116static void (*do_ubd)(void);
117
118static int ubd_open(struct inode * inode, struct file * filp);
119static int ubd_release(struct inode * inode, struct file * file);
120static int ubd_ioctl(struct inode * inode, struct file * file,
121 unsigned int cmd, unsigned long arg);
122
123#define MAX_DEV (8)
124
125/* Changed in early boot */
126static int ubd_do_mmap = 0;
127#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE
128
129static struct block_device_operations ubd_blops = {
130 .owner = THIS_MODULE,
131 .open = ubd_open,
132 .release = ubd_release,
133 .ioctl = ubd_ioctl,
134};
135
136/* Protected by the queue_lock */
137static request_queue_t *ubd_queue;
138
139/* Protected by ubd_lock */
140static int fake_major = MAJOR_NR;
141
142static struct gendisk *ubd_gendisk[MAX_DEV];
143static struct gendisk *fake_gendisk[MAX_DEV];
144
145#ifdef CONFIG_BLK_DEV_UBD_SYNC
146#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \
147 .cl = 1 })
148#else
149#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \
150 .cl = 1 })
151#endif
152
153/* Not protected - changed only in ubd_setup_common and then only to
154 * to enable O_SYNC.
155 */
156static struct openflags global_openflags = OPEN_FLAGS;
157
158struct cow {
159 char *file;
160 int fd;
161 unsigned long *bitmap;
162 unsigned long bitmap_len;
163 int bitmap_offset;
164 int data_offset;
165};
166
167struct ubd {
168 char *file;
169 int count;
170 int fd;
171 __u64 size;
172 struct openflags boot_openflags;
173 struct openflags openflags;
174 int no_cow;
175 struct cow cow;
176 struct platform_device pdev;
177
178 int map_writes;
179 int map_reads;
180 int nomap_writes;
181 int nomap_reads;
182 int write_maps;
183};
184
185#define DEFAULT_COW { \
186 .file = NULL, \
187 .fd = -1, \
188 .bitmap = NULL, \
189 .bitmap_offset = 0, \
190 .data_offset = 0, \
191}
192
193#define DEFAULT_UBD { \
194 .file = NULL, \
195 .count = 0, \
196 .fd = -1, \
197 .size = -1, \
198 .boot_openflags = OPEN_FLAGS, \
199 .openflags = OPEN_FLAGS, \
200 .no_cow = 0, \
201 .cow = DEFAULT_COW, \
202 .map_writes = 0, \
203 .map_reads = 0, \
204 .nomap_writes = 0, \
205 .nomap_reads = 0, \
206 .write_maps = 0, \
207}
208
209struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
210
211static int ubd0_init(void)
212{
213 struct ubd *dev = &ubd_dev[0];
214
215 if(dev->file == NULL)
216 dev->file = "root_fs";
217 return(0);
218}
219
220__initcall(ubd0_init);
221
222/* Only changed by fake_ide_setup which is a setup */
223static int fake_ide = 0;
224static struct proc_dir_entry *proc_ide_root = NULL;
225static struct proc_dir_entry *proc_ide = NULL;
226
227static void make_proc_ide(void)
228{
229 proc_ide_root = proc_mkdir("ide", NULL);
230 proc_ide = proc_mkdir("ide0", proc_ide_root);
231}
232
233static int proc_ide_read_media(char *page, char **start, off_t off, int count,
234 int *eof, void *data)
235{
236 int len;
237
238 strcpy(page, "disk\n");
239 len = strlen("disk\n");
240 len -= off;
241 if (len < count){
242 *eof = 1;
243 if (len <= 0) return 0;
244 }
245 else len = count;
246 *start = page + off;
247 return len;
248}
249
250static void make_ide_entries(char *dev_name)
251{
252 struct proc_dir_entry *dir, *ent;
253 char name[64];
254
255 if(proc_ide_root == NULL) make_proc_ide();
256
257 dir = proc_mkdir(dev_name, proc_ide);
258 if(!dir) return;
259
260 ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
261 if(!ent) return;
262 ent->nlink = 1;
263 ent->data = NULL;
264 ent->read_proc = proc_ide_read_media;
265 ent->write_proc = NULL;
266 sprintf(name,"ide0/%s", dev_name);
267 proc_symlink(dev_name, proc_ide_root, name);
268}
269
270static int fake_ide_setup(char *str)
271{
272 fake_ide = 1;
273 return(1);
274}
275
276__setup("fake_ide", fake_ide_setup);
277
278__uml_help(fake_ide_setup,
279"fake_ide\n"
280" Create ide0 entries that map onto ubd devices.\n\n"
281);
282
283static int parse_unit(char **ptr)
284{
285 char *str = *ptr, *end;
286 int n = -1;
287
288 if(isdigit(*str)) {
289 n = simple_strtoul(str, &end, 0);
290 if(end == str)
291 return(-1);
292 *ptr = end;
293 }
294 else if (('a' <= *str) && (*str <= 'h')) {
295 n = *str - 'a';
296 str++;
297 *ptr = str;
298 }
299 return(n);
300}
301
302static int ubd_setup_common(char *str, int *index_out)
303{
304 struct ubd *dev;
305 struct openflags flags = global_openflags;
306 char *backing_file;
307 int n, err, i;
308
309 if(index_out) *index_out = -1;
310 n = *str;
311 if(n == '='){
312 char *end;
313 int major;
314
315 str++;
316 if(!strcmp(str, "mmap")){
317 CHOOSE_MODE(printk("mmap not supported by the ubd "
318 "driver in tt mode\n"),
319 ubd_do_mmap = 1);
320 return(0);
321 }
322
323 if(!strcmp(str, "sync")){
324 global_openflags = of_sync(global_openflags);
325 return(0);
326 }
327 major = simple_strtoul(str, &end, 0);
328 if((*end != '\0') || (end == str)){
329 printk(KERN_ERR
330 "ubd_setup : didn't parse major number\n");
331 return(1);
332 }
333
334 err = 1;
335 spin_lock(&ubd_lock);
336 if(fake_major != MAJOR_NR){
337 printk(KERN_ERR "Can't assign a fake major twice\n");
338 goto out1;
339 }
340
341 fake_major = major;
342
343 printk(KERN_INFO "Setting extra ubd major number to %d\n",
344 major);
345 err = 0;
346 out1:
347 spin_unlock(&ubd_lock);
348 return(err);
349 }
350
351 n = parse_unit(&str);
352 if(n < 0){
353 printk(KERN_ERR "ubd_setup : couldn't parse unit number "
354 "'%s'\n", str);
355 return(1);
356 }
357 if(n >= MAX_DEV){
358 printk(KERN_ERR "ubd_setup : index %d out of range "
359 "(%d devices, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1);
360 return(1);
361 }
362
363 err = 1;
364 spin_lock(&ubd_lock);
365
366 dev = &ubd_dev[n];
367 if(dev->file != NULL){
368 printk(KERN_ERR "ubd_setup : device already configured\n");
369 goto out;
370 }
371
372 if (index_out)
373 *index_out = n;
374
375 for (i = 0; i < 4; i++) {
376 switch (*str) {
377 case 'r':
378 flags.w = 0;
379 break;
380 case 's':
381 flags.s = 1;
382 break;
383 case 'd':
384 dev->no_cow = 1;
385 break;
386 case '=':
387 str++;
388 goto break_loop;
389 default:
390 printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r,s or d)\n");
391 goto out;
392 }
393 str++;
394 }
395
396 if (*str == '=')
397 printk(KERN_ERR "ubd_setup : Too many flags specified\n");
398 else
399 printk(KERN_ERR "ubd_setup : Expected '='\n");
400 goto out;
401
402break_loop:
403 err = 0;
404 backing_file = strchr(str, ',');
405
406 if (!backing_file) {
407 backing_file = strchr(str, ':');
408 }
409
410 if(backing_file){
411 if(dev->no_cow)
412 printk(KERN_ERR "Can't specify both 'd' and a "
413 "cow file\n");
414 else {
415 *backing_file = '\0';
416 backing_file++;
417 }
418 }
419 dev->file = str;
420 dev->cow.file = backing_file;
421 dev->boot_openflags = flags;
422out:
423 spin_unlock(&ubd_lock);
424 return(err);
425}
426
427static int ubd_setup(char *str)
428{
429 ubd_setup_common(str, NULL);
430 return(1);
431}
432
433__setup("ubd", ubd_setup);
434__uml_help(ubd_setup,
435"ubd<n><flags>=<filename>[(:|,)<filename2>]\n"
436" This is used to associate a device with a file in the underlying\n"
437" filesystem. When specifying two filenames, the first one is the\n"
438" COW name and the second is the backing file name. As separator you can\n"
439" use either a ':' or a ',': the first one allows writing things like;\n"
440" ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n"
441" while with a ',' the shell would not expand the 2nd '~'.\n"
442" When using only one filename, UML will detect whether to thread it like\n"
443" a COW file or a backing file. To override this detection, add the 'd'\n"
444" flag:\n"
445" ubd0d=BackingFile\n"
446" Usually, there is a filesystem in the file, but \n"
447" that's not required. Swap devices containing swap files can be\n"
448" specified like this. Also, a file which doesn't contain a\n"
449" filesystem can have its contents read in the virtual \n"
450" machine by running 'dd' on the device. <n> must be in the range\n"
451" 0 to 7. Appending an 'r' to the number will cause that device\n"
452" to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
453" an 's' will cause data to be written to disk on the host immediately.\n\n"
454);
455
456static int udb_setup(char *str)
457{
458 printk("udb%s specified on command line is almost certainly a ubd -> "
459 "udb TYPO\n", str);
460 return(1);
461}
462
463__setup("udb", udb_setup);
464__uml_help(udb_setup,
465"udb\n"
466" This option is here solely to catch ubd -> udb typos, which can be\n\n"
467" to impossible to catch visually unless you specifically look for\n\n"
468" them. The only result of any option starting with 'udb' is an error\n\n"
469" in the boot output.\n\n"
470);
471
472static int fakehd_set = 0;
473static int fakehd(char *str)
474{
475 printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
476 fakehd_set = 1;
477 return 1;
478}
479
480__setup("fakehd", fakehd);
481__uml_help(fakehd,
482"fakehd\n"
483" Change the ubd device name to \"hd\".\n\n"
484);
485
486static void do_ubd_request(request_queue_t * q);
487
488/* Only changed by ubd_init, which is an initcall. */
489int thread_fd = -1;
490
491/* Changed by ubd_handler, which is serialized because interrupts only
492 * happen on CPU 0.
493 */
494int intr_count = 0;
495
496/* call ubd_finish if you need to serialize */
497static void __ubd_finish(struct request *req, int error)
498{
499 int nsect;
500
501 if(error){
502 end_request(req, 0);
503 return;
504 }
505 nsect = req->current_nr_sectors;
506 req->sector += nsect;
507 req->buffer += nsect << 9;
508 req->errors = 0;
509 req->nr_sectors -= nsect;
510 req->current_nr_sectors = 0;
511 end_request(req, 1);
512}
513
514static inline void ubd_finish(struct request *req, int error)
515{
516 spin_lock(&ubd_io_lock);
517 __ubd_finish(req, error);
518 spin_unlock(&ubd_io_lock);
519}
520
521/* Called without ubd_io_lock held */
522static void ubd_handler(void)
523{
524 struct io_thread_req req;
525 struct request *rq = elv_next_request(ubd_queue);
526 int n, err;
527
528 do_ubd = NULL;
529 intr_count++;
530 n = os_read_file(thread_fd, &req, sizeof(req));
531 if(n != sizeof(req)){
532 printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
533 "err = %d\n", os_getpid(), -n);
534 spin_lock(&ubd_io_lock);
535 end_request(rq, 0);
536 spin_unlock(&ubd_io_lock);
537 return;
538 }
539
540 if((req.op != UBD_MMAP) &&
541 ((req.offset != ((__u64) (rq->sector)) << 9) ||
542 (req.length != (rq->current_nr_sectors) << 9)))
543 panic("I/O op mismatch");
544
545 if(req.map_fd != -1){
546 err = physmem_subst_mapping(req.buffer, req.map_fd,
547 req.map_offset, 1);
548 if(err)
549 printk("ubd_handler - physmem_subst_mapping failed, "
550 "err = %d\n", -err);
551 }
552
553 ubd_finish(rq, req.error);
554 reactivate_fd(thread_fd, UBD_IRQ);
555 do_ubd_request(ubd_queue);
556}
557
558static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
559{
560 ubd_handler();
561 return(IRQ_HANDLED);
562}
563
564/* Only changed by ubd_init, which is an initcall. */
565static int io_pid = -1;
566
567void kill_io_thread(void)
568{
569 if(io_pid != -1)
570 os_kill_process(io_pid, 1);
571}
572
573__uml_exitcall(kill_io_thread);
574
575static int ubd_file_size(struct ubd *dev, __u64 *size_out)
576{
577 char *file;
578
579 file = dev->cow.file ? dev->cow.file : dev->file;
580 return(os_file_size(file, size_out));
581}
582
583static void ubd_close(struct ubd *dev)
584{
585 if(ubd_do_mmap)
586 physmem_forget_descriptor(dev->fd);
587 os_close_file(dev->fd);
588 if(dev->cow.file == NULL)
589 return;
590
591 if(ubd_do_mmap)
592 physmem_forget_descriptor(dev->cow.fd);
593 os_close_file(dev->cow.fd);
594 vfree(dev->cow.bitmap);
595 dev->cow.bitmap = NULL;
596}
597
598static int ubd_open_dev(struct ubd *dev)
599{
600 struct openflags flags;
601 char **back_ptr;
602 int err, create_cow, *create_ptr;
603
604 dev->openflags = dev->boot_openflags;
605 create_cow = 0;
606 create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
607 back_ptr = dev->no_cow ? NULL : &dev->cow.file;
608 dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr,
609 &dev->cow.bitmap_offset, &dev->cow.bitmap_len,
610 &dev->cow.data_offset, create_ptr);
611
612 if((dev->fd == -ENOENT) && create_cow){
613 dev->fd = create_cow_file(dev->file, dev->cow.file,
614 dev->openflags, 1 << 9, PAGE_SIZE,
615 &dev->cow.bitmap_offset,
616 &dev->cow.bitmap_len,
617 &dev->cow.data_offset);
618 if(dev->fd >= 0){
619 printk(KERN_INFO "Creating \"%s\" as COW file for "
620 "\"%s\"\n", dev->file, dev->cow.file);
621 }
622 }
623
624 if(dev->fd < 0){
625 printk("Failed to open '%s', errno = %d\n", dev->file,
626 -dev->fd);
627 return(dev->fd);
628 }
629
630 if(dev->cow.file != NULL){
631 err = -ENOMEM;
632 dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
633 if(dev->cow.bitmap == NULL){
634 printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
635 goto error;
636 }
637 flush_tlb_kernel_vm();
638
639 err = read_cow_bitmap(dev->fd, dev->cow.bitmap,
640 dev->cow.bitmap_offset,
641 dev->cow.bitmap_len);
642 if(err < 0)
643 goto error;
644
645 flags = dev->openflags;
646 flags.w = 0;
647 err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL,
648 NULL, NULL);
649 if(err < 0) goto error;
650 dev->cow.fd = err;
651 }
652 return(0);
653 error:
654 os_close_file(dev->fd);
655 return(err);
656}
657
658static int ubd_new_disk(int major, u64 size, int unit,
659 struct gendisk **disk_out)
660
661{
662 struct gendisk *disk;
663 char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")];
664 int err;
665
666 disk = alloc_disk(1 << UBD_SHIFT);
667 if(disk == NULL)
668 return(-ENOMEM);
669
670 disk->major = major;
671 disk->first_minor = unit << UBD_SHIFT;
672 disk->fops = &ubd_blops;
673 set_capacity(disk, size / 512);
674 if(major == MAJOR_NR){
675 sprintf(disk->disk_name, "ubd%c", 'a' + unit);
676 sprintf(disk->devfs_name, "ubd/disc%d", unit);
677 sprintf(from, "ubd/%d", unit);
678 sprintf(to, "disc%d/disc", unit);
679 err = devfs_mk_symlink(from, to);
680 if(err)
681 printk("ubd_new_disk failed to make link from %s to "
682 "%s, error = %d\n", from, to, err);
683 }
684 else {
685 sprintf(disk->disk_name, "ubd_fake%d", unit);
686 sprintf(disk->devfs_name, "ubd_fake/disc%d", unit);
687 }
688
689 /* sysfs register (not for ide fake devices) */
690 if (major == MAJOR_NR) {
691 ubd_dev[unit].pdev.id = unit;
692 ubd_dev[unit].pdev.name = DRIVER_NAME;
693 platform_device_register(&ubd_dev[unit].pdev);
694 disk->driverfs_dev = &ubd_dev[unit].pdev.dev;
695 }
696
697 disk->private_data = &ubd_dev[unit];
698 disk->queue = ubd_queue;
699 add_disk(disk);
700
701 *disk_out = disk;
702 return 0;
703}
704
705#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))
706
707static int ubd_add(int n)
708{
709 struct ubd *dev = &ubd_dev[n];
710 int err;
711
712 if(dev->file == NULL)
713 return(-ENODEV);
714
715 if (ubd_open_dev(dev))
716 return(-ENODEV);
717
718 err = ubd_file_size(dev, &dev->size);
719 if(err < 0)
720 return(err);
721
722 dev->size = ROUND_BLOCK(dev->size);
723
724 err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
725 if(err)
726 return(err);
727
728 if(fake_major != MAJOR_NR)
729 ubd_new_disk(fake_major, dev->size, n,
730 &fake_gendisk[n]);
731
732 /* perhaps this should also be under the "if (fake_major)" above */
733 /* using the fake_disk->disk_name and also the fakehd_set name */
734 if (fake_ide)
735 make_ide_entries(ubd_gendisk[n]->disk_name);
736
737 ubd_close(dev);
738 return 0;
739}
740
741static int ubd_config(char *str)
742{
743 int n, err;
744
745 str = uml_strdup(str);
746 if(str == NULL){
747 printk(KERN_ERR "ubd_config failed to strdup string\n");
748 return(1);
749 }
750 err = ubd_setup_common(str, &n);
751 if(err){
752 kfree(str);
753 return(-1);
754 }
755 if(n == -1) return(0);
756
757 spin_lock(&ubd_lock);
758 err = ubd_add(n);
759 if(err)
760 ubd_dev[n].file = NULL;
761 spin_unlock(&ubd_lock);
762
763 return(err);
764}
765
766static int ubd_get_config(char *name, char *str, int size, char **error_out)
767{
768 struct ubd *dev;
769 int n, len = 0;
770
771 n = parse_unit(&name);
772 if((n >= MAX_DEV) || (n < 0)){
773 *error_out = "ubd_get_config : device number out of range";
774 return(-1);
775 }
776
777 dev = &ubd_dev[n];
778 spin_lock(&ubd_lock);
779
780 if(dev->file == NULL){
781 CONFIG_CHUNK(str, size, len, "", 1);
782 goto out;
783 }
784
785 CONFIG_CHUNK(str, size, len, dev->file, 0);
786
787 if(dev->cow.file != NULL){
788 CONFIG_CHUNK(str, size, len, ",", 0);
789 CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
790 }
791 else CONFIG_CHUNK(str, size, len, "", 1);
792
793 out:
794 spin_unlock(&ubd_lock);
795 return(len);
796}
797
798static int ubd_remove(char *str)
799{
800 struct ubd *dev;
801 int n, err = -ENODEV;
802
803 n = parse_unit(&str);
804
805 if((n < 0) || (n >= MAX_DEV))
806 return(err);
807
808 dev = &ubd_dev[n];
809 if(dev->count > 0)
810 return(-EBUSY); /* you cannot remove a open disk */
811
812 err = 0;
813 spin_lock(&ubd_lock);
814
815 if(ubd_gendisk[n] == NULL)
816 goto out;
817
818 del_gendisk(ubd_gendisk[n]);
819 put_disk(ubd_gendisk[n]);
820 ubd_gendisk[n] = NULL;
821
822 if(fake_gendisk[n] != NULL){
823 del_gendisk(fake_gendisk[n]);
824 put_disk(fake_gendisk[n]);
825 fake_gendisk[n] = NULL;
826 }
827
828 platform_device_unregister(&dev->pdev);
829 *dev = ((struct ubd) DEFAULT_UBD);
830 err = 0;
831 out:
832 spin_unlock(&ubd_lock);
833 return(err);
834}
835
836static struct mc_device ubd_mc = {
837 .name = "ubd",
838 .config = ubd_config,
839 .get_config = ubd_get_config,
840 .remove = ubd_remove,
841};
842
843static int ubd_mc_init(void)
844{
845 mconsole_register_dev(&ubd_mc);
846 return 0;
847}
848
849__initcall(ubd_mc_init);
850
851static struct device_driver ubd_driver = {
852 .name = DRIVER_NAME,
853 .bus = &platform_bus_type,
854};
855
856int ubd_init(void)
857{
858 int i;
859
860 devfs_mk_dir("ubd");
861 if (register_blkdev(MAJOR_NR, "ubd"))
862 return -1;
863
864 ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock);
865 if (!ubd_queue) {
866 unregister_blkdev(MAJOR_NR, "ubd");
867 return -1;
868 }
869
870 if (fake_major != MAJOR_NR) {
871 char name[sizeof("ubd_nnn\0")];
872
873 snprintf(name, sizeof(name), "ubd_%d", fake_major);
874 devfs_mk_dir(name);
875 if (register_blkdev(fake_major, "ubd"))
876 return -1;
877 }
878 driver_register(&ubd_driver);
879 for (i = 0; i < MAX_DEV; i++)
880 ubd_add(i);
881 return 0;
882}
883
884late_initcall(ubd_init);
885
886int ubd_driver_init(void){
887 unsigned long stack;
888 int err;
889
890 /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
891 if(global_openflags.s){
892 printk(KERN_INFO "ubd: Synchronous mode\n");
893 /* Letting ubd=sync be like using ubd#s= instead of ubd#= is
894 * enough. So use anyway the io thread. */
895 }
896 stack = alloc_stack(0, 0);
897 io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
898 &thread_fd);
899 if(io_pid < 0){
900 printk(KERN_ERR
901 "ubd : Failed to start I/O thread (errno = %d) - "
902 "falling back to synchronous I/O\n", -io_pid);
903 io_pid = -1;
904 return(0);
905 }
906 err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
907 SA_INTERRUPT, "ubd", ubd_dev);
908 if(err != 0)
909 printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
910 return(err);
911}
912
913device_initcall(ubd_driver_init);
914
915static int ubd_open(struct inode *inode, struct file *filp)
916{
917 struct gendisk *disk = inode->i_bdev->bd_disk;
918 struct ubd *dev = disk->private_data;
919 int err = 0;
920
921 if(dev->count == 0){
922 err = ubd_open_dev(dev);
923 if(err){
924 printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
925 disk->disk_name, dev->file, -err);
926 goto out;
927 }
928 }
929 dev->count++;
930 if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
931 if(--dev->count == 0) ubd_close(dev);
932 err = -EROFS;
933 }
934 out:
935 return(err);
936}
937
938static int ubd_release(struct inode * inode, struct file * file)
939{
940 struct gendisk *disk = inode->i_bdev->bd_disk;
941 struct ubd *dev = disk->private_data;
942
943 if(--dev->count == 0)
944 ubd_close(dev);
945 return(0);
946}
947
948static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
949 __u64 *cow_offset, unsigned long *bitmap,
950 __u64 bitmap_offset, unsigned long *bitmap_words,
951 __u64 bitmap_len)
952{
953 __u64 sector = io_offset >> 9;
954 int i, update_bitmap = 0;
955
956 for(i = 0; i < length >> 9; i++){
957 if(cow_mask != NULL)
958 ubd_set_bit(i, (unsigned char *) cow_mask);
959 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
960 continue;
961
962 update_bitmap = 1;
963 ubd_set_bit(sector + i, (unsigned char *) bitmap);
964 }
965
966 if(!update_bitmap)
967 return;
968
969 *cow_offset = sector / (sizeof(unsigned long) * 8);
970
971 /* This takes care of the case where we're exactly at the end of the
972 * device, and *cow_offset + 1 is off the end. So, just back it up
973 * by one word. Thanks to Lynn Kerby for the fix and James McMechan
974 * for the original diagnosis.
975 */
976 if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
977 sizeof(unsigned long) - 1))
978 (*cow_offset)--;
979
980 bitmap_words[0] = bitmap[*cow_offset];
981 bitmap_words[1] = bitmap[*cow_offset + 1];
982
983 *cow_offset *= sizeof(unsigned long);
984 *cow_offset += bitmap_offset;
985}
986
987static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
988 __u64 bitmap_offset, __u64 bitmap_len)
989{
990 __u64 sector = req->offset >> 9;
991 int i;
992
993 if(req->length > (sizeof(req->sector_mask) * 8) << 9)
994 panic("Operation too long");
995
996 if(req->op == UBD_READ) {
997 for(i = 0; i < req->length >> 9; i++){
998 if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
999 ubd_set_bit(i, (unsigned char *)
1000 &req->sector_mask);
1001 }
1002 }
1003 else cowify_bitmap(req->offset, req->length, &req->sector_mask,
1004 &req->cow_offset, bitmap, bitmap_offset,
1005 req->bitmap_words, bitmap_len);
1006}
1007
1008static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset)
1009{
1010 __u64 sector;
1011 unsigned char *bitmap;
1012 int bit, i;
1013
1014 /* mmap must have been requested on the command line */
1015 if(!ubd_do_mmap)
1016 return(-1);
1017
1018 /* The buffer must be page aligned */
1019 if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0)
1020 return(-1);
1021
1022 /* The request must be a page long */
1023 if((req->current_nr_sectors << 9) != PAGE_SIZE)
1024 return(-1);
1025
1026 if(dev->cow.file == NULL)
1027 return(dev->fd);
1028
1029 sector = offset >> 9;
1030 bitmap = (unsigned char *) dev->cow.bitmap;
1031 bit = ubd_test_bit(sector, bitmap);
1032
1033 for(i = 1; i < req->current_nr_sectors; i++){
1034 if(ubd_test_bit(sector + i, bitmap) != bit)
1035 return(-1);
1036 }
1037
1038 if(bit || (rq_data_dir(req) == WRITE))
1039 offset += dev->cow.data_offset;
1040
1041 /* The data on disk must be page aligned */
1042 if((offset % UBD_MMAP_BLOCK_SIZE) != 0)
1043 return(-1);
1044
1045 return(bit ? dev->fd : dev->cow.fd);
1046}
1047
1048static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset,
1049 struct request *req,
1050 struct io_thread_req *io_req)
1051{
1052 int err;
1053
1054 if(rq_data_dir(req) == WRITE){
1055 /* Writes are almost no-ops since the new data is already in the
1056 * host page cache
1057 */
1058 dev->map_writes++;
1059 if(dev->cow.file != NULL)
1060 cowify_bitmap(io_req->offset, io_req->length,
1061 &io_req->sector_mask, &io_req->cow_offset,
1062 dev->cow.bitmap, dev->cow.bitmap_offset,
1063 io_req->bitmap_words,
1064 dev->cow.bitmap_len);
1065 }
1066 else {
1067 int w;
1068
1069 if((dev->cow.file != NULL) && (fd == dev->cow.fd))
1070 w = 0;
1071 else w = dev->openflags.w;
1072
1073 if((dev->cow.file != NULL) && (fd == dev->fd))
1074 offset += dev->cow.data_offset;
1075
1076 err = physmem_subst_mapping(req->buffer, fd, offset, w);
1077 if(err){
1078 printk("physmem_subst_mapping failed, err = %d\n",
1079 -err);
1080 return(1);
1081 }
1082 dev->map_reads++;
1083 }
1084 io_req->op = UBD_MMAP;
1085 io_req->buffer = req->buffer;
1086 return(0);
1087}
1088
1089/* Called with ubd_io_lock held */
1090static int prepare_request(struct request *req, struct io_thread_req *io_req)
1091{
1092 struct gendisk *disk = req->rq_disk;
1093 struct ubd *dev = disk->private_data;
1094 __u64 offset;
1095 int len, fd;
1096
1097 if(req->rq_status == RQ_INACTIVE) return(1);
1098
1099 if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
1100 printk("Write attempted on readonly ubd device %s\n",
1101 disk->disk_name);
1102 end_request(req, 0);
1103 return(1);
1104 }
1105
1106 offset = ((__u64) req->sector) << 9;
1107 len = req->current_nr_sectors << 9;
1108
1109 io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
1110 io_req->fds[1] = dev->fd;
1111 io_req->map_fd = -1;
1112 io_req->cow_offset = -1;
1113 io_req->offset = offset;
1114 io_req->length = len;
1115 io_req->error = 0;
1116 io_req->sector_mask = 0;
1117
1118 fd = mmap_fd(req, dev, io_req->offset);
1119 if(fd > 0){
1120 /* If mmapping is otherwise OK, but the first access to the
1121 * page is a write, then it's not mapped in yet. So we have
1122 * to write the data to disk first, then we can map the disk
1123 * page in and continue normally from there.
1124 */
1125 if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){
1126 io_req->map_fd = dev->fd;
1127 io_req->map_offset = io_req->offset +
1128 dev->cow.data_offset;
1129 dev->write_maps++;
1130 }
1131 else return(prepare_mmap_request(dev, fd, io_req->offset, req,
1132 io_req));
1133 }
1134
1135 if(rq_data_dir(req) == READ)
1136 dev->nomap_reads++;
1137 else dev->nomap_writes++;
1138
1139 io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
1140 io_req->offsets[0] = 0;
1141 io_req->offsets[1] = dev->cow.data_offset;
1142 io_req->buffer = req->buffer;
1143 io_req->sectorsize = 1 << 9;
1144
1145 if(dev->cow.file != NULL)
1146 cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
1147 dev->cow.bitmap_len);
1148
1149 return(0);
1150}
1151
1152/* Called with ubd_io_lock held */
1153static void do_ubd_request(request_queue_t *q)
1154{
1155 struct io_thread_req io_req;
1156 struct request *req;
1157 int err, n;
1158
1159 if(thread_fd == -1){
1160 while((req = elv_next_request(q)) != NULL){
1161 err = prepare_request(req, &io_req);
1162 if(!err){
1163 do_io(&io_req);
1164 __ubd_finish(req, io_req.error);
1165 }
1166 }
1167 }
1168 else {
1169 if(do_ubd || (req = elv_next_request(q)) == NULL)
1170 return;
1171 err = prepare_request(req, &io_req);
1172 if(!err){
1173 do_ubd = ubd_handler;
1174 n = os_write_file(thread_fd, (char *) &io_req,
1175 sizeof(io_req));
1176 if(n != sizeof(io_req))
1177 printk("write to io thread failed, "
1178 "errno = %d\n", -n);
1179 }
1180 }
1181}
1182
1183static int ubd_ioctl(struct inode * inode, struct file * file,
1184 unsigned int cmd, unsigned long arg)
1185{
1186 struct hd_geometry __user *loc = (struct hd_geometry __user *) arg;
1187 struct ubd *dev = inode->i_bdev->bd_disk->private_data;
1188 struct hd_driveid ubd_id = {
1189 .cyls = 0,
1190 .heads = 128,
1191 .sectors = 32,
1192 };
1193
1194 switch (cmd) {
1195 struct hd_geometry g;
1196 struct cdrom_volctrl volume;
1197 case HDIO_GETGEO:
1198 if(!loc) return(-EINVAL);
1199 g.heads = 128;
1200 g.sectors = 32;
1201 g.cylinders = dev->size / (128 * 32 * 512);
1202 g.start = get_start_sect(inode->i_bdev);
1203 return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);
1204
1205 case HDIO_GET_IDENTITY:
1206 ubd_id.cyls = dev->size / (128 * 32 * 512);
1207 if(copy_to_user((char __user *) arg, (char *) &ubd_id,
1208 sizeof(ubd_id)))
1209 return(-EFAULT);
1210 return(0);
1211
1212 case CDROMVOLREAD:
1213 if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
1214 return(-EFAULT);
1215 volume.channel0 = 255;
1216 volume.channel1 = 255;
1217 volume.channel2 = 255;
1218 volume.channel3 = 255;
1219 if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
1220 return(-EFAULT);
1221 return(0);
1222 }
1223 return(-EINVAL);
1224}
1225
1226static int ubd_check_remapped(int fd, unsigned long address, int is_write,
1227 __u64 offset)
1228{
1229 __u64 bitmap_offset;
1230 unsigned long new_bitmap[2];
1231 int i, err, n;
1232
1233 /* If it's not a write access, we can't do anything about it */
1234 if(!is_write)
1235 return(0);
1236
1237 /* We have a write */
1238 for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){
1239 struct ubd *dev = &ubd_dev[i];
1240
1241 if((dev->fd != fd) && (dev->cow.fd != fd))
1242 continue;
1243
1244 /* It's a write to a ubd device */
1245
1246 if(!dev->openflags.w){
1247 /* It's a write access on a read-only device - probably
1248 * shouldn't happen. If the kernel is trying to change
1249 * something with no intention of writing it back out,
1250 * then this message will clue us in that this needs
1251 * fixing
1252 */
1253 printk("Write access to mapped page from readonly ubd "
1254 "device %d\n", i);
1255 return(0);
1256 }
1257
1258 /* It's a write to a writeable ubd device - it must be COWed
1259 * because, otherwise, the page would have been mapped in
1260 * writeable
1261 */
1262
1263 if(!dev->cow.file)
1264 panic("Write fault on writeable non-COW ubd device %d",
1265 i);
1266
1267 /* It should also be an access to the backing file since the
1268 * COW pages should be mapped in read-write
1269 */
1270
1271 if(fd == dev->fd)
1272 panic("Write fault on a backing page of ubd "
1273 "device %d\n", i);
1274
1275 /* So, we do the write, copying the backing data to the COW
1276 * file...
1277 */
1278
1279 err = os_seek_file(dev->fd, offset + dev->cow.data_offset);
1280 if(err < 0)
1281 panic("Couldn't seek to %lld in COW file of ubd "
1282 "device %d, err = %d",
1283 offset + dev->cow.data_offset, i, -err);
1284
1285 n = os_write_file(dev->fd, (void *) address, PAGE_SIZE);
1286 if(n != PAGE_SIZE)
1287 panic("Couldn't copy data to COW file of ubd "
1288 "device %d, err = %d", i, -n);
1289
1290 /* ... updating the COW bitmap... */
1291
1292 cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset,
1293 dev->cow.bitmap, dev->cow.bitmap_offset,
1294 new_bitmap, dev->cow.bitmap_len);
1295
1296 err = os_seek_file(dev->fd, bitmap_offset);
1297 if(err < 0)
1298 panic("Couldn't seek to %lld in COW file of ubd "
1299 "device %d, err = %d", bitmap_offset, i, -err);
1300
1301 n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap));
1302 if(n != sizeof(new_bitmap))
1303 panic("Couldn't update bitmap of ubd device %d, "
1304 "err = %d", i, -n);
1305
1306 /* Maybe we can map the COW page in, and maybe we can't. If
1307 * it is a pre-V3 COW file, we can't, since the alignment will
1308 * be wrong. If it is a V3 or later COW file which has been
1309 * moved to a system with a larger page size, then maybe we
1310 * can't, depending on the exact location of the page.
1311 */
1312
1313 offset += dev->cow.data_offset;
1314
1315 /* Remove the remapping, putting the original anonymous page
1316 * back. If the COW file can be mapped in, that is done.
1317 * Otherwise, the COW page is read in.
1318 */
1319
1320 if(!physmem_remove_mapping((void *) address))
1321 panic("Address 0x%lx not remapped by ubd device %d",
1322 address, i);
1323 if((offset % UBD_MMAP_BLOCK_SIZE) == 0)
1324 physmem_subst_mapping((void *) address, dev->fd,
1325 offset, 1);
1326 else {
1327 err = os_seek_file(dev->fd, offset);
1328 if(err < 0)
1329 panic("Couldn't seek to %lld in COW file of "
1330 "ubd device %d, err = %d", offset, i,
1331 -err);
1332
1333 n = os_read_file(dev->fd, (void *) address, PAGE_SIZE);
1334 if(n != PAGE_SIZE)
1335 panic("Failed to read page from offset %llx of "
1336 "COW file of ubd device %d, err = %d",
1337 offset, i, -n);
1338 }
1339
1340 return(1);
1341 }
1342
1343 /* It's not a write on a ubd device */
1344 return(0);
1345}
1346
1347static struct remapper ubd_remapper = {
1348 .list = LIST_HEAD_INIT(ubd_remapper.list),
1349 .proc = ubd_check_remapped,
1350};
1351
1352static int ubd_remapper_setup(void)
1353{
1354 if(ubd_do_mmap)
1355 register_remapper(&ubd_remapper);
1356
1357 return(0);
1358}
1359
1360__initcall(ubd_remapper_setup);
1361
1362static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
1363{
1364 struct uml_stat buf1, buf2;
1365 int err;
1366
1367 if(from_cmdline == NULL) return(1);
1368 if(!strcmp(from_cmdline, from_cow)) return(1);
1369
1370 err = os_stat_file(from_cmdline, &buf1);
1371 if(err < 0){
1372 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
1373 return(1);
1374 }
1375 err = os_stat_file(from_cow, &buf2);
1376 if(err < 0){
1377 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
1378 return(1);
1379 }
1380 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
1381 return(1);
1382
1383 printk("Backing file mismatch - \"%s\" requested,\n"
1384 "\"%s\" specified in COW header of \"%s\"\n",
1385 from_cmdline, from_cow, cow);
1386 return(0);
1387}
1388
1389static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
1390{
1391 unsigned long modtime;
1392 long long actual;
1393 int err;
1394
1395 err = os_file_modtime(file, &modtime);
1396 if(err < 0){
1397 printk("Failed to get modification time of backing file "
1398 "\"%s\", err = %d\n", file, -err);
1399 return(err);
1400 }
1401
1402 err = os_file_size(file, &actual);
1403 if(err < 0){
1404 printk("Failed to get size of backing file \"%s\", "
1405 "err = %d\n", file, -err);
1406 return(err);
1407 }
1408
1409 if(actual != size){
1410 /*__u64 can be a long on AMD64 and with %lu GCC complains; so
1411 * the typecast.*/
1412 printk("Size mismatch (%llu vs %llu) of COW header vs backing "
1413 "file\n", (unsigned long long) size, actual);
1414 return(-EINVAL);
1415 }
1416 if(modtime != mtime){
1417 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
1418 "file\n", mtime, modtime);
1419 return(-EINVAL);
1420 }
1421 return(0);
1422}
1423
1424int read_cow_bitmap(int fd, void *buf, int offset, int len)
1425{
1426 int err;
1427
1428 err = os_seek_file(fd, offset);
1429 if(err < 0)
1430 return(err);
1431
1432 err = os_read_file(fd, buf, len);
1433 if(err < 0)
1434 return(err);
1435
1436 return(0);
1437}
1438
1439int open_ubd_file(char *file, struct openflags *openflags,
1440 char **backing_file_out, int *bitmap_offset_out,
1441 unsigned long *bitmap_len_out, int *data_offset_out,
1442 int *create_cow_out)
1443{
1444 time_t mtime;
1445 unsigned long long size;
1446 __u32 version, align;
1447 char *backing_file;
1448 int fd, err, sectorsize, same, mode = 0644;
1449
1450 fd = os_open_file(file, *openflags, mode);
1451 if(fd < 0){
1452 if((fd == -ENOENT) && (create_cow_out != NULL))
1453 *create_cow_out = 1;
1454 if(!openflags->w ||
1455 ((fd != -EROFS) && (fd != -EACCES))) return(fd);
1456 openflags->w = 0;
1457 fd = os_open_file(file, *openflags, mode);
1458 if(fd < 0)
1459 return(fd);
1460 }
1461
1462 err = os_lock_file(fd, openflags->w);
1463 if(err < 0){
1464 printk("Failed to lock '%s', err = %d\n", file, -err);
1465 goto out_close;
1466 }
1467
1468 if(backing_file_out == NULL) return(fd);
1469
1470 err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
1471 &size, &sectorsize, &align, bitmap_offset_out);
1472 if(err && (*backing_file_out != NULL)){
1473 printk("Failed to read COW header from COW file \"%s\", "
1474 "errno = %d\n", file, -err);
1475 goto out_close;
1476 }
1477 if(err) return(fd);
1478
1479 if(backing_file_out == NULL) return(fd);
1480
1481 same = same_backing_files(*backing_file_out, backing_file, file);
1482
1483 if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
1484 printk("Switching backing file to '%s'\n", *backing_file_out);
1485 err = write_cow_header(file, fd, *backing_file_out,
1486 sectorsize, align, &size);
1487 if(err){
1488 printk("Switch failed, errno = %d\n", -err);
1489 return(err);
1490 }
1491 }
1492 else {
1493 *backing_file_out = backing_file;
1494 err = backing_file_mismatch(*backing_file_out, size, mtime);
1495 if(err) goto out_close;
1496 }
1497
1498 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
1499 bitmap_len_out, data_offset_out);
1500
1501 return(fd);
1502 out_close:
1503 os_close_file(fd);
1504 return(err);
1505}
1506
1507int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
1508 int sectorsize, int alignment, int *bitmap_offset_out,
1509 unsigned long *bitmap_len_out, int *data_offset_out)
1510{
1511 int err, fd;
1512
1513 flags.c = 1;
1514 fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
1515 if(fd < 0){
1516 err = fd;
1517 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
1518 -err);
1519 goto out;
1520 }
1521
1522 err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
1523 bitmap_offset_out, bitmap_len_out,
1524 data_offset_out);
1525 if(!err)
1526 return(fd);
1527 os_close_file(fd);
1528 out:
1529 return(err);
1530}
1531
1532static int update_bitmap(struct io_thread_req *req)
1533{
1534 int n;
1535
1536 if(req->cow_offset == -1)
1537 return(0);
1538
1539 n = os_seek_file(req->fds[1], req->cow_offset);
1540 if(n < 0){
1541 printk("do_io - bitmap lseek failed : err = %d\n", -n);
1542 return(1);
1543 }
1544
1545 n = os_write_file(req->fds[1], &req->bitmap_words,
1546 sizeof(req->bitmap_words));
1547 if(n != sizeof(req->bitmap_words)){
1548 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
1549 req->fds[1]);
1550 return(1);
1551 }
1552
1553 return(0);
1554}
1555
1556void do_io(struct io_thread_req *req)
1557{
1558 char *buf;
1559 unsigned long len;
1560 int n, nsectors, start, end, bit;
1561 int err;
1562 __u64 off;
1563
1564 if(req->op == UBD_MMAP){
1565 /* Touch the page to force the host to do any necessary IO to
1566 * get it into memory
1567 */
1568 n = *((volatile int *) req->buffer);
1569 req->error = update_bitmap(req);
1570 return;
1571 }
1572
1573 nsectors = req->length / req->sectorsize;
1574 start = 0;
1575 do {
1576 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
1577 end = start;
1578 while((end < nsectors) &&
1579 (ubd_test_bit(end, (unsigned char *)
1580 &req->sector_mask) == bit))
1581 end++;
1582
1583 off = req->offset + req->offsets[bit] +
1584 start * req->sectorsize;
1585 len = (end - start) * req->sectorsize;
1586 buf = &req->buffer[start * req->sectorsize];
1587
1588 err = os_seek_file(req->fds[bit], off);
1589 if(err < 0){
1590 printk("do_io - lseek failed : err = %d\n", -err);
1591 req->error = 1;
1592 return;
1593 }
1594 if(req->op == UBD_READ){
1595 n = 0;
1596 do {
1597 buf = &buf[n];
1598 len -= n;
1599 n = os_read_file(req->fds[bit], buf, len);
1600 if (n < 0) {
1601 printk("do_io - read failed, err = %d "
1602 "fd = %d\n", -n, req->fds[bit]);
1603 req->error = 1;
1604 return;
1605 }
1606 } while((n < len) && (n != 0));
1607 if (n < len) memset(&buf[n], 0, len - n);
1608 }
1609 else {
1610 n = os_write_file(req->fds[bit], buf, len);
1611 if(n != len){
1612 printk("do_io - write failed err = %d "
1613 "fd = %d\n", -n, req->fds[bit]);
1614 req->error = 1;
1615 return;
1616 }
1617 }
1618
1619 start = end;
1620 } while(start < nsectors);
1621
1622 req->error = update_bitmap(req);
1623}
1624
1625/* Changed in start_io_thread, which is serialized by being called only
1626 * from ubd_init, which is an initcall.
1627 */
1628int kernel_fd = -1;
1629
1630/* Only changed by the io thread */
1631int io_count = 0;
1632
1633int io_thread(void *arg)
1634{
1635 struct io_thread_req req;
1636 int n;
1637
1638 ignore_sigwinch_sig();
1639 while(1){
1640 n = os_read_file(kernel_fd, &req, sizeof(req));
1641 if(n != sizeof(req)){
1642 if(n < 0)
1643 printk("io_thread - read failed, fd = %d, "
1644 "err = %d\n", kernel_fd, -n);
1645 else {
1646 printk("io_thread - short read, fd = %d, "
1647 "length = %d\n", kernel_fd, n);
1648 }
1649 continue;
1650 }
1651 io_count++;
1652 do_io(&req);
1653 n = os_write_file(kernel_fd, &req, sizeof(req));
1654 if(n != sizeof(req))
1655 printk("io_thread - write failed, fd = %d, err = %d\n",
1656 kernel_fd, -n);
1657 }
1658}
1659
1660/*
1661 * Overrides for Emacs so that we follow Linus's tabbing style.
1662 * Emacs will notice this stuff at the end of the file and automatically
1663 * adjust the settings for this buffer only. This must remain at the end
1664 * of the file.
1665 * ---------------------------------------------------------------------------
1666 * Local variables:
1667 * c-file-style: "linux"
1668 * End:
1669 */
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
new file mode 100644
index 000000000000..b94d2bc4fe06
--- /dev/null
+++ b/arch/um/drivers/ubd_user.c
@@ -0,0 +1,75 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com)
4 * Licensed under the GPL
5 */
6
7#include <stddef.h>
8#include <unistd.h>
9#include <errno.h>
10#include <sched.h>
11#include <signal.h>
12#include <string.h>
13#include <netinet/in.h>
14#include <sys/time.h>
15#include <sys/socket.h>
16#include <sys/mman.h>
17#include <sys/param.h>
18#include "asm/types.h"
19#include "user_util.h"
20#include "kern_util.h"
21#include "user.h"
22#include "ubd_user.h"
23#include "os.h"
24#include "cow.h"
25
26#include <endian.h>
27#include <byteswap.h>
28
29void ignore_sigwinch_sig(void)
30{
31 signal(SIGWINCH, SIG_IGN);
32}
33
34int start_io_thread(unsigned long sp, int *fd_out)
35{
36 int pid, fds[2], err;
37
38 err = os_pipe(fds, 1, 1);
39 if(err < 0){
40 printk("start_io_thread - os_pipe failed, err = %d\n", -err);
41 goto out;
42 }
43
44 kernel_fd = fds[0];
45 *fd_out = fds[1];
46
47 pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
48 NULL);
49 if(pid < 0){
50 printk("start_io_thread - clone failed : errno = %d\n", errno);
51 err = -errno;
52 goto out_close;
53 }
54
55 return(pid);
56
57 out_close:
58 os_close_file(fds[0]);
59 os_close_file(fds[1]);
60 kernel_fd = -1;
61 *fd_out = -1;
62 out:
63 return(err);
64}
65
66/*
67 * Overrides for Emacs so that we follow Linus's tabbing style.
68 * Emacs will notice this stuff at the end of the file and automatically
69 * adjust the settings for this buffer only. This must remain at the end
70 * of the file.
71 * ---------------------------------------------------------------------------
72 * Local variables:
73 * c-file-style: "linux"
74 * End:
75 */
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
new file mode 100644
index 000000000000..93dc1911363f
--- /dev/null
+++ b/arch/um/drivers/xterm.c
@@ -0,0 +1,225 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <string.h>
10#include <errno.h>
11#include <termios.h>
12#include <signal.h>
13#include <sched.h>
14#include <sys/socket.h>
15#include "kern_util.h"
16#include "chan_user.h"
17#include "helper.h"
18#include "user_util.h"
19#include "user.h"
20#include "os.h"
21#include "xterm.h"
22
23struct xterm_chan {
24 int pid;
25 int helper_pid;
26 char *title;
27 int device;
28 int raw;
29 struct termios tt;
30 unsigned long stack;
31 int direct_rcv;
32};
33
34/* Not static because it's called directly by the tt mode gdb code */
35void *xterm_init(char *str, int device, struct chan_opts *opts)
36{
37 struct xterm_chan *data;
38
39 data = malloc(sizeof(*data));
40 if(data == NULL) return(NULL);
41 *data = ((struct xterm_chan) { .pid = -1,
42 .helper_pid = -1,
43 .device = device,
44 .title = opts->xterm_title,
45 .raw = opts->raw,
46 .stack = opts->tramp_stack,
47 .direct_rcv = !opts->in_kernel } );
48 return(data);
49}
50
51/* Only changed by xterm_setup, which is a setup */
52static char *terminal_emulator = "xterm";
53static char *title_switch = "-T";
54static char *exec_switch = "-e";
55
56static int __init xterm_setup(char *line, int *add)
57{
58 *add = 0;
59 terminal_emulator = line;
60
61 line = strchr(line, ',');
62 if(line == NULL) return(0);
63 *line++ = '\0';
64 if(*line) title_switch = line;
65
66 line = strchr(line, ',');
67 if(line == NULL) return(0);
68 *line++ = '\0';
69 if(*line) exec_switch = line;
70
71 return(0);
72}
73
74__uml_setup("xterm=", xterm_setup,
75"xterm=<terminal emulator>,<title switch>,<exec switch>\n"
76" Specifies an alternate terminal emulator to use for the debugger,\n"
77" consoles, and serial lines when they are attached to the xterm channel.\n"
78" The values are the terminal emulator binary, the switch it uses to set\n"
79" its title, and the switch it uses to execute a subprocess,\n"
80" respectively. The title switch must have the form '<switch> title',\n"
81" not '<switch>=title'. Similarly, the exec switch must have the form\n"
82" '<switch> command arg1 arg2 ...'.\n"
83" The default values are 'xterm=xterm,-T,-e'. Values for gnome-terminal\n"
84" are 'xterm=gnome-terminal,-t,-x'.\n\n"
85);
86
87/* XXX This badly needs some cleaning up in the error paths
88 * Not static because it's called directly by the tt mode gdb code
89 */
90int xterm_open(int input, int output, int primary, void *d,
91 char **dev_out)
92{
93 struct xterm_chan *data = d;
94 unsigned long stack;
95 int pid, fd, new, err;
96 char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
97 char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
98 "/usr/lib/uml/port-helper", "-uml-socket",
99 file, NULL };
100
101 if(os_access(argv[4], OS_ACC_X_OK) < 0)
102 argv[4] = "port-helper";
103
104 /* Check that DISPLAY is set, this doesn't guarantee the xterm
105 * will work but w/o it we can be pretty sure it won't. */
106 if (!getenv("DISPLAY")) {
107 printk("xterm_open: $DISPLAY not set.\n");
108 return -ENODEV;
109 }
110
111 fd = mkstemp(file);
112 if(fd < 0){
113 printk("xterm_open : mkstemp failed, errno = %d\n", errno);
114 return(-errno);
115 }
116
117 if(unlink(file)){
118 printk("xterm_open : unlink failed, errno = %d\n", errno);
119 return(-errno);
120 }
121 os_close_file(fd);
122
123 fd = os_create_unix_socket(file, sizeof(file), 1);
124 if(fd < 0){
125 printk("xterm_open : create_unix_socket failed, errno = %d\n",
126 -fd);
127 return(fd);
128 }
129
130 sprintf(title, data->title, data->device);
131 stack = data->stack;
132 pid = run_helper(NULL, NULL, argv, &stack);
133 if(pid < 0){
134 printk("xterm_open : run_helper failed, errno = %d\n", -pid);
135 return(pid);
136 }
137
138 if(data->stack == 0) free_stack(stack, 0);
139
140 if (data->direct_rcv) {
141 new = os_rcv_fd(fd, &data->helper_pid);
142 } else {
143 err = os_set_fd_block(fd, 0);
144 if(err < 0){
145 printk("xterm_open : failed to set descriptor "
146 "non-blocking, err = %d\n", -err);
147 return(err);
148 }
149 new = xterm_fd(fd, &data->helper_pid);
150 }
151 if(new < 0){
152 printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
153 goto out;
154 }
155
156 CATCH_EINTR(err = tcgetattr(new, &data->tt));
157 if(err){
158 new = err;
159 goto out;
160 }
161
162 if(data->raw){
163 err = raw(new);
164 if(err){
165 new = err;
166 goto out;
167 }
168 }
169
170 data->pid = pid;
171 *dev_out = NULL;
172 out:
173 unlink(file);
174 return(new);
175}
176
177/* Not static because it's called directly by the tt mode gdb code */
178void xterm_close(int fd, void *d)
179{
180 struct xterm_chan *data = d;
181
182 if(data->pid != -1)
183 os_kill_process(data->pid, 1);
184 data->pid = -1;
185 if(data->helper_pid != -1)
186 os_kill_process(data->helper_pid, 0);
187 data->helper_pid = -1;
188 os_close_file(fd);
189}
190
191static void xterm_free(void *d)
192{
193 free(d);
194}
195
196static int xterm_console_write(int fd, const char *buf, int n, void *d)
197{
198 struct xterm_chan *data = d;
199
200 return(generic_console_write(fd, buf, n, &data->tt));
201}
202
203struct chan_ops xterm_ops = {
204 .type = "xterm",
205 .init = xterm_init,
206 .open = xterm_open,
207 .close = xterm_close,
208 .read = generic_read,
209 .write = generic_write,
210 .console_write = xterm_console_write,
211 .window_size = generic_window_size,
212 .free = xterm_free,
213 .winch = 1,
214};
215
216/*
217 * Overrides for Emacs so that we follow Linus's tabbing style.
218 * Emacs will notice this stuff at the end of the file and automatically
219 * adjust the settings for this buffer only. This must remain at the end
220 * of the file.
221 * ---------------------------------------------------------------------------
222 * Local variables:
223 * c-file-style: "linux"
224 * End:
225 */
diff --git a/arch/um/drivers/xterm.h b/arch/um/drivers/xterm.h
new file mode 100644
index 000000000000..f33a6e77b186
--- /dev/null
+++ b/arch/um/drivers/xterm.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __XTERM_H__
7#define __XTERM_H__
8
9extern int xterm_fd(int socket, int *pid_out);
10
11#endif
12
13/*
14 * Overrides for Emacs so that we follow Linus's tabbing style.
15 * Emacs will notice this stuff at the end of the file and automatically
16 * adjust the settings for this buffer only. This must remain at the end
17 * of the file.
18 * ---------------------------------------------------------------------------
19 * Local variables:
20 * c-file-style: "linux"
21 * End:
22 */
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
new file mode 100644
index 000000000000..7917b9d1cec8
--- /dev/null
+++ b/arch/um/drivers/xterm_kern.c
@@ -0,0 +1,93 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/errno.h"
7#include "linux/slab.h"
8#include "linux/signal.h"
9#include "linux/interrupt.h"
10#include "asm/semaphore.h"
11#include "asm/irq.h"
12#include "irq_user.h"
13#include "irq_kern.h"
14#include "kern_util.h"
15#include "os.h"
16#include "xterm.h"
17
18struct xterm_wait {
19 struct completion ready;
20 int fd;
21 int pid;
22 int new_fd;
23};
24
25static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs)
26{
27 struct xterm_wait *xterm = data;
28 int fd;
29
30 fd = os_rcv_fd(xterm->fd, &xterm->pid);
31 if(fd == -EAGAIN)
32 return(IRQ_NONE);
33
34 xterm->new_fd = fd;
35 complete(&xterm->ready);
36 return(IRQ_HANDLED);
37}
38
39int xterm_fd(int socket, int *pid_out)
40{
41 struct xterm_wait *data;
42 int err, ret;
43
44 data = kmalloc(sizeof(*data), GFP_KERNEL);
45 if(data == NULL){
46 printk(KERN_ERR "xterm_fd : failed to allocate xterm_wait\n");
47 return(-ENOMEM);
48 }
49
50 /* This is a locked semaphore... */
51 *data = ((struct xterm_wait)
52 { .fd = socket,
53 .pid = -1,
54 .new_fd = -1 });
55 init_completion(&data->ready);
56
57 err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt,
58 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
59 "xterm", data);
60 if (err){
61 printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
62 "err = %d\n", err);
63 ret = err;
64 goto out;
65 }
66
67 /* ... so here we wait for an xterm interrupt.
68 *
69 * XXX Note, if the xterm doesn't work for some reason (eg. DISPLAY
70 * isn't set) this will hang... */
71 wait_for_completion(&data->ready);
72
73 free_irq_by_irq_and_dev(XTERM_IRQ, data);
74 free_irq(XTERM_IRQ, data);
75
76 ret = data->new_fd;
77 *pid_out = data->pid;
78 out:
79 kfree(data);
80
81 return(ret);
82}
83
84/*
85 * Overrides for Emacs so that we follow Linus's tabbing style.
86 * Emacs will notice this stuff at the end of the file and automatically
87 * adjust the settings for this buffer only. This must remain at the end
88 * of the file.
89 * ---------------------------------------------------------------------------
90 * Local variables:
91 * c-file-style: "linux"
92 * End:
93 */