0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/types.h>
0011 #include <linux/termios.h>
0012 #include <linux/errno.h>
0013 #include <linux/sched/signal.h>
0014 #include <linux/kernel.h>
0015 #include <linux/major.h>
0016 #include <linux/tty.h>
0017 #include <linux/fcntl.h>
0018 #include <linux/string.h>
0019 #include <linux/mm.h>
0020 #include <linux/module.h>
0021 #include <linux/bitops.h>
0022 #include <linux/mutex.h>
0023 #include <linux/compat.h>
0024 #include "tty.h"
0025
0026 #include <asm/io.h>
0027 #include <linux/uaccess.h>
0028
0029 #undef TTY_DEBUG_WAIT_UNTIL_SENT
0030
0031 #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
0032 # define tty_debug_wait_until_sent(tty, f, args...) tty_debug(tty, f, ##args)
0033 #else
0034 # define tty_debug_wait_until_sent(tty, f, args...) do {} while (0)
0035 #endif
0036
0037 #undef DEBUG
0038
0039
0040
0041
0042 #define TERMIOS_FLUSH 1
0043 #define TERMIOS_WAIT 2
0044 #define TERMIOS_TERMIO 4
0045 #define TERMIOS_OLD 8
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 unsigned int tty_chars_in_buffer(struct tty_struct *tty)
0058 {
0059 if (tty->ops->chars_in_buffer)
0060 return tty->ops->chars_in_buffer(tty);
0061 return 0;
0062 }
0063 EXPORT_SYMBOL(tty_chars_in_buffer);
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 unsigned int tty_write_room(struct tty_struct *tty)
0077 {
0078 if (tty->ops->write_room)
0079 return tty->ops->write_room(tty);
0080 return 2048;
0081 }
0082 EXPORT_SYMBOL(tty_write_room);
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092 void tty_driver_flush_buffer(struct tty_struct *tty)
0093 {
0094 if (tty->ops->flush_buffer)
0095 tty->ops->flush_buffer(tty);
0096 }
0097 EXPORT_SYMBOL(tty_driver_flush_buffer);
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 void tty_unthrottle(struct tty_struct *tty)
0113 {
0114 down_write(&tty->termios_rwsem);
0115 if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
0116 tty->ops->unthrottle)
0117 tty->ops->unthrottle(tty);
0118 tty->flow_change = 0;
0119 up_write(&tty->termios_rwsem);
0120 }
0121 EXPORT_SYMBOL(tty_unthrottle);
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136 int tty_throttle_safe(struct tty_struct *tty)
0137 {
0138 int ret = 0;
0139
0140 mutex_lock(&tty->throttle_mutex);
0141 if (!tty_throttled(tty)) {
0142 if (tty->flow_change != TTY_THROTTLE_SAFE)
0143 ret = 1;
0144 else {
0145 set_bit(TTY_THROTTLED, &tty->flags);
0146 if (tty->ops->throttle)
0147 tty->ops->throttle(tty);
0148 }
0149 }
0150 mutex_unlock(&tty->throttle_mutex);
0151
0152 return ret;
0153 }
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167 int tty_unthrottle_safe(struct tty_struct *tty)
0168 {
0169 int ret = 0;
0170
0171 mutex_lock(&tty->throttle_mutex);
0172 if (tty_throttled(tty)) {
0173 if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
0174 ret = 1;
0175 else {
0176 clear_bit(TTY_THROTTLED, &tty->flags);
0177 if (tty->ops->unthrottle)
0178 tty->ops->unthrottle(tty);
0179 }
0180 }
0181 mutex_unlock(&tty->throttle_mutex);
0182
0183 return ret;
0184 }
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197 void tty_wait_until_sent(struct tty_struct *tty, long timeout)
0198 {
0199 tty_debug_wait_until_sent(tty, "wait until sent, timeout=%ld\n", timeout);
0200
0201 if (!timeout)
0202 timeout = MAX_SCHEDULE_TIMEOUT;
0203
0204 timeout = wait_event_interruptible_timeout(tty->write_wait,
0205 !tty_chars_in_buffer(tty), timeout);
0206 if (timeout <= 0)
0207 return;
0208
0209 if (timeout == MAX_SCHEDULE_TIMEOUT)
0210 timeout = 0;
0211
0212 if (tty->ops->wait_until_sent)
0213 tty->ops->wait_until_sent(tty, timeout);
0214 }
0215 EXPORT_SYMBOL(tty_wait_until_sent);
0216
0217
0218
0219
0220
0221
0222 static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old)
0223 {
0224 struct ktermios *termios = &tty->termios;
0225 struct ktermios *locked = &tty->termios_locked;
0226 int i;
0227
0228 #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
0229
0230 NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
0231 NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
0232 NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
0233 NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
0234 termios->c_line = locked->c_line ? old->c_line : termios->c_line;
0235 for (i = 0; i < NCCS; i++)
0236 termios->c_cc[i] = locked->c_cc[i] ?
0237 old->c_cc[i] : termios->c_cc[i];
0238
0239 }
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252 void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
0253 {
0254
0255
0256 new->c_cflag &= HUPCL | CREAD | CLOCAL;
0257 new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
0258 new->c_ispeed = old->c_ispeed;
0259 new->c_ospeed = old->c_ospeed;
0260 }
0261 EXPORT_SYMBOL(tty_termios_copy_hw);
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272 int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
0273 {
0274 if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
0275 return 1;
0276 if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
0277 return 1;
0278 return 0;
0279 }
0280 EXPORT_SYMBOL(tty_termios_hw_change);
0281
0282
0283
0284
0285
0286
0287
0288
0289 unsigned char tty_get_char_size(unsigned int cflag)
0290 {
0291 switch (cflag & CSIZE) {
0292 case CS5:
0293 return 5;
0294 case CS6:
0295 return 6;
0296 case CS7:
0297 return 7;
0298 case CS8:
0299 default:
0300 return 8;
0301 }
0302 }
0303 EXPORT_SYMBOL_GPL(tty_get_char_size);
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314 unsigned char tty_get_frame_size(unsigned int cflag)
0315 {
0316 unsigned char bits = 2 + tty_get_char_size(cflag);
0317
0318 if (cflag & CSTOPB)
0319 bits++;
0320 if (cflag & PARENB)
0321 bits++;
0322 if (cflag & ADDRB)
0323 bits++;
0324
0325 return bits;
0326 }
0327 EXPORT_SYMBOL_GPL(tty_get_frame_size);
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340 int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
0341 {
0342 struct ktermios old_termios;
0343 struct tty_ldisc *ld;
0344
0345 WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY &&
0346 tty->driver->subtype == PTY_TYPE_MASTER);
0347
0348
0349
0350
0351
0352
0353
0354 down_write(&tty->termios_rwsem);
0355 old_termios = tty->termios;
0356 tty->termios = *new_termios;
0357 unset_locked_termios(tty, &old_termios);
0358
0359 tty->termios.c_cflag ^= (tty->termios.c_cflag ^ old_termios.c_cflag) & ADDRB;
0360
0361 if (tty->ops->set_termios)
0362 tty->ops->set_termios(tty, &old_termios);
0363 else
0364 tty_termios_copy_hw(&tty->termios, &old_termios);
0365
0366 ld = tty_ldisc_ref(tty);
0367 if (ld != NULL) {
0368 if (ld->ops->set_termios)
0369 ld->ops->set_termios(tty, &old_termios);
0370 tty_ldisc_deref(ld);
0371 }
0372 up_write(&tty->termios_rwsem);
0373 return 0;
0374 }
0375 EXPORT_SYMBOL_GPL(tty_set_termios);
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390 static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
0391 {
0392 struct ktermios tmp_termios;
0393 struct tty_ldisc *ld;
0394 int retval = tty_check_change(tty);
0395
0396 if (retval)
0397 return retval;
0398
0399 down_read(&tty->termios_rwsem);
0400 tmp_termios = tty->termios;
0401 up_read(&tty->termios_rwsem);
0402
0403 if (opt & TERMIOS_TERMIO) {
0404 if (user_termio_to_kernel_termios(&tmp_termios,
0405 (struct termio __user *)arg))
0406 return -EFAULT;
0407 #ifdef TCGETS2
0408 } else if (opt & TERMIOS_OLD) {
0409 if (user_termios_to_kernel_termios_1(&tmp_termios,
0410 (struct termios __user *)arg))
0411 return -EFAULT;
0412 } else {
0413 if (user_termios_to_kernel_termios(&tmp_termios,
0414 (struct termios2 __user *)arg))
0415 return -EFAULT;
0416 }
0417 #else
0418 } else if (user_termios_to_kernel_termios(&tmp_termios,
0419 (struct termios __user *)arg))
0420 return -EFAULT;
0421 #endif
0422
0423
0424
0425 tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
0426 tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
0427
0428 ld = tty_ldisc_ref(tty);
0429
0430 if (ld != NULL) {
0431 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
0432 ld->ops->flush_buffer(tty);
0433 tty_ldisc_deref(ld);
0434 }
0435
0436 if (opt & TERMIOS_WAIT) {
0437 tty_wait_until_sent(tty, 0);
0438 if (signal_pending(current))
0439 return -ERESTARTSYS;
0440 }
0441
0442 tty_set_termios(tty, &tmp_termios);
0443
0444
0445
0446
0447
0448 return 0;
0449 }
0450
0451 static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
0452 {
0453 down_read(&tty->termios_rwsem);
0454 *kterm = tty->termios;
0455 up_read(&tty->termios_rwsem);
0456 }
0457
0458 static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
0459 {
0460 down_read(&tty->termios_rwsem);
0461 *kterm = tty->termios_locked;
0462 up_read(&tty->termios_rwsem);
0463 }
0464
0465 static int get_termio(struct tty_struct *tty, struct termio __user *termio)
0466 {
0467 struct ktermios kterm;
0468 copy_termios(tty, &kterm);
0469 if (kernel_termios_to_user_termio(termio, &kterm))
0470 return -EFAULT;
0471 return 0;
0472 }
0473
0474 #ifdef TIOCGETP
0475
0476
0477
0478
0479
0480 static int get_sgflags(struct tty_struct *tty)
0481 {
0482 int flags = 0;
0483
0484 if (!L_ICANON(tty)) {
0485 if (L_ISIG(tty))
0486 flags |= 0x02;
0487 else
0488 flags |= 0x20;
0489 }
0490 if (L_ECHO(tty))
0491 flags |= 0x08;
0492 if (O_OPOST(tty))
0493 if (O_ONLCR(tty))
0494 flags |= 0x10;
0495 return flags;
0496 }
0497
0498 static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
0499 {
0500 struct sgttyb tmp;
0501
0502 down_read(&tty->termios_rwsem);
0503 tmp.sg_ispeed = tty->termios.c_ispeed;
0504 tmp.sg_ospeed = tty->termios.c_ospeed;
0505 tmp.sg_erase = tty->termios.c_cc[VERASE];
0506 tmp.sg_kill = tty->termios.c_cc[VKILL];
0507 tmp.sg_flags = get_sgflags(tty);
0508 up_read(&tty->termios_rwsem);
0509
0510 return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
0511 }
0512
0513 static void set_sgflags(struct ktermios *termios, int flags)
0514 {
0515 termios->c_iflag = ICRNL | IXON;
0516 termios->c_oflag = 0;
0517 termios->c_lflag = ISIG | ICANON;
0518 if (flags & 0x02) {
0519 termios->c_iflag = 0;
0520 termios->c_lflag &= ~ICANON;
0521 }
0522 if (flags & 0x08) {
0523 termios->c_lflag |= ECHO | ECHOE | ECHOK |
0524 ECHOCTL | ECHOKE | IEXTEN;
0525 }
0526 if (flags & 0x10) {
0527 termios->c_oflag |= OPOST | ONLCR;
0528 }
0529 if (flags & 0x20) {
0530 termios->c_iflag = 0;
0531 termios->c_lflag &= ~(ISIG | ICANON);
0532 }
0533 if (!(termios->c_lflag & ICANON)) {
0534 termios->c_cc[VMIN] = 1;
0535 termios->c_cc[VTIME] = 0;
0536 }
0537 }
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550 static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
0551 {
0552 int retval;
0553 struct sgttyb tmp;
0554 struct ktermios termios;
0555
0556 retval = tty_check_change(tty);
0557 if (retval)
0558 return retval;
0559
0560 if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
0561 return -EFAULT;
0562
0563 down_write(&tty->termios_rwsem);
0564 termios = tty->termios;
0565 termios.c_cc[VERASE] = tmp.sg_erase;
0566 termios.c_cc[VKILL] = tmp.sg_kill;
0567 set_sgflags(&termios, tmp.sg_flags);
0568
0569 tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
0570 termios.c_ospeed);
0571 up_write(&tty->termios_rwsem);
0572 tty_set_termios(tty, &termios);
0573 return 0;
0574 }
0575 #endif
0576
0577 #ifdef TIOCGETC
0578 static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
0579 {
0580 struct tchars tmp;
0581
0582 down_read(&tty->termios_rwsem);
0583 tmp.t_intrc = tty->termios.c_cc[VINTR];
0584 tmp.t_quitc = tty->termios.c_cc[VQUIT];
0585 tmp.t_startc = tty->termios.c_cc[VSTART];
0586 tmp.t_stopc = tty->termios.c_cc[VSTOP];
0587 tmp.t_eofc = tty->termios.c_cc[VEOF];
0588 tmp.t_brkc = tty->termios.c_cc[VEOL2];
0589 up_read(&tty->termios_rwsem);
0590 return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
0591 }
0592
0593 static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
0594 {
0595 struct tchars tmp;
0596
0597 if (copy_from_user(&tmp, tchars, sizeof(tmp)))
0598 return -EFAULT;
0599 down_write(&tty->termios_rwsem);
0600 tty->termios.c_cc[VINTR] = tmp.t_intrc;
0601 tty->termios.c_cc[VQUIT] = tmp.t_quitc;
0602 tty->termios.c_cc[VSTART] = tmp.t_startc;
0603 tty->termios.c_cc[VSTOP] = tmp.t_stopc;
0604 tty->termios.c_cc[VEOF] = tmp.t_eofc;
0605 tty->termios.c_cc[VEOL2] = tmp.t_brkc;
0606 up_write(&tty->termios_rwsem);
0607 return 0;
0608 }
0609 #endif
0610
0611 #ifdef TIOCGLTC
0612 static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
0613 {
0614 struct ltchars tmp;
0615
0616 down_read(&tty->termios_rwsem);
0617 tmp.t_suspc = tty->termios.c_cc[VSUSP];
0618
0619 tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
0620 tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
0621
0622 tmp.t_flushc = tty->termios.c_cc[VEOL2];
0623 tmp.t_werasc = tty->termios.c_cc[VWERASE];
0624 tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
0625 up_read(&tty->termios_rwsem);
0626 return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
0627 }
0628
0629 static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
0630 {
0631 struct ltchars tmp;
0632
0633 if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
0634 return -EFAULT;
0635
0636 down_write(&tty->termios_rwsem);
0637 tty->termios.c_cc[VSUSP] = tmp.t_suspc;
0638
0639 tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
0640 tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
0641
0642 tty->termios.c_cc[VEOL2] = tmp.t_flushc;
0643 tty->termios.c_cc[VWERASE] = tmp.t_werasc;
0644 tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
0645 up_write(&tty->termios_rwsem);
0646 return 0;
0647 }
0648 #endif
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659 static int tty_change_softcar(struct tty_struct *tty, int arg)
0660 {
0661 int ret = 0;
0662 int bit = arg ? CLOCAL : 0;
0663 struct ktermios old;
0664
0665 down_write(&tty->termios_rwsem);
0666 old = tty->termios;
0667 tty->termios.c_cflag &= ~CLOCAL;
0668 tty->termios.c_cflag |= bit;
0669 if (tty->ops->set_termios)
0670 tty->ops->set_termios(tty, &old);
0671 if (C_CLOCAL(tty) != bit)
0672 ret = -EINVAL;
0673 up_write(&tty->termios_rwsem);
0674 return ret;
0675 }
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688 int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
0689 {
0690 struct tty_struct *real_tty;
0691 void __user *p = (void __user *)arg;
0692 int ret = 0;
0693 struct ktermios kterm;
0694
0695 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
0696 tty->driver->subtype == PTY_TYPE_MASTER)
0697 real_tty = tty->link;
0698 else
0699 real_tty = tty;
0700
0701 switch (cmd) {
0702 #ifdef TIOCGETP
0703 case TIOCGETP:
0704 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
0705 case TIOCSETP:
0706 case TIOCSETN:
0707 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
0708 #endif
0709 #ifdef TIOCGETC
0710 case TIOCGETC:
0711 return get_tchars(real_tty, p);
0712 case TIOCSETC:
0713 return set_tchars(real_tty, p);
0714 #endif
0715 #ifdef TIOCGLTC
0716 case TIOCGLTC:
0717 return get_ltchars(real_tty, p);
0718 case TIOCSLTC:
0719 return set_ltchars(real_tty, p);
0720 #endif
0721 case TCSETSF:
0722 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
0723 case TCSETSW:
0724 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
0725 case TCSETS:
0726 return set_termios(real_tty, p, TERMIOS_OLD);
0727 #ifndef TCGETS2
0728 case TCGETS:
0729 copy_termios(real_tty, &kterm);
0730 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
0731 ret = -EFAULT;
0732 return ret;
0733 #else
0734 case TCGETS:
0735 copy_termios(real_tty, &kterm);
0736 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
0737 ret = -EFAULT;
0738 return ret;
0739 case TCGETS2:
0740 copy_termios(real_tty, &kterm);
0741 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
0742 ret = -EFAULT;
0743 return ret;
0744 case TCSETSF2:
0745 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
0746 case TCSETSW2:
0747 return set_termios(real_tty, p, TERMIOS_WAIT);
0748 case TCSETS2:
0749 return set_termios(real_tty, p, 0);
0750 #endif
0751 case TCGETA:
0752 return get_termio(real_tty, p);
0753 case TCSETAF:
0754 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
0755 case TCSETAW:
0756 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
0757 case TCSETA:
0758 return set_termios(real_tty, p, TERMIOS_TERMIO);
0759 #ifndef TCGETS2
0760 case TIOCGLCKTRMIOS:
0761 copy_termios_locked(real_tty, &kterm);
0762 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
0763 ret = -EFAULT;
0764 return ret;
0765 case TIOCSLCKTRMIOS:
0766 if (!capable(CAP_SYS_ADMIN))
0767 return -EPERM;
0768 copy_termios_locked(real_tty, &kterm);
0769 if (user_termios_to_kernel_termios(&kterm,
0770 (struct termios __user *) arg))
0771 return -EFAULT;
0772 down_write(&real_tty->termios_rwsem);
0773 real_tty->termios_locked = kterm;
0774 up_write(&real_tty->termios_rwsem);
0775 return 0;
0776 #else
0777 case TIOCGLCKTRMIOS:
0778 copy_termios_locked(real_tty, &kterm);
0779 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
0780 ret = -EFAULT;
0781 return ret;
0782 case TIOCSLCKTRMIOS:
0783 if (!capable(CAP_SYS_ADMIN))
0784 return -EPERM;
0785 copy_termios_locked(real_tty, &kterm);
0786 if (user_termios_to_kernel_termios_1(&kterm,
0787 (struct termios __user *) arg))
0788 return -EFAULT;
0789 down_write(&real_tty->termios_rwsem);
0790 real_tty->termios_locked = kterm;
0791 up_write(&real_tty->termios_rwsem);
0792 return ret;
0793 #endif
0794 #ifdef TCGETX
0795 case TCGETX:
0796 case TCSETX:
0797 case TCSETXW:
0798 case TCSETXF:
0799 return -ENOTTY;
0800 #endif
0801 case TIOCGSOFTCAR:
0802 copy_termios(real_tty, &kterm);
0803 ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
0804 (int __user *)arg);
0805 return ret;
0806 case TIOCSSOFTCAR:
0807 if (get_user(arg, (unsigned int __user *) arg))
0808 return -EFAULT;
0809 return tty_change_softcar(real_tty, arg);
0810 default:
0811 return -ENOIOCTLCMD;
0812 }
0813 }
0814 EXPORT_SYMBOL_GPL(tty_mode_ioctl);
0815
0816
0817
0818 static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
0819 {
0820 struct tty_ldisc *ld = tty->ldisc;
0821
0822 switch (arg) {
0823 case TCIFLUSH:
0824 if (ld && ld->ops->flush_buffer) {
0825 ld->ops->flush_buffer(tty);
0826 tty_unthrottle(tty);
0827 }
0828 break;
0829 case TCIOFLUSH:
0830 if (ld && ld->ops->flush_buffer) {
0831 ld->ops->flush_buffer(tty);
0832 tty_unthrottle(tty);
0833 }
0834 fallthrough;
0835 case TCOFLUSH:
0836 tty_driver_flush_buffer(tty);
0837 break;
0838 default:
0839 return -EINVAL;
0840 }
0841 return 0;
0842 }
0843
0844 int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
0845 {
0846 struct tty_ldisc *ld;
0847 int retval = tty_check_change(tty);
0848 if (retval)
0849 return retval;
0850
0851 ld = tty_ldisc_ref_wait(tty);
0852 retval = __tty_perform_flush(tty, arg);
0853 if (ld)
0854 tty_ldisc_deref(ld);
0855 return retval;
0856 }
0857 EXPORT_SYMBOL_GPL(tty_perform_flush);
0858
0859 int n_tty_ioctl_helper(struct tty_struct *tty, unsigned int cmd,
0860 unsigned long arg)
0861 {
0862 int retval;
0863
0864 switch (cmd) {
0865 case TCXONC:
0866 retval = tty_check_change(tty);
0867 if (retval)
0868 return retval;
0869 switch (arg) {
0870 case TCOOFF:
0871 spin_lock_irq(&tty->flow.lock);
0872 if (!tty->flow.tco_stopped) {
0873 tty->flow.tco_stopped = true;
0874 __stop_tty(tty);
0875 }
0876 spin_unlock_irq(&tty->flow.lock);
0877 break;
0878 case TCOON:
0879 spin_lock_irq(&tty->flow.lock);
0880 if (tty->flow.tco_stopped) {
0881 tty->flow.tco_stopped = false;
0882 __start_tty(tty);
0883 }
0884 spin_unlock_irq(&tty->flow.lock);
0885 break;
0886 case TCIOFF:
0887 if (STOP_CHAR(tty) != __DISABLED_CHAR)
0888 retval = tty_send_xchar(tty, STOP_CHAR(tty));
0889 break;
0890 case TCION:
0891 if (START_CHAR(tty) != __DISABLED_CHAR)
0892 retval = tty_send_xchar(tty, START_CHAR(tty));
0893 break;
0894 default:
0895 return -EINVAL;
0896 }
0897 return retval;
0898 case TCFLSH:
0899 retval = tty_check_change(tty);
0900 if (retval)
0901 return retval;
0902 return __tty_perform_flush(tty, arg);
0903 default:
0904
0905 return tty_mode_ioctl(tty, cmd, arg);
0906 }
0907 }
0908 EXPORT_SYMBOL(n_tty_ioctl_helper);