OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [char/] [pty.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/*
2
 *  linux/drivers/char/pty.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 */
6
 
7
/*
8
 *      pty.c
9
 *
10
 * This module exports the following pty function:
11
 *
12
 *      int  pty_open(struct tty_struct * tty, struct file * filp);
13
 */
14
 
15
#include <linux/errno.h>
16
#include <linux/sched.h>
17
#include <linux/interrupt.h>
18
#include <linux/tty.h>
19
#include <linux/tty_flip.h>
20
#include <linux/fcntl.h>
21
#include <linux/string.h>
22
#include <linux/major.h>
23
#include <linux/mm.h>
24
 
25
#include <asm/segment.h>
26
#include <asm/system.h>
27
#include <asm/bitops.h>
28
 
29
struct pty_struct {
30
        int     magic;
31
        struct wait_queue * open_wait;
32
};
33
 
34
#define PTY_MAGIC 0x5001
35
 
36
#define PTY_BUF_SIZE PAGE_SIZE/2
37
 
38
/*
39
 * tmp_buf is used as a temporary buffer by pty_write.  We need to
40
 * lock it in case the memcpy_fromfs blocks while swapping in a page,
41
 * and some other program tries to do a pty write at the same time.
42
 * Since the lock will only come under contention when the system is
43
 * swapping and available memory is low, it makes sense to share one
44
 * buffer across all the PTY's, since it significantly saves memory if
45
 * large numbers of PTY's are open.
46
 */
47
static unsigned char *tmp_buf;
48
static struct semaphore tmp_buf_sem = MUTEX;
49
 
50
struct tty_driver pty_driver, pty_slave_driver;
51
struct tty_driver old_pty_driver, old_pty_slave_driver;
52
static int pty_refcount;
53
 
54
static struct tty_struct *pty_table[NR_PTYS];
55
static struct termios *pty_termios[NR_PTYS];
56
static struct termios *pty_termios_locked[NR_PTYS];
57
static struct tty_struct *ttyp_table[NR_PTYS];
58
static struct termios *ttyp_termios[NR_PTYS];
59
static struct termios *ttyp_termios_locked[NR_PTYS];
60
static struct pty_struct pty_state[NR_PTYS];
61
 
62
#define MIN(a,b)        ((a) < (b) ? (a) : (b))
63
 
64
static void pty_close(struct tty_struct * tty, struct file * filp)
65
{
66
        if (!tty)
67
                return;
68
        if (tty->driver.subtype == PTY_TYPE_MASTER) {
69
                if (tty->count > 1)
70
                        printk("master pty_close: count = %d!!\n", tty->count);
71
        } else {
72
                if (tty->count > 2)
73
                        return;
74
        }
75
        wake_up_interruptible(&tty->read_wait);
76
        wake_up_interruptible(&tty->write_wait);
77
        if (!tty->link)
78
                return;
79
        wake_up_interruptible(&tty->link->read_wait);
80
        wake_up_interruptible(&tty->link->write_wait);
81
        set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
82
        if (tty->driver.subtype == PTY_TYPE_MASTER) {
83
                tty_hangup(tty->link);
84
                set_bit(TTY_OTHER_CLOSED, &tty->flags);
85
        }
86
}
87
 
88
/*
89
 * The unthrottle routine is called by the line discipline to signal
90
 * that it can receive more characters.  For PTY's, the TTY_THROTTLED
91
 * flag is always set, to force the line discipline to always call the
92
 * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
93
 * characters in the queue.  This is necessary since each time this
94
 * happens, we need to wake up any sleeping processes that could be
95
 * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
96
 * for the pty buffer to be drained.
97
 */
98
static void pty_unthrottle(struct tty_struct * tty)
99
{
100
        struct tty_struct *o_tty = tty->link;
101
 
102
        if (!o_tty)
103
                return;
104
 
105
        if ((o_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
106
            o_tty->ldisc.write_wakeup)
107
                (o_tty->ldisc.write_wakeup)(o_tty);
108
        wake_up_interruptible(&o_tty->write_wait);
109
        set_bit(TTY_THROTTLED, &tty->flags);
110
}
111
 
112
static int pty_write(struct tty_struct * tty, int from_user,
113
                       const unsigned char *buf, int count)
114
{
115
        struct tty_struct *to = tty->link;
116
        int     c=0, n, r;
117
        char    *temp_buffer;
118
 
119
        if (!to || tty->stopped)
120
                return 0;
121
 
122
        if (from_user) {
123
                down(&tmp_buf_sem);
124
                temp_buffer = tmp_buf +
125
                        ((tty->driver.subtype-1) * PTY_BUF_SIZE);
126
                while (count > 0) {
127
                        n = MIN(count, PTY_BUF_SIZE);
128
                        memcpy_fromfs(temp_buffer, buf, n);
129
                        r = to->ldisc.receive_room(to);
130
                        if (r <= 0)
131
                                break;
132
                        n = MIN(n, r);
133
                        to->ldisc.receive_buf(to, temp_buffer, 0, n);
134
                        buf += n;  c+= n;
135
                        count -= n;
136
                }
137
                up(&tmp_buf_sem);
138
        } else {
139
                c = MIN(count, to->ldisc.receive_room(to));
140
                to->ldisc.receive_buf(to, buf, 0, c);
141
        }
142
 
143
        return c;
144
}
145
 
146
static int pty_write_room(struct tty_struct *tty)
147
{
148
        struct tty_struct *to = tty->link;
149
 
150
        if (!to || tty->stopped)
151
                return 0;
152
 
153
        return to->ldisc.receive_room(to);
154
}
155
 
156
/*
157
 * Modified for asymmetric master/slave behavior
158
 * The chars_in_buffer() value is used by the ldisc select() function
159
 * to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256).
160
 * To allow typed-ahead commands to accumulate, the master side returns 0
161
 * until the buffer is half full. The slave side returns the true count.
162
 */
163
static int pty_chars_in_buffer(struct tty_struct *tty)
164
{
165
        struct tty_struct *to = tty->link;
166
        int count;
167
 
168
        if (!to || !to->ldisc.chars_in_buffer)
169
                return 0;
170
 
171
        /* The ldisc must report 0 if no characters available to be read */
172
        count = to->ldisc.chars_in_buffer(to);
173
 
174
        if (tty->driver.subtype == PTY_TYPE_SLAVE) return count;
175
 
176
        /*
177
         * Master side driver ... return 0 if the other side's read buffer
178
         * is less than half full.  This allows room for typed-ahead commands
179
         * with a reasonable margin to avoid overflow.
180
         */
181
        return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
182
}
183
 
184
static void pty_flush_buffer(struct tty_struct *tty)
185
{
186
        struct tty_struct *to = tty->link;
187
 
188
        if (!to)
189
                return;
190
 
191
        if (to->ldisc.flush_buffer)
192
                to->ldisc.flush_buffer(to);
193
 
194
        if (to->packet) {
195
                tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
196
                wake_up_interruptible(&to->read_wait);
197
        }
198
}
199
 
200
int pty_open(struct tty_struct *tty, struct file * filp)
201
{
202
        int     retval;
203
        int     line;
204
        struct  pty_struct *pty;
205
 
206
        retval = -ENODEV;
207
        if (!tty || !tty->link)
208
                goto out;
209
        line = MINOR(tty->device) - tty->driver.minor_start;
210
        if ((line < 0) || (line >= NR_PTYS))
211
                goto out;
212
        pty = pty_state + line;
213
        tty->driver_data = pty;
214
 
215
        if (!tmp_buf) {
216
                unsigned long page = __get_free_page(GFP_KERNEL);
217
                if (!tmp_buf) {
218
                        retval = -ENOMEM;
219
                        if (!page)
220
                                goto out;
221
                        tmp_buf = (unsigned char *) page;
222
                        memset((void *) page, 0, PAGE_SIZE);
223
                } else
224
                        free_page(page);
225
        }
226
        retval = -EIO;
227
        if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
228
                goto out;
229
        if (tty->link->count != 1)
230
                goto out;
231
 
232
        clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
233
        wake_up_interruptible(&pty->open_wait);
234
        set_bit(TTY_THROTTLED, &tty->flags);
235
        retval = 0;
236
out:
237
        return retval;
238
}
239
 
240
static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios)
241
{
242
        tty->termios->c_cflag &= ~(CSIZE | PARENB);
243
        tty->termios->c_cflag |= (CS8 | CREAD);
244
}
245
 
246
int pty_init(void)
247
{
248
        memset(&pty_state, 0, sizeof(pty_state));
249
        memset(&pty_driver, 0, sizeof(struct tty_driver));
250
        pty_driver.magic = TTY_DRIVER_MAGIC;
251
        pty_driver.name = "pty";
252
        pty_driver.major = PTY_MASTER_MAJOR;
253
        pty_driver.minor_start = 0;
254
        pty_driver.num = NR_PTYS;
255
        pty_driver.type = TTY_DRIVER_TYPE_PTY;
256
        pty_driver.subtype = PTY_TYPE_MASTER;
257
        pty_driver.init_termios = tty_std_termios;
258
        pty_driver.init_termios.c_iflag = 0;
259
        pty_driver.init_termios.c_oflag = 0;
260
        pty_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
261
        pty_driver.init_termios.c_lflag = 0;
262
        pty_driver.flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
263
        pty_driver.refcount = &pty_refcount;
264
        pty_driver.table = pty_table;
265
        pty_driver.termios = pty_termios;
266
        pty_driver.termios_locked = pty_termios_locked;
267
        pty_driver.other = &pty_slave_driver;
268
 
269
        pty_driver.open = pty_open;
270
        pty_driver.close = pty_close;
271
        pty_driver.write = pty_write;
272
        pty_driver.write_room = pty_write_room;
273
        pty_driver.flush_buffer = pty_flush_buffer;
274
        pty_driver.chars_in_buffer = pty_chars_in_buffer;
275
        pty_driver.unthrottle = pty_unthrottle;
276
        pty_driver.set_termios = pty_set_termios;
277
 
278
        pty_slave_driver = pty_driver;
279
        pty_slave_driver.name = "ttyp";
280
        pty_slave_driver.subtype = PTY_TYPE_SLAVE;
281
        pty_slave_driver.major = PTY_SLAVE_MAJOR;
282
        pty_slave_driver.minor_start = 0;
283
        pty_slave_driver.init_termios = tty_std_termios;
284
        pty_slave_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
285
        pty_slave_driver.table = ttyp_table;
286
        pty_slave_driver.termios = ttyp_termios;
287
        pty_slave_driver.termios_locked = ttyp_termios_locked;
288
        pty_slave_driver.other = &pty_driver;
289
 
290
        old_pty_driver = pty_driver;
291
        old_pty_driver.major = TTY_MAJOR;
292
        old_pty_driver.minor_start = 128;
293
        old_pty_driver.num = (NR_PTYS > 64) ? 64 : NR_PTYS;
294
        old_pty_driver.other = &old_pty_slave_driver;
295
 
296
        old_pty_slave_driver = pty_slave_driver;
297
        old_pty_slave_driver.major = TTY_MAJOR;
298
        old_pty_slave_driver.minor_start = 192;
299
        old_pty_slave_driver.num = (NR_PTYS > 64) ? 64 : NR_PTYS;
300
        old_pty_slave_driver.other = &old_pty_driver;
301
 
302
        tmp_buf = 0;
303
 
304
        if (tty_register_driver(&pty_driver))
305
                panic("Couldn't register pty driver");
306
        if (tty_register_driver(&pty_slave_driver))
307
                panic("Couldn't register pty slave driver");
308
        if (tty_register_driver(&old_pty_driver))
309
                panic("Couldn't register compat pty driver");
310
        if (tty_register_driver(&old_pty_slave_driver))
311
                panic("Couldn't register compat pty slave driver");
312
 
313
        return 0;
314
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.