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

Subversion Repositories or1k

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

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/*
2
 *  linux/drivers/char/tty_ioctl.c
3
 *
4
 *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
5
 *
6
 * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
7
 * which can be dynamically activated and de-activated by the line
8
 * discipline handling modules (like SLIP).
9
 */
10
 
11
#include <linux/types.h>
12
#include <linux/termios.h>
13
#include <linux/errno.h>
14
#include <linux/sched.h>
15
#include <linux/kernel.h>
16
#include <linux/major.h>
17
#include <linux/tty.h>
18
#include <linux/fcntl.h>
19
#include <linux/string.h>
20
#include <linux/mm.h>
21
 
22
#include <asm/io.h>
23
#include <asm/bitops.h>
24
#include <asm/segment.h>
25
#include <asm/system.h>
26
 
27
#undef TTY_DEBUG_WAIT_UNTIL_SENT
28
 
29
#undef  DEBUG
30
#ifdef DEBUG
31
# define        PRINTK(x)       printk (x)
32
#else
33
# define        PRINTK(x)       /**/
34
#endif
35
 
36
/*
37
 * Internal flag options for termios setting behavior
38
 */
39
#define TERMIOS_FLUSH   1
40
#define TERMIOS_WAIT    2
41
#define TERMIOS_TERMIO  4
42
 
43
void tty_wait_until_sent(struct tty_struct * tty, int timeout)
44
{
45
        struct wait_queue wait = { current, NULL };
46
 
47
#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
48
        printk("%s wait until sent...\n", tty_name(tty));
49
#endif
50
        if (!tty->driver.chars_in_buffer ||
51
            !tty->driver.chars_in_buffer(tty))
52
                return;
53
        add_wait_queue(&tty->write_wait, &wait);
54
        current->counter = 0;    /* make us low-priority */
55
        if (timeout)
56
                current->timeout = timeout + jiffies;
57
        else
58
                current->timeout = (unsigned) -1;
59
        do {
60
#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
61
                printk("waiting %s...(%d)\n", tty_name(tty), tty->driver.chars_in_buffer(tty));
62
#endif
63
                current->state = TASK_INTERRUPTIBLE;
64
                if (current->signal & ~current->blocked)
65
                        break;
66
                if (!tty->driver.chars_in_buffer(tty))
67
                        break;
68
                schedule();
69
        } while (current->timeout);
70
        current->state = TASK_RUNNING;
71
        remove_wait_queue(&tty->write_wait, &wait);
72
}
73
 
74
static void unset_locked_termios(struct termios *termios,
75
                                 struct termios *old,
76
                                 struct termios *locked)
77
{
78
        int     i;
79
 
80
#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
81
 
82
        if (!locked) {
83
                printk("Warning?!? termios_locked is NULL.\n");
84
                return;
85
        }
86
 
87
        NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
88
        NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
89
        NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
90
        NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
91
        termios->c_line = locked->c_line ? old->c_line : termios->c_line;
92
        for (i=0; i < NCCS; i++)
93
                termios->c_cc[i] = locked->c_cc[i] ?
94
                        old->c_cc[i] : termios->c_cc[i];
95
}
96
 
97
static void change_termios(struct tty_struct * tty, struct termios * new_termios)
98
{
99
        int canon_change;
100
        struct termios old_termios = *tty->termios;
101
 
102
        cli();
103
        *tty->termios = *new_termios;
104
        unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
105
        canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
106
        if (canon_change) {
107
                memset(&tty->read_flags, 0, sizeof tty->read_flags);
108
                tty->canon_head = tty->read_tail;
109
                tty->canon_data = 0;
110
                tty->erasing = 0;
111
        }
112
        sti();
113
        if (canon_change && !L_ICANON(tty) && tty->read_cnt)
114
                /* Get characters left over from canonical mode. */
115
                wake_up_interruptible(&tty->read_wait);
116
 
117
        /* see if packet mode change of state */
118
 
119
        if (tty->link && tty->link->packet) {
120
                int old_flow = ((old_termios.c_iflag & IXON) &&
121
                                (old_termios.c_cc[VSTOP] == '\023') &&
122
                                (old_termios.c_cc[VSTART] == '\021'));
123
                int new_flow = (I_IXON(tty) &&
124
                                STOP_CHAR(tty) == '\023' &&
125
                                START_CHAR(tty) == '\021');
126
                if (old_flow != new_flow) {
127
                        tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
128
                        if (new_flow)
129
                                tty->ctrl_status |= TIOCPKT_DOSTOP;
130
                        else
131
                                tty->ctrl_status |= TIOCPKT_NOSTOP;
132
                        wake_up_interruptible(&tty->link->read_wait);
133
                }
134
        }
135
 
136
        if (tty->driver.set_termios)
137
                (*tty->driver.set_termios)(tty, &old_termios);
138
 
139
        if (tty->ldisc.set_termios)
140
                (*tty->ldisc.set_termios)(tty, &old_termios);
141
}
142
 
