]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/um/drivers/pty.c
aa311afa966761c90e9229d4c8d6f57fa4ccb864
[karo-tx-linux.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 <stdlib.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <errno.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 #include "os.h"
17 #include "um_malloc.h"
18
19 struct pty_chan {
20         void (*announce)(char *dev_name, int dev);
21         int dev;
22         int raw;
23         struct termios tt;
24         char dev_name[sizeof("/dev/pts/0123456\0")];
25 };
26
27 static void *pty_chan_init(char *str, int device, const struct chan_opts *opts)
28 {
29         struct pty_chan *data;
30
31         data = um_kmalloc(sizeof(*data));
32         if(data == NULL) return(NULL);
33         *data = ((struct pty_chan) { .announce          = opts->announce, 
34                                      .dev               = device,
35                                      .raw               = opts->raw });
36         return(data);
37 }
38
39 static int pts_open(int input, int output, int primary, void *d,
40                     char **dev_out)
41 {
42         struct pty_chan *data = d;
43         char *dev;
44         int fd, err;
45
46         fd = get_pty();
47         if(fd < 0){
48                 err = -errno;
49                 printk("open_pts : Failed to open pts\n");
50                 return err;
51         }
52         if(data->raw){
53                 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
54                 if(err)
55                         return(err);
56
57                 err = raw(fd);
58                 if(err)
59                         return(err);
60         }
61
62         dev = ptsname(fd);
63         sprintf(data->dev_name, "%s", dev);
64         *dev_out = data->dev_name;
65         if (data->announce)
66                 (*data->announce)(dev, data->dev);
67         return(fd);
68 }
69
70 static int getmaster(char *line)
71 {
72         char *pty, *bank, *cp;
73         int master, err;
74
75         pty = &line[strlen("/dev/ptyp")];
76         for (bank = "pqrs"; *bank; bank++) {
77                 line[strlen("/dev/pty")] = *bank;
78                 *pty = '0';
79                 if (os_stat_file(line, NULL) < 0)
80                         break;
81                 for (cp = "0123456789abcdef"; *cp; cp++) {
82                         *pty = *cp;
83                         master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
84                         if (master >= 0) {
85                                 char *tp = &line[strlen("/dev/")];
86
87                                 /* verify slave side is usable */
88                                 *tp = 't';
89                                 err = os_access(line, OS_ACC_RW_OK);
90                                 *tp = 'p';
91                                 if(err == 0) return(master);
92                                 (void) os_close_file(master);
93                         }
94                 }
95         }
96         return(-1);
97 }
98
99 static int pty_open(int input, int output, int primary, void *d,
100                     char **dev_out)
101 {
102         struct pty_chan *data = d;
103         int fd, err;
104         char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
105
106         fd = getmaster(dev);
107         if(fd < 0)
108                 return(-errno);
109
110         if(data->raw){
111                 err = raw(fd);
112                 if(err)
113                         return(err);
114         }
115         
116         if(data->announce) (*data->announce)(dev, data->dev);
117
118         sprintf(data->dev_name, "%s", dev);
119         *dev_out = data->dev_name;
120         return(fd);
121 }
122
123 const struct chan_ops pty_ops = {
124         .type           = "pty",
125         .init           = pty_chan_init,
126         .open           = pty_open,
127         .close          = generic_close,
128         .read           = generic_read,
129         .write          = generic_write,
130         .console_write  = generic_console_write,
131         .window_size    = generic_window_size,
132         .free           = generic_free,
133         .winch          = 0,
134 };
135
136 const struct chan_ops pts_ops = {
137         .type           = "pts",
138         .init           = pty_chan_init,
139         .open           = pts_open,
140         .close          = generic_close,
141         .read           = generic_read,
142         .write          = generic_write,
143         .console_write  = generic_console_write,
144         .window_size    = generic_window_size,
145         .free           = generic_free,
146         .winch          = 0,
147 };
148
149 /*
150  * Overrides for Emacs so that we follow Linus's tabbing style.
151  * Emacs will notice this stuff at the end of the file and automatically
152  * adjust the settings for this buffer only.  This must remain at the end
153  * of the file.
154  * ---------------------------------------------------------------------------
155  * Local variables:
156  * c-file-style: "linux"
157  * End:
158  */