Merge branch 'upstream-fixes'
[linux-2.6] / 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 <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
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 static 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
37 static 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                 err = -errno;
47                 printk("open_pts : Failed to open pts\n");
48                 return err;
49         }
50         if(data->raw){
51                 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
52                 if(err)
53                         return(err);
54
55                 err = raw(fd);
56                 if(err)
57                         return(err);
58         }
59
60         dev = ptsname(fd);
61         sprintf(data->dev_name, "%s", dev);
62         *dev_out = data->dev_name;
63         if (data->announce)
64                 (*data->announce)(dev, data->dev);
65         return(fd);
66 }
67
68 static int getmaster(char *line)
69 {
70         char *pty, *bank, *cp;
71         int master, err;
72
73         pty = &line[strlen("/dev/ptyp")];
74         for (bank = "pqrs"; *bank; bank++) {
75                 line[strlen("/dev/pty")] = *bank;
76                 *pty = '0';
77                 if (os_stat_file(line, NULL) < 0)
78                         break;
79                 for (cp = "0123456789abcdef"; *cp; cp++) {
80                         *pty = *cp;
81                         master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
82                         if (master >= 0) {
83                                 char *tp = &line[strlen("/dev/")];
84
85                                 /* verify slave side is usable */
86                                 *tp = 't';
87                                 err = os_access(line, OS_ACC_RW_OK);
88                                 *tp = 'p';
89                                 if(err == 0) return(master);
90                                 (void) os_close_file(master);
91                         }
92                 }
93         }
94         return(-1);
95 }
96
97 static int pty_open(int input, int output, int primary, void *d,
98                     char **dev_out)
99 {
100         struct pty_chan *data = d;
101         int fd, err;
102         char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
103
104         fd = getmaster(dev);
105         if(fd < 0)
106                 return(-errno);
107
108         if(data->raw){
109                 err = raw(fd);
110                 if(err)
111                         return(err);
112         }
113         
114         if(data->announce) (*data->announce)(dev, data->dev);
115
116         sprintf(data->dev_name, "%s", dev);
117         *dev_out = data->dev_name;
118         return(fd);
119 }
120
121 struct chan_ops pty_ops = {
122         .type           = "pty",
123         .init           = pty_chan_init,
124         .open           = pty_open,
125         .close          = generic_close,
126         .read           = generic_read,
127         .write          = generic_write,
128         .console_write  = generic_console_write,
129         .window_size    = generic_window_size,
130         .free           = generic_free,
131         .winch          = 0,
132 };
133
134 struct chan_ops pts_ops = {
135         .type           = "pts",
136         .init           = pty_chan_init,
137         .open           = pts_open,
138         .close          = generic_close,
139         .read           = generic_read,
140         .write          = generic_write,
141         .console_write  = generic_console_write,
142         .window_size    = generic_window_size,
143         .free           = generic_free,
144         .winch          = 0,
145 };
146
147 /*
148  * Overrides for Emacs so that we follow Linus's tabbing style.
149  * Emacs will notice this stuff at the end of the file and automatically
150  * adjust the settings for this buffer only.  This must remain at the end
151  * of the file.
152  * ---------------------------------------------------------------------------
153  * Local variables:
154  * c-file-style: "linux"
155  * End:
156  */