143
static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
144
{
145
        struct termios tmp_termios;
146
        int retval;
147
 
148
        retval = tty_check_change(tty);
149
        if (retval)
150
                return retval;
151
 
152
        if (opt & TERMIOS_TERMIO) {
153
                struct termio tmp_termio;
154
                retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio));
155
                if (retval)
156
                        return retval;
157
                tmp_termios = *tty->termios;
158
                memcpy_fromfs(&tmp_termio, (struct termio *) arg,
159
                              sizeof (struct termio));
160
                trans_from_termio(&tmp_termio, &tmp_termios);
161
        } else {
162
                retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termios));
163
                if (retval)
164
                        return retval;
165
                memcpy_fromfs(&tmp_termios, (struct termios *) arg,
166
                              sizeof (struct termios));
167
        }
168
 
169
        if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
170
                tty->ldisc.flush_buffer(tty);
171
 
172
        if (opt & TERMIOS_WAIT)
173
                tty_wait_until_sent(tty, 0);
174
 
175
        change_termios(tty, &tmp_termios);
176
        return 0;
177
}
178
 
179
static int get_termio(struct tty_struct * tty, struct termio * termio)
180
{
181
        int i;
182
        struct termio tmp_termio;
183
 
184
        i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
185
        if (i)
186
                return i;
187
        trans_to_termio(tty->termios, &tmp_termio);
188
        memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
189
        return 0;
190
}
191
 
192
static unsigned long inq_canon(struct tty_struct * tty)
193
{
194
        int nr, head, tail;
195
 
196
        if (!tty->canon_data || !tty->read_buf)
197
                return 0;
198
        head = tty->canon_head;
199
        tail = tty->read_tail;
200
        nr = (head - tail) & (N_TTY_BUF_SIZE-1);
201
        /* Skip EOF-chars.. */
202
        while (head != tail) {
203
                if (test_bit(tail, &tty->read_flags) &&
204
                    tty->read_buf[tail] == __DISABLED_CHAR)
205
                        nr--;
206
                tail = (tail+1) & (N_TTY_BUF_SIZE-1);
207
        }
208
        return nr;
209
}
210
 
211
#ifdef TIOCGETP
212
/*
213
 * These are deprecated, but there is limited support..
214
 *
215
 * The "sg_flags" translation is a joke..
216
 */
217
static int get_sgflags(struct tty_struct * tty)
218
{
219
        int flags = 0;
220
 
221
        if (!(tty->termios->c_lflag & ICANON))
222
                if (tty->termios->c_lflag & ISIG)
223
                        flags |= 0x02;          /* cbreak */
224
                else
225
                        flags |= 0x20;          /* raw */
226
        if (tty->termios->c_lflag & ECHO)
227
                flags |= 0x08;                  /* echo */
228
        if (tty->termios->c_oflag & OPOST)
229
                if (tty->termios->c_oflag & ONLCR)
230
                        flags |= 0x10;          /* crmod */
231
        return flags;
232
}
233
 
