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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [armnommu/] [drivers/] [char/] [pty.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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