ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / um / drivers / pty.c
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 <fcntl.h>
11 #include <termios.h>
12 #include "chan_user.h"
13 #include "user.h"
14 #include "user_util.h"
15 #include "kern_util.h"
16
17 struct 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
25 void *pty_chan_init(char *str, int device, struct chan_opts *opts)
26 {
27         struct pty_chan *data;
28
29         if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
30         *data = ((struct pty_chan) { .announce          = opts->announce, 
31                                      .dev               = device,
32                                      .raw               = opts->raw });
33         return(data);
34 }
35
36 int pts_open(int input, int output, int primary, void *d, char **dev_out)
37 {
38         struct pty_chan *data = d;
39         char *dev;
40         int fd;
41
42         if((fd = get_pty()) < 0){
43                 printk("open_pts : Failed to open pts\n");
44                 return(-errno);
45         }
46         if(data->raw){
47                 tcgetattr(fd, &data->tt);
48                 raw(fd, 0);
49         }
50
51         dev = ptsname(fd);
52         sprintf(data->dev_name, "%s", dev);
53         *dev_out = data->dev_name;
54         if(data->announce) (*data->announce)(dev, data->dev);
55         return(fd);
56 }
57
58 int getmaster(char *line)
59 {
60         struct stat stb;
61         char *pty, *bank, *cp;
62         int master;
63
64         pty = &line[strlen("/dev/ptyp")];
65         for (bank = "pqrs"; *bank; bank++) {
66                 line[strlen("/dev/pty")] = *bank;
67                 *pty = '0';
68                 if (stat(line, &stb) < 0)
69                         break;
70                 for (cp = "0123456789abcdef"; *cp; cp++) {
71                         *pty = *cp;
72                         master = open(line, O_RDWR);
73                         if (master >= 0) {
74                                 char *tp = &line[strlen("/dev/")];
75                                 int ok;
76
77                                 /* verify slave side is usable */
78                                 *tp = 't';
79                                 ok = access(line, R_OK|W_OK) == 0;
80                                 *tp = 'p';
81                                 if (ok) return(master);
82                                 (void) close(master);
83                         }
84                 }
85         }
86         return(-1);
87 }
88
89 int pty_open(int input, int output, int primary, void *d, char **dev_out)
90 {
91         struct pty_chan *data = d;
92         int fd;
93         char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
94
95         fd = getmaster(dev);
96         if(fd < 0) return(-errno);
97         
98         if(data->raw) raw(fd, 0);
99         if(data->announce) (*data->announce)(dev, data->dev);
100
101         sprintf(data->dev_name, "%s", dev);
102         *dev_out = data->dev_name;
103         return(fd);
104 }
105
106 int pty_console_write(int fd, const char *buf, int n, void *d)
107 {
108         struct pty_chan *data = d;
109
110         return(generic_console_write(fd, buf, n, &data->tt));
111 }
112
113 struct chan_ops pty_ops = {
114         .type           = "pty",
115         .init           = pty_chan_init,
116         .open           = pty_open,
117         .close          = generic_close,
118         .read           = generic_read,
119         .write          = generic_write,
120         .console_write  = pty_console_write,
121         .window_size    = generic_window_size,
122         .free           = generic_free,
123         .winch          = 0,
124 };
125
126 struct chan_ops pts_ops = {
127         .type           = "pts",
128         .init           = pty_chan_init,
129         .open           = pts_open,
130         .close          = generic_close,
131         .read           = generic_read,
132         .write          = generic_write,
133         .console_write  = pty_console_write,
134         .window_size    = generic_window_size,
135         .free           = generic_free,
136         .winch          = 0,
137 };
138
139 /*
140  * Overrides for Emacs so that we follow Linus's tabbing style.
141  * Emacs will notice this stuff at the end of the file and automatically
142  * adjust the settings for this buffer only.  This must remain at the end
143  * of the file.
144  * ---------------------------------------------------------------------------
145  * Local variables:
146  * c-file-style: "linux"
147  * End:
148  */