234
static int get_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb)
235
{
236
        int retval;
237
        struct sgttyb tmp;
238
 
239
        retval = verify_area(VERIFY_WRITE, sgttyb, sizeof(struct sgttyb));
240
        if (retval)
241
                return retval;
242
        tmp.sg_ispeed = 0;
243
        tmp.sg_ospeed = 0;
244
        tmp.sg_erase = tty->termios->c_cc[VERASE];
245
        tmp.sg_kill = tty->termios->c_cc[VKILL];
246
        tmp.sg_flags = get_sgflags(tty);
247
        memcpy_tofs(sgttyb, &tmp, sizeof(tmp));
248
        return 0;
249
}
250
 
251
static void set_sgflags(struct termios * termios, int flags)
252
{
253
        termios->c_iflag = ICRNL | IXON;
254
        termios->c_oflag = 0;
255
        termios->c_lflag = ISIG | ICANON;
256
        if (flags & 0x02) {     /* cbreak */
257
                termios->c_iflag = 0;
258
                termios->c_lflag &= ~ICANON;
259
        }
260
        if (flags & 0x08) {             /* echo */
261
                termios->c_lflag |= ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
262
        }
263
        if (flags & 0x10) {             /* crmod */
264
                termios->c_oflag |= OPOST | ONLCR;
265
        }
266
        if (flags & 0x20) {     /* raw */
267
                termios->c_iflag = 0;
268
                termios->c_lflag &= ~(ISIG | ICANON);
269
        }
270
        if (!(termios->c_lflag & ICANON)) {
271
                termios->c_cc[VMIN] = 1;
272
                termios->c_cc[VTIME] = 0;
273
        }
274
}
275
 
276
static int set_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb)
277
{
278
        int retval;
279
        struct sgttyb tmp;
280
        struct termios termios;
281
 
282
        retval = verify_area(VERIFY_READ, sgttyb, sizeof(struct sgttyb));
283
        if (retval)
284
                return retval;
285
        retval = tty_check_change(tty);
286
        if (retval)
287
                return retval;
288
        termios =  *tty->termios;
289
        memcpy_fromfs(&tmp, sgttyb, sizeof(tmp));
290
        termios.c_cc[VERASE] = tmp.sg_erase;
291
        termios.c_cc[VKILL] = tmp.sg_kill;
292
        set_sgflags(&termios, tmp.sg_flags);
293
        change_termios(tty, &termios);
294
        return 0;
295
}
296
#endif
297
 
298
#ifdef TIOCGETC
299
static int get_tchars(struct tty_struct * tty, struct tchars * tchars)
300
{
301
        int retval;
302
        struct tchars tmp;
303
 
304
        retval = verify_area(VERIFY_WRITE, tchars, sizeof(struct tchars));
305
        if (retval)
306
                return retval;
307
        tmp.t_intrc = tty->termios->c_cc[VINTR];
308
        tmp.t_quitc = tty->termios->c_cc[VQUIT];
309
        tmp.t_startc = tty->termios->c_cc[VSTART];
310
        tmp.t_stopc = tty->termios->c_cc[VSTOP];
311
        tmp.t_eofc = tty->termios->c_cc[VEOF];
312
        tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
313
        memcpy_tofs(tchars, &tmp, sizeof(tmp));
314
        return 0;
315
}
316
 
317
static int set_tchars(struct tty_struct * tty, struct tchars * tchars)
318
{
319
        int retval;
320
        struct tchars tmp;
321
 
322
        retval = verify_area(VERIFY_READ, tchars, sizeof(struct tchars));
323
        if (retval)
324
                return retval;
325
        memcpy_fromfs(&tmp, tchars, sizeof(tmp));
326
        tty->termios->c_cc[VINTR] = tmp.t_intrc;
327
        tty->termios->c_cc[VQUIT] = tmp.t_quitc;
328
        tty->termios->c_cc[VSTART] = tmp.t_startc;
329
        tty->termios->c_cc[VSTOP] = tmp.t_stopc;
330
        tty->termios->c_cc[VEOF] = tmp.t_eofc;
331
        tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
332
        return 0;
333
}
334
#endif
335
 
336
#ifdef TIOCGLTC
337
static int get_ltchars(struct tty_struct * tty, struct ltchars * ltchars)
338
{
339
        int retval;
340
        struct ltchars tmp;
341
 
342
        retval = verify_area(VERIFY_WRITE, ltchars, sizeof(struct ltchars));
343
        if (retval)
344
                return retval;
345
        tmp.t_suspc = tty->termios->c_cc[VSUSP];
346
        tmp.t_dsuspc = tty->termios->c_cc[VSUSP];       /* what is dsuspc anyway? */
347
        tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
348
        tmp.t_flushc = tty->termios->c_cc[VEOL2];       /* what is flushc anyway? */
349
        tmp.t_werasc = tty->termios->c_cc[VWERASE];
350
        tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
351
        memcpy_tofs(ltchars, &tmp, sizeof(tmp));
352
        return 0;
353
}
354
 
355
static int set_ltchars(struct tty_struct * tty, struct ltchars * ltchars)
356
{
357
        int retval;
358
        struct ltchars tmp;
359
 
360
        retval = verify_area(VERIFY_READ, ltchars, sizeof(struct ltchars));
361
        if (retval)
362
                return retval;
363
        memcpy_fromfs(&tmp, ltchars, sizeof(tmp));
364
        tty->termios->c_cc[VSUSP] = tmp.t_suspc;
365
        tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;       /* what is dsuspc anyway? */
366
        tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
367
        tty->termios->c_cc[VEOL2] = tmp.t_flushc;       /* what is flushc anyway? */
368
        tty->termios->c_cc[VWERASE] = tmp.t_werasc;
369
        tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
370
        return 0;
371
}
372
#endif
373
 
374
int n_tty_ioctl(struct tty_struct * tty, struct file * file,
375
                       unsigned int cmd, unsigned long arg)
376
{
377
        struct tty_struct * real_tty;
378
        int retval;
379
 
380
        if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
381
            tty->driver.subtype == PTY_TYPE_MASTER)
382
                real_tty = tty->link;
383
        else
384
                real_tty = tty;
385
 
386
        switch (cmd) {
387
#ifdef TIOCGETP
388
                case TIOCGETP:
389
                        return get_sgttyb(real_tty, (struct sgttyb *) arg);
390
                case TIOCSETP:
391
                case TIOCSETN:
392
                        return set_sgttyb(real_tty, (struct sgttyb *) arg);
393
#endif
394
#ifdef TIOCGETC
395
                case TIOCGETC:
396
                        return get_tchars(real_tty, (struct tchars *) arg);
397
                case TIOCSETC:
398
                        return set_tchars(real_tty, (struct tchars *) arg);
399
#endif
400
#ifdef TIOCGLTC
401
                case TIOCGLTC:
402
                        return get_ltchars(real_tty, (struct ltchars *) arg);
403
                case TIOCSLTC:
404
                        return set_ltchars(real_tty, (struct ltchars *) arg);
405
#endif
406
                case TCGETS:
407
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
408
                                             sizeof (struct termios));
409
                        if (retval)
410
                                return retval;
411
                        memcpy_tofs((struct termios *) arg,
412
                                    real_tty->termios,
413
                                    sizeof (struct termios));
414
                        return 0;
415
                case TCSETSF:
416
                        return set_termios(real_tty, arg, TERMIOS_FLUSH);
417
                case TCSETSW:
418
                        return set_termios(real_tty, arg, TERMIOS_WAIT);
419
                case TCSETS:
420
                        return set_termios(real_tty, arg, 0);
421
                case TCGETA:
422
                        return get_termio(real_tty,(struct termio *) arg);
423
                case TCSETAF:
424
                        return set_termios(real_tty, arg, TERMIOS_FLUSH | TERMIOS_TERMIO);
425
                case TCSETAW:
426
                        return set_termios(real_tty, arg, TERMIOS_WAIT | TERMIOS_TERMIO);
427
                case TCSETA:
428
                        return set_termios(real_tty, arg, TERMIOS_TERMIO);
429
                case TCXONC:
430
                        retval = tty_check_change(tty);
431
                        if (retval)
432
                                return retval;
433
                        switch (arg) {
434
                        case TCOOFF:
435
                                stop_tty(tty);
436
                                break;
437
                        case TCOON:
438
                                start_tty(tty);
439
                                break;
440
                        case TCIOFF:
441
                                if (STOP_CHAR(tty) != __DISABLED_CHAR)
442
                                        tty->driver.write(tty, 0,
443
                                                          &STOP_CHAR(tty), 1);
444
                                break;
445
                        case TCION:
446
                                if (START_CHAR(tty) != __DISABLED_CHAR)
447
                                        tty->driver.write(tty, 0,
448
                                                          &START_CHAR(tty), 1);
449
                                break;
450
                        default:
451
                                return -EINVAL;
452
                        }
453
                        return 0;
454
                case TCFLSH:
455
                        retval = tty_check_change(tty);
456
                        if (retval)
457
                                return retval;
458
                        switch (arg) {
459
                        case TCIFLUSH:
460
                                if (tty->ldisc.flush_buffer)
461
                                        tty->ldisc.flush_buffer(tty);
462
                                break;
463
                        case TCIOFLUSH:
464
                                if (tty->ldisc.flush_buffer)
465
                                        tty->ldisc.flush_buffer(tty);
466
                                /* fall through */
467
                        case TCOFLUSH:
468
                                if (tty->driver.flush_buffer)
469
                                        tty->driver.flush_buffer(tty);
470
                                break;
471
                        default:
472
                                return -EINVAL;
473
                        }
474
                        return 0;
475
                case TIOCOUTQ:
476
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
477
                                             sizeof (int));
478
                        if (retval)
479
                                return retval;
480
                        if (tty->driver.chars_in_buffer)
481
                                put_user(tty->driver.chars_in_buffer(tty),
482
                                         (int *) arg);
483
                        else
484
                                put_user(0, (int *) arg);
485
                        return 0;
486
                case TIOCINQ:
487
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
488
                                             sizeof (unsigned long));
489
                        if (retval)
490
                                return retval;
491
                        if (L_ICANON(tty))
492
                                put_fs_long(inq_canon(tty),
493
                                        (unsigned long *) arg);
494
                        else
495
                                put_fs_long(tty->read_cnt,
496
                                            (unsigned long *) arg);
497
                        return 0;
498
                case TIOCGLCKTRMIOS:
499
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
500
                                             sizeof (struct termios));
501
                        if (retval)
502
                                return retval;
503
                        memcpy_tofs((struct termios *) arg,
504
                                    real_tty->termios_locked,
505
                                    sizeof (struct termios));
506
                        return 0;
507
                case TIOCSLCKTRMIOS:
508
                        if (!suser())
509
                                return -EPERM;
510
                        retval = verify_area(VERIFY_READ, (void *) arg,
511
                                             sizeof (struct termios));
512
                        if (retval)
513
                                return retval;
514
                        memcpy_fromfs(real_tty->termios_locked,
515
                                      (struct termios *) arg,
516
                                      sizeof (struct termios));
517
                        return 0;
518
                case TIOCPKT:
519
                        if (tty->driver.type != TTY_DRIVER_TYPE_PTY ||
520
                            tty->driver.subtype != PTY_TYPE_MASTER)
521
                                return -ENOTTY;
522
                        retval = verify_area(VERIFY_READ, (void *) arg,
523
                                             sizeof (int));
524
                        if (retval)
525
                                return retval;
526
                        if (get_user((int*)arg)) {
527
                                if (!tty->packet) {
528
                                        tty->packet = 1;
529
                                        tty->link->ctrl_status = 0;
530
                                }
531
                        } else
532
                                tty->packet = 0;
533
                        return 0;
534
                /* These two ioctl's always return success; even if */
535
                /* the driver doesn't support them. */
536
                case TCSBRK: case TCSBRKP:
537
                        retval = tty_check_change(tty);
538
                        if (retval)
539
                                return retval;
540
                        tty_wait_until_sent(tty, 0);
541
                        if (!tty->driver.ioctl)
542
                                return 0;
543
                        tty->driver.ioctl(tty, file, cmd, arg);
544
                        return 0;
545
                default:
546
                        return -ENOIOCTLCMD;
547
                }
548
}

powered by: WebSVN 2.1.0

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