18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines 68c2ecf20Sopenharmony_ci * which can be dynamically activated and de-activated by the line 78c2ecf20Sopenharmony_ci * discipline handling modules (like SLIP). 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/types.h> 118c2ecf20Sopenharmony_ci#include <linux/termios.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/major.h> 168c2ecf20Sopenharmony_ci#include <linux/tty.h> 178c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 188c2ecf20Sopenharmony_ci#include <linux/string.h> 198c2ecf20Sopenharmony_ci#include <linux/mm.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/bitops.h> 228c2ecf20Sopenharmony_ci#include <linux/mutex.h> 238c2ecf20Sopenharmony_ci#include <linux/compat.h> 248c2ecf20Sopenharmony_ci#include "tty.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <asm/io.h> 278c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#undef TTY_DEBUG_WAIT_UNTIL_SENT 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#ifdef TTY_DEBUG_WAIT_UNTIL_SENT 328c2ecf20Sopenharmony_ci# define tty_debug_wait_until_sent(tty, f, args...) tty_debug(tty, f, ##args) 338c2ecf20Sopenharmony_ci#else 348c2ecf20Sopenharmony_ci# define tty_debug_wait_until_sent(tty, f, args...) do {} while (0) 358c2ecf20Sopenharmony_ci#endif 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#undef DEBUG 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Internal flag options for termios setting behavior 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci#define TERMIOS_FLUSH 1 438c2ecf20Sopenharmony_ci#define TERMIOS_WAIT 2 448c2ecf20Sopenharmony_ci#define TERMIOS_TERMIO 4 458c2ecf20Sopenharmony_ci#define TERMIOS_OLD 8 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/** 498c2ecf20Sopenharmony_ci * tty_chars_in_buffer - characters pending 508c2ecf20Sopenharmony_ci * @tty: terminal 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * Return the number of bytes of data in the device private 538c2ecf20Sopenharmony_ci * output queue. If no private method is supplied there is assumed 548c2ecf20Sopenharmony_ci * to be no queue on the device. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciint tty_chars_in_buffer(struct tty_struct *tty) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci if (tty->ops->chars_in_buffer) 608c2ecf20Sopenharmony_ci return tty->ops->chars_in_buffer(tty); 618c2ecf20Sopenharmony_ci else 628c2ecf20Sopenharmony_ci return 0; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_chars_in_buffer); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * tty_write_room - write queue space 688c2ecf20Sopenharmony_ci * @tty: terminal 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * Return the number of bytes that can be queued to this device 718c2ecf20Sopenharmony_ci * at the present time. The result should be treated as a guarantee 728c2ecf20Sopenharmony_ci * and the driver cannot offer a value it later shrinks by more than 738c2ecf20Sopenharmony_ci * the number of bytes written. If no method is provided 2K is always 748c2ecf20Sopenharmony_ci * returned and data may be lost as there will be no flow control. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciint tty_write_room(struct tty_struct *tty) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci if (tty->ops->write_room) 808c2ecf20Sopenharmony_ci return tty->ops->write_room(tty); 818c2ecf20Sopenharmony_ci return 2048; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_write_room); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/** 868c2ecf20Sopenharmony_ci * tty_driver_flush_buffer - discard internal buffer 878c2ecf20Sopenharmony_ci * @tty: terminal 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * Discard the internal output buffer for this device. If no method 908c2ecf20Sopenharmony_ci * is provided then either the buffer cannot be hardware flushed or 918c2ecf20Sopenharmony_ci * there is no buffer driver side. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_civoid tty_driver_flush_buffer(struct tty_struct *tty) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci if (tty->ops->flush_buffer) 968c2ecf20Sopenharmony_ci tty->ops->flush_buffer(tty); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_driver_flush_buffer); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/** 1018c2ecf20Sopenharmony_ci * tty_throttle - flow control 1028c2ecf20Sopenharmony_ci * @tty: terminal 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * Indicate that a tty should stop transmitting data down the stack. 1058c2ecf20Sopenharmony_ci * Takes the termios rwsem to protect against parallel throttle/unthrottle 1068c2ecf20Sopenharmony_ci * and also to ensure the driver can consistently reference its own 1078c2ecf20Sopenharmony_ci * termios data at this point when implementing software flow control. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_civoid tty_throttle(struct tty_struct *tty) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci down_write(&tty->termios_rwsem); 1138c2ecf20Sopenharmony_ci /* check TTY_THROTTLED first so it indicates our state */ 1148c2ecf20Sopenharmony_ci if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && 1158c2ecf20Sopenharmony_ci tty->ops->throttle) 1168c2ecf20Sopenharmony_ci tty->ops->throttle(tty); 1178c2ecf20Sopenharmony_ci tty->flow_change = 0; 1188c2ecf20Sopenharmony_ci up_write(&tty->termios_rwsem); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_throttle); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/** 1238c2ecf20Sopenharmony_ci * tty_unthrottle - flow control 1248c2ecf20Sopenharmony_ci * @tty: terminal 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * Indicate that a tty may continue transmitting data down the stack. 1278c2ecf20Sopenharmony_ci * Takes the termios rwsem to protect against parallel throttle/unthrottle 1288c2ecf20Sopenharmony_ci * and also to ensure the driver can consistently reference its own 1298c2ecf20Sopenharmony_ci * termios data at this point when implementing software flow control. 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci * Drivers should however remember that the stack can issue a throttle, 1328c2ecf20Sopenharmony_ci * then change flow control method, then unthrottle. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_civoid tty_unthrottle(struct tty_struct *tty) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci down_write(&tty->termios_rwsem); 1388c2ecf20Sopenharmony_ci if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && 1398c2ecf20Sopenharmony_ci tty->ops->unthrottle) 1408c2ecf20Sopenharmony_ci tty->ops->unthrottle(tty); 1418c2ecf20Sopenharmony_ci tty->flow_change = 0; 1428c2ecf20Sopenharmony_ci up_write(&tty->termios_rwsem); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_unthrottle); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/** 1478c2ecf20Sopenharmony_ci * tty_throttle_safe - flow control 1488c2ecf20Sopenharmony_ci * @tty: terminal 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * Similar to tty_throttle() but will only attempt throttle 1518c2ecf20Sopenharmony_ci * if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental 1528c2ecf20Sopenharmony_ci * throttle due to race conditions when throttling is conditional 1538c2ecf20Sopenharmony_ci * on factors evaluated prior to throttling. 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * Returns 0 if tty is throttled (or was already throttled) 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ciint tty_throttle_safe(struct tty_struct *tty) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci int ret = 0; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci mutex_lock(&tty->throttle_mutex); 1638c2ecf20Sopenharmony_ci if (!tty_throttled(tty)) { 1648c2ecf20Sopenharmony_ci if (tty->flow_change != TTY_THROTTLE_SAFE) 1658c2ecf20Sopenharmony_ci ret = 1; 1668c2ecf20Sopenharmony_ci else { 1678c2ecf20Sopenharmony_ci set_bit(TTY_THROTTLED, &tty->flags); 1688c2ecf20Sopenharmony_ci if (tty->ops->throttle) 1698c2ecf20Sopenharmony_ci tty->ops->throttle(tty); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci mutex_unlock(&tty->throttle_mutex); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return ret; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/** 1788c2ecf20Sopenharmony_ci * tty_unthrottle_safe - flow control 1798c2ecf20Sopenharmony_ci * @tty: terminal 1808c2ecf20Sopenharmony_ci * 1818c2ecf20Sopenharmony_ci * Similar to tty_unthrottle() but will only attempt unthrottle 1828c2ecf20Sopenharmony_ci * if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental 1838c2ecf20Sopenharmony_ci * unthrottle due to race conditions when unthrottling is conditional 1848c2ecf20Sopenharmony_ci * on factors evaluated prior to unthrottling. 1858c2ecf20Sopenharmony_ci * 1868c2ecf20Sopenharmony_ci * Returns 0 if tty is unthrottled (or was already unthrottled) 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ciint tty_unthrottle_safe(struct tty_struct *tty) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci int ret = 0; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci mutex_lock(&tty->throttle_mutex); 1948c2ecf20Sopenharmony_ci if (tty_throttled(tty)) { 1958c2ecf20Sopenharmony_ci if (tty->flow_change != TTY_UNTHROTTLE_SAFE) 1968c2ecf20Sopenharmony_ci ret = 1; 1978c2ecf20Sopenharmony_ci else { 1988c2ecf20Sopenharmony_ci clear_bit(TTY_THROTTLED, &tty->flags); 1998c2ecf20Sopenharmony_ci if (tty->ops->unthrottle) 2008c2ecf20Sopenharmony_ci tty->ops->unthrottle(tty); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci mutex_unlock(&tty->throttle_mutex); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return ret; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/** 2098c2ecf20Sopenharmony_ci * tty_wait_until_sent - wait for I/O to finish 2108c2ecf20Sopenharmony_ci * @tty: tty we are waiting for 2118c2ecf20Sopenharmony_ci * @timeout: how long we will wait 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * Wait for characters pending in a tty driver to hit the wire, or 2148c2ecf20Sopenharmony_ci * for a timeout to occur (eg due to flow control) 2158c2ecf20Sopenharmony_ci * 2168c2ecf20Sopenharmony_ci * Locking: none 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_civoid tty_wait_until_sent(struct tty_struct *tty, long timeout) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci tty_debug_wait_until_sent(tty, "wait until sent, timeout=%ld\n", timeout); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (!timeout) 2248c2ecf20Sopenharmony_ci timeout = MAX_SCHEDULE_TIMEOUT; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci timeout = wait_event_interruptible_timeout(tty->write_wait, 2278c2ecf20Sopenharmony_ci !tty_chars_in_buffer(tty), timeout); 2288c2ecf20Sopenharmony_ci if (timeout <= 0) 2298c2ecf20Sopenharmony_ci return; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (timeout == MAX_SCHEDULE_TIMEOUT) 2328c2ecf20Sopenharmony_ci timeout = 0; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (tty->ops->wait_until_sent) 2358c2ecf20Sopenharmony_ci tty->ops->wait_until_sent(tty, timeout); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_wait_until_sent); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/* 2418c2ecf20Sopenharmony_ci * Termios Helper Methods 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void unset_locked_termios(struct tty_struct *tty, struct ktermios *old) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct ktermios *termios = &tty->termios; 2478c2ecf20Sopenharmony_ci struct ktermios *locked = &tty->termios_locked; 2488c2ecf20Sopenharmony_ci int i; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z))) 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag); 2538c2ecf20Sopenharmony_ci NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag); 2548c2ecf20Sopenharmony_ci NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag); 2558c2ecf20Sopenharmony_ci NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag); 2568c2ecf20Sopenharmony_ci termios->c_line = locked->c_line ? old->c_line : termios->c_line; 2578c2ecf20Sopenharmony_ci for (i = 0; i < NCCS; i++) 2588c2ecf20Sopenharmony_ci termios->c_cc[i] = locked->c_cc[i] ? 2598c2ecf20Sopenharmony_ci old->c_cc[i] : termios->c_cc[i]; 2608c2ecf20Sopenharmony_ci /* FIXME: What should we do for i/ospeed */ 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/** 2648c2ecf20Sopenharmony_ci * tty_termios_copy_hw - copy hardware settings 2658c2ecf20Sopenharmony_ci * @new: New termios 2668c2ecf20Sopenharmony_ci * @old: Old termios 2678c2ecf20Sopenharmony_ci * 2688c2ecf20Sopenharmony_ci * Propagate the hardware specific terminal setting bits from 2698c2ecf20Sopenharmony_ci * the old termios structure to the new one. This is used in cases 2708c2ecf20Sopenharmony_ci * where the hardware does not support reconfiguration or as a helper 2718c2ecf20Sopenharmony_ci * in some cases where only minimal reconfiguration is supported 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_civoid tty_termios_copy_hw(struct ktermios *new, struct ktermios *old) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci /* The bits a dumb device handles in software. Smart devices need 2778c2ecf20Sopenharmony_ci to always provide a set_termios method */ 2788c2ecf20Sopenharmony_ci new->c_cflag &= HUPCL | CREAD | CLOCAL; 2798c2ecf20Sopenharmony_ci new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL); 2808c2ecf20Sopenharmony_ci new->c_ispeed = old->c_ispeed; 2818c2ecf20Sopenharmony_ci new->c_ospeed = old->c_ospeed; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_termios_copy_hw); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/** 2868c2ecf20Sopenharmony_ci * tty_termios_hw_change - check for setting change 2878c2ecf20Sopenharmony_ci * @a: termios 2888c2ecf20Sopenharmony_ci * @b: termios to compare 2898c2ecf20Sopenharmony_ci * 2908c2ecf20Sopenharmony_ci * Check if any of the bits that affect a dumb device have changed 2918c2ecf20Sopenharmony_ci * between the two termios structures, or a speed change is needed. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciint tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed) 2978c2ecf20Sopenharmony_ci return 1; 2988c2ecf20Sopenharmony_ci if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL)) 2998c2ecf20Sopenharmony_ci return 1; 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tty_termios_hw_change); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/** 3058c2ecf20Sopenharmony_ci * tty_set_termios - update termios values 3068c2ecf20Sopenharmony_ci * @tty: tty to update 3078c2ecf20Sopenharmony_ci * @new_termios: desired new value 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * Perform updates to the termios values set on this terminal. 3108c2ecf20Sopenharmony_ci * A master pty's termios should never be set. 3118c2ecf20Sopenharmony_ci * 3128c2ecf20Sopenharmony_ci * Locking: termios_rwsem 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ciint tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct ktermios old_termios; 3188c2ecf20Sopenharmony_ci struct tty_ldisc *ld; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY && 3218c2ecf20Sopenharmony_ci tty->driver->subtype == PTY_TYPE_MASTER); 3228c2ecf20Sopenharmony_ci /* 3238c2ecf20Sopenharmony_ci * Perform the actual termios internal changes under lock. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* FIXME: we need to decide on some locking/ordering semantics 3288c2ecf20Sopenharmony_ci for the set_termios notification eventually */ 3298c2ecf20Sopenharmony_ci down_write(&tty->termios_rwsem); 3308c2ecf20Sopenharmony_ci old_termios = tty->termios; 3318c2ecf20Sopenharmony_ci tty->termios = *new_termios; 3328c2ecf20Sopenharmony_ci unset_locked_termios(tty, &old_termios); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (tty->ops->set_termios) 3358c2ecf20Sopenharmony_ci tty->ops->set_termios(tty, &old_termios); 3368c2ecf20Sopenharmony_ci else 3378c2ecf20Sopenharmony_ci tty_termios_copy_hw(&tty->termios, &old_termios); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci ld = tty_ldisc_ref(tty); 3408c2ecf20Sopenharmony_ci if (ld != NULL) { 3418c2ecf20Sopenharmony_ci if (ld->ops->set_termios) 3428c2ecf20Sopenharmony_ci ld->ops->set_termios(tty, &old_termios); 3438c2ecf20Sopenharmony_ci tty_ldisc_deref(ld); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci up_write(&tty->termios_rwsem); 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_set_termios); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/** 3518c2ecf20Sopenharmony_ci * set_termios - set termios values for a tty 3528c2ecf20Sopenharmony_ci * @tty: terminal device 3538c2ecf20Sopenharmony_ci * @arg: user data 3548c2ecf20Sopenharmony_ci * @opt: option information 3558c2ecf20Sopenharmony_ci * 3568c2ecf20Sopenharmony_ci * Helper function to prepare termios data and run necessary other 3578c2ecf20Sopenharmony_ci * functions before using tty_set_termios to do the actual changes. 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * Locking: 3608c2ecf20Sopenharmony_ci * Called functions take ldisc and termios_rwsem locks 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int set_termios(struct tty_struct *tty, void __user *arg, int opt) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct ktermios tmp_termios; 3668c2ecf20Sopenharmony_ci struct tty_ldisc *ld; 3678c2ecf20Sopenharmony_ci int retval = tty_check_change(tty); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (retval) 3708c2ecf20Sopenharmony_ci return retval; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci down_read(&tty->termios_rwsem); 3738c2ecf20Sopenharmony_ci tmp_termios = tty->termios; 3748c2ecf20Sopenharmony_ci up_read(&tty->termios_rwsem); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (opt & TERMIOS_TERMIO) { 3778c2ecf20Sopenharmony_ci if (user_termio_to_kernel_termios(&tmp_termios, 3788c2ecf20Sopenharmony_ci (struct termio __user *)arg)) 3798c2ecf20Sopenharmony_ci return -EFAULT; 3808c2ecf20Sopenharmony_ci#ifdef TCGETS2 3818c2ecf20Sopenharmony_ci } else if (opt & TERMIOS_OLD) { 3828c2ecf20Sopenharmony_ci if (user_termios_to_kernel_termios_1(&tmp_termios, 3838c2ecf20Sopenharmony_ci (struct termios __user *)arg)) 3848c2ecf20Sopenharmony_ci return -EFAULT; 3858c2ecf20Sopenharmony_ci } else { 3868c2ecf20Sopenharmony_ci if (user_termios_to_kernel_termios(&tmp_termios, 3878c2ecf20Sopenharmony_ci (struct termios2 __user *)arg)) 3888c2ecf20Sopenharmony_ci return -EFAULT; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci#else 3918c2ecf20Sopenharmony_ci } else if (user_termios_to_kernel_termios(&tmp_termios, 3928c2ecf20Sopenharmony_ci (struct termios __user *)arg)) 3938c2ecf20Sopenharmony_ci return -EFAULT; 3948c2ecf20Sopenharmony_ci#endif 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* If old style Bfoo values are used then load c_ispeed/c_ospeed 3978c2ecf20Sopenharmony_ci * with the real speed so its unconditionally usable */ 3988c2ecf20Sopenharmony_ci tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); 3998c2ecf20Sopenharmony_ci tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (opt & (TERMIOS_FLUSH|TERMIOS_WAIT)) { 4028c2ecf20Sopenharmony_ciretry_write_wait: 4038c2ecf20Sopenharmony_ci retval = wait_event_interruptible(tty->write_wait, !tty_chars_in_buffer(tty)); 4048c2ecf20Sopenharmony_ci if (retval < 0) 4058c2ecf20Sopenharmony_ci return retval; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (tty_write_lock(tty, false) < 0) 4088c2ecf20Sopenharmony_ci goto retry_write_wait; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci /* Racing writer? */ 4118c2ecf20Sopenharmony_ci if (tty_chars_in_buffer(tty)) { 4128c2ecf20Sopenharmony_ci tty_write_unlock(tty); 4138c2ecf20Sopenharmony_ci goto retry_write_wait; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci ld = tty_ldisc_ref(tty); 4178c2ecf20Sopenharmony_ci if (ld != NULL) { 4188c2ecf20Sopenharmony_ci if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) 4198c2ecf20Sopenharmony_ci ld->ops->flush_buffer(tty); 4208c2ecf20Sopenharmony_ci tty_ldisc_deref(ld); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if ((opt & TERMIOS_WAIT) && tty->ops->wait_until_sent) { 4248c2ecf20Sopenharmony_ci tty->ops->wait_until_sent(tty, 0); 4258c2ecf20Sopenharmony_ci if (signal_pending(current)) { 4268c2ecf20Sopenharmony_ci tty_write_unlock(tty); 4278c2ecf20Sopenharmony_ci return -ERESTARTSYS; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci tty_set_termios(tty, &tmp_termios); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci tty_write_unlock(tty); 4348c2ecf20Sopenharmony_ci } else { 4358c2ecf20Sopenharmony_ci tty_set_termios(tty, &tmp_termios); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* FIXME: Arguably if tmp_termios == tty->termios AND the 4398c2ecf20Sopenharmony_ci actual requested termios was not tmp_termios then we may 4408c2ecf20Sopenharmony_ci want to return an error as no user requested change has 4418c2ecf20Sopenharmony_ci succeeded */ 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void copy_termios(struct tty_struct *tty, struct ktermios *kterm) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci down_read(&tty->termios_rwsem); 4488c2ecf20Sopenharmony_ci *kterm = tty->termios; 4498c2ecf20Sopenharmony_ci up_read(&tty->termios_rwsem); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci down_read(&tty->termios_rwsem); 4558c2ecf20Sopenharmony_ci *kterm = tty->termios_locked; 4568c2ecf20Sopenharmony_ci up_read(&tty->termios_rwsem); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int get_termio(struct tty_struct *tty, struct termio __user *termio) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct ktermios kterm; 4628c2ecf20Sopenharmony_ci copy_termios(tty, &kterm); 4638c2ecf20Sopenharmony_ci if (kernel_termios_to_user_termio(termio, &kterm)) 4648c2ecf20Sopenharmony_ci return -EFAULT; 4658c2ecf20Sopenharmony_ci return 0; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci#ifdef TIOCGETP 4698c2ecf20Sopenharmony_ci/* 4708c2ecf20Sopenharmony_ci * These are deprecated, but there is limited support.. 4718c2ecf20Sopenharmony_ci * 4728c2ecf20Sopenharmony_ci * The "sg_flags" translation is a joke.. 4738c2ecf20Sopenharmony_ci */ 4748c2ecf20Sopenharmony_cistatic int get_sgflags(struct tty_struct *tty) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci int flags = 0; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (!L_ICANON(tty)) { 4798c2ecf20Sopenharmony_ci if (L_ISIG(tty)) 4808c2ecf20Sopenharmony_ci flags |= 0x02; /* cbreak */ 4818c2ecf20Sopenharmony_ci else 4828c2ecf20Sopenharmony_ci flags |= 0x20; /* raw */ 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci if (L_ECHO(tty)) 4858c2ecf20Sopenharmony_ci flags |= 0x08; /* echo */ 4868c2ecf20Sopenharmony_ci if (O_OPOST(tty)) 4878c2ecf20Sopenharmony_ci if (O_ONLCR(tty)) 4888c2ecf20Sopenharmony_ci flags |= 0x10; /* crmod */ 4898c2ecf20Sopenharmony_ci return flags; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct sgttyb tmp; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci down_read(&tty->termios_rwsem); 4978c2ecf20Sopenharmony_ci tmp.sg_ispeed = tty->termios.c_ispeed; 4988c2ecf20Sopenharmony_ci tmp.sg_ospeed = tty->termios.c_ospeed; 4998c2ecf20Sopenharmony_ci tmp.sg_erase = tty->termios.c_cc[VERASE]; 5008c2ecf20Sopenharmony_ci tmp.sg_kill = tty->termios.c_cc[VKILL]; 5018c2ecf20Sopenharmony_ci tmp.sg_flags = get_sgflags(tty); 5028c2ecf20Sopenharmony_ci up_read(&tty->termios_rwsem); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic void set_sgflags(struct ktermios *termios, int flags) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci termios->c_iflag = ICRNL | IXON; 5108c2ecf20Sopenharmony_ci termios->c_oflag = 0; 5118c2ecf20Sopenharmony_ci termios->c_lflag = ISIG | ICANON; 5128c2ecf20Sopenharmony_ci if (flags & 0x02) { /* cbreak */ 5138c2ecf20Sopenharmony_ci termios->c_iflag = 0; 5148c2ecf20Sopenharmony_ci termios->c_lflag &= ~ICANON; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci if (flags & 0x08) { /* echo */ 5178c2ecf20Sopenharmony_ci termios->c_lflag |= ECHO | ECHOE | ECHOK | 5188c2ecf20Sopenharmony_ci ECHOCTL | ECHOKE | IEXTEN; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci if (flags & 0x10) { /* crmod */ 5218c2ecf20Sopenharmony_ci termios->c_oflag |= OPOST | ONLCR; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci if (flags & 0x20) { /* raw */ 5248c2ecf20Sopenharmony_ci termios->c_iflag = 0; 5258c2ecf20Sopenharmony_ci termios->c_lflag &= ~(ISIG | ICANON); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci if (!(termios->c_lflag & ICANON)) { 5288c2ecf20Sopenharmony_ci termios->c_cc[VMIN] = 1; 5298c2ecf20Sopenharmony_ci termios->c_cc[VTIME] = 0; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/** 5348c2ecf20Sopenharmony_ci * set_sgttyb - set legacy terminal values 5358c2ecf20Sopenharmony_ci * @tty: tty structure 5368c2ecf20Sopenharmony_ci * @sgttyb: pointer to old style terminal structure 5378c2ecf20Sopenharmony_ci * 5388c2ecf20Sopenharmony_ci * Updates a terminal from the legacy BSD style terminal information 5398c2ecf20Sopenharmony_ci * structure. 5408c2ecf20Sopenharmony_ci * 5418c2ecf20Sopenharmony_ci * Locking: termios_rwsem 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci int retval; 5478c2ecf20Sopenharmony_ci struct sgttyb tmp; 5488c2ecf20Sopenharmony_ci struct ktermios termios; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci retval = tty_check_change(tty); 5518c2ecf20Sopenharmony_ci if (retval) 5528c2ecf20Sopenharmony_ci return retval; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) 5558c2ecf20Sopenharmony_ci return -EFAULT; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci down_write(&tty->termios_rwsem); 5588c2ecf20Sopenharmony_ci termios = tty->termios; 5598c2ecf20Sopenharmony_ci termios.c_cc[VERASE] = tmp.sg_erase; 5608c2ecf20Sopenharmony_ci termios.c_cc[VKILL] = tmp.sg_kill; 5618c2ecf20Sopenharmony_ci set_sgflags(&termios, tmp.sg_flags); 5628c2ecf20Sopenharmony_ci /* Try and encode into Bfoo format */ 5638c2ecf20Sopenharmony_ci#ifdef BOTHER 5648c2ecf20Sopenharmony_ci tty_termios_encode_baud_rate(&termios, termios.c_ispeed, 5658c2ecf20Sopenharmony_ci termios.c_ospeed); 5668c2ecf20Sopenharmony_ci#endif 5678c2ecf20Sopenharmony_ci up_write(&tty->termios_rwsem); 5688c2ecf20Sopenharmony_ci tty_set_termios(tty, &termios); 5698c2ecf20Sopenharmony_ci return 0; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci#endif 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci#ifdef TIOCGETC 5748c2ecf20Sopenharmony_cistatic int get_tchars(struct tty_struct *tty, struct tchars __user *tchars) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct tchars tmp; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci down_read(&tty->termios_rwsem); 5798c2ecf20Sopenharmony_ci tmp.t_intrc = tty->termios.c_cc[VINTR]; 5808c2ecf20Sopenharmony_ci tmp.t_quitc = tty->termios.c_cc[VQUIT]; 5818c2ecf20Sopenharmony_ci tmp.t_startc = tty->termios.c_cc[VSTART]; 5828c2ecf20Sopenharmony_ci tmp.t_stopc = tty->termios.c_cc[VSTOP]; 5838c2ecf20Sopenharmony_ci tmp.t_eofc = tty->termios.c_cc[VEOF]; 5848c2ecf20Sopenharmony_ci tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */ 5858c2ecf20Sopenharmony_ci up_read(&tty->termios_rwsem); 5868c2ecf20Sopenharmony_ci return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int set_tchars(struct tty_struct *tty, struct tchars __user *tchars) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci struct tchars tmp; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (copy_from_user(&tmp, tchars, sizeof(tmp))) 5948c2ecf20Sopenharmony_ci return -EFAULT; 5958c2ecf20Sopenharmony_ci down_write(&tty->termios_rwsem); 5968c2ecf20Sopenharmony_ci tty->termios.c_cc[VINTR] = tmp.t_intrc; 5978c2ecf20Sopenharmony_ci tty->termios.c_cc[VQUIT] = tmp.t_quitc; 5988c2ecf20Sopenharmony_ci tty->termios.c_cc[VSTART] = tmp.t_startc; 5998c2ecf20Sopenharmony_ci tty->termios.c_cc[VSTOP] = tmp.t_stopc; 6008c2ecf20Sopenharmony_ci tty->termios.c_cc[VEOF] = tmp.t_eofc; 6018c2ecf20Sopenharmony_ci tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */ 6028c2ecf20Sopenharmony_ci up_write(&tty->termios_rwsem); 6038c2ecf20Sopenharmony_ci return 0; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci#endif 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci#ifdef TIOCGLTC 6088c2ecf20Sopenharmony_cistatic int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct ltchars tmp; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci down_read(&tty->termios_rwsem); 6138c2ecf20Sopenharmony_ci tmp.t_suspc = tty->termios.c_cc[VSUSP]; 6148c2ecf20Sopenharmony_ci /* what is dsuspc anyway? */ 6158c2ecf20Sopenharmony_ci tmp.t_dsuspc = tty->termios.c_cc[VSUSP]; 6168c2ecf20Sopenharmony_ci tmp.t_rprntc = tty->termios.c_cc[VREPRINT]; 6178c2ecf20Sopenharmony_ci /* what is flushc anyway? */ 6188c2ecf20Sopenharmony_ci tmp.t_flushc = tty->termios.c_cc[VEOL2]; 6198c2ecf20Sopenharmony_ci tmp.t_werasc = tty->termios.c_cc[VWERASE]; 6208c2ecf20Sopenharmony_ci tmp.t_lnextc = tty->termios.c_cc[VLNEXT]; 6218c2ecf20Sopenharmony_ci up_read(&tty->termios_rwsem); 6228c2ecf20Sopenharmony_ci return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct ltchars tmp; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (copy_from_user(&tmp, ltchars, sizeof(tmp))) 6308c2ecf20Sopenharmony_ci return -EFAULT; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci down_write(&tty->termios_rwsem); 6338c2ecf20Sopenharmony_ci tty->termios.c_cc[VSUSP] = tmp.t_suspc; 6348c2ecf20Sopenharmony_ci /* what is dsuspc anyway? */ 6358c2ecf20Sopenharmony_ci tty->termios.c_cc[VEOL2] = tmp.t_dsuspc; 6368c2ecf20Sopenharmony_ci tty->termios.c_cc[VREPRINT] = tmp.t_rprntc; 6378c2ecf20Sopenharmony_ci /* what is flushc anyway? */ 6388c2ecf20Sopenharmony_ci tty->termios.c_cc[VEOL2] = tmp.t_flushc; 6398c2ecf20Sopenharmony_ci tty->termios.c_cc[VWERASE] = tmp.t_werasc; 6408c2ecf20Sopenharmony_ci tty->termios.c_cc[VLNEXT] = tmp.t_lnextc; 6418c2ecf20Sopenharmony_ci up_write(&tty->termios_rwsem); 6428c2ecf20Sopenharmony_ci return 0; 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci#endif 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci/** 6478c2ecf20Sopenharmony_ci * tty_change_softcar - carrier change ioctl helper 6488c2ecf20Sopenharmony_ci * @tty: tty to update 6498c2ecf20Sopenharmony_ci * @arg: enable/disable CLOCAL 6508c2ecf20Sopenharmony_ci * 6518c2ecf20Sopenharmony_ci * Perform a change to the CLOCAL state and call into the driver 6528c2ecf20Sopenharmony_ci * layer to make it visible. All done with the termios rwsem 6538c2ecf20Sopenharmony_ci */ 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic int tty_change_softcar(struct tty_struct *tty, int arg) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci int ret = 0; 6588c2ecf20Sopenharmony_ci int bit = arg ? CLOCAL : 0; 6598c2ecf20Sopenharmony_ci struct ktermios old; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci down_write(&tty->termios_rwsem); 6628c2ecf20Sopenharmony_ci old = tty->termios; 6638c2ecf20Sopenharmony_ci tty->termios.c_cflag &= ~CLOCAL; 6648c2ecf20Sopenharmony_ci tty->termios.c_cflag |= bit; 6658c2ecf20Sopenharmony_ci if (tty->ops->set_termios) 6668c2ecf20Sopenharmony_ci tty->ops->set_termios(tty, &old); 6678c2ecf20Sopenharmony_ci if (C_CLOCAL(tty) != bit) 6688c2ecf20Sopenharmony_ci ret = -EINVAL; 6698c2ecf20Sopenharmony_ci up_write(&tty->termios_rwsem); 6708c2ecf20Sopenharmony_ci return ret; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci/** 6748c2ecf20Sopenharmony_ci * tty_mode_ioctl - mode related ioctls 6758c2ecf20Sopenharmony_ci * @tty: tty for the ioctl 6768c2ecf20Sopenharmony_ci * @file: file pointer for the tty 6778c2ecf20Sopenharmony_ci * @cmd: command 6788c2ecf20Sopenharmony_ci * @arg: ioctl argument 6798c2ecf20Sopenharmony_ci * 6808c2ecf20Sopenharmony_ci * Perform non line discipline specific mode control ioctls. This 6818c2ecf20Sopenharmony_ci * is designed to be called by line disciplines to ensure they provide 6828c2ecf20Sopenharmony_ci * consistent mode setting. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ciint tty_mode_ioctl(struct tty_struct *tty, struct file *file, 6868c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct tty_struct *real_tty; 6898c2ecf20Sopenharmony_ci void __user *p = (void __user *)arg; 6908c2ecf20Sopenharmony_ci int ret = 0; 6918c2ecf20Sopenharmony_ci struct ktermios kterm; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci BUG_ON(file == NULL); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (tty->driver->type == TTY_DRIVER_TYPE_PTY && 6968c2ecf20Sopenharmony_ci tty->driver->subtype == PTY_TYPE_MASTER) 6978c2ecf20Sopenharmony_ci real_tty = tty->link; 6988c2ecf20Sopenharmony_ci else 6998c2ecf20Sopenharmony_ci real_tty = tty; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci switch (cmd) { 7028c2ecf20Sopenharmony_ci#ifdef TIOCGETP 7038c2ecf20Sopenharmony_ci case TIOCGETP: 7048c2ecf20Sopenharmony_ci return get_sgttyb(real_tty, (struct sgttyb __user *) arg); 7058c2ecf20Sopenharmony_ci case TIOCSETP: 7068c2ecf20Sopenharmony_ci case TIOCSETN: 7078c2ecf20Sopenharmony_ci return set_sgttyb(real_tty, (struct sgttyb __user *) arg); 7088c2ecf20Sopenharmony_ci#endif 7098c2ecf20Sopenharmony_ci#ifdef TIOCGETC 7108c2ecf20Sopenharmony_ci case TIOCGETC: 7118c2ecf20Sopenharmony_ci return get_tchars(real_tty, p); 7128c2ecf20Sopenharmony_ci case TIOCSETC: 7138c2ecf20Sopenharmony_ci return set_tchars(real_tty, p); 7148c2ecf20Sopenharmony_ci#endif 7158c2ecf20Sopenharmony_ci#ifdef TIOCGLTC 7168c2ecf20Sopenharmony_ci case TIOCGLTC: 7178c2ecf20Sopenharmony_ci return get_ltchars(real_tty, p); 7188c2ecf20Sopenharmony_ci case TIOCSLTC: 7198c2ecf20Sopenharmony_ci return set_ltchars(real_tty, p); 7208c2ecf20Sopenharmony_ci#endif 7218c2ecf20Sopenharmony_ci case TCSETSF: 7228c2ecf20Sopenharmony_ci return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD); 7238c2ecf20Sopenharmony_ci case TCSETSW: 7248c2ecf20Sopenharmony_ci return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD); 7258c2ecf20Sopenharmony_ci case TCSETS: 7268c2ecf20Sopenharmony_ci return set_termios(real_tty, p, TERMIOS_OLD); 7278c2ecf20Sopenharmony_ci#ifndef TCGETS2 7288c2ecf20Sopenharmony_ci case TCGETS: 7298c2ecf20Sopenharmony_ci copy_termios(real_tty, &kterm); 7308c2ecf20Sopenharmony_ci if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm)) 7318c2ecf20Sopenharmony_ci ret = -EFAULT; 7328c2ecf20Sopenharmony_ci return ret; 7338c2ecf20Sopenharmony_ci#else 7348c2ecf20Sopenharmony_ci case TCGETS: 7358c2ecf20Sopenharmony_ci copy_termios(real_tty, &kterm); 7368c2ecf20Sopenharmony_ci if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm)) 7378c2ecf20Sopenharmony_ci ret = -EFAULT; 7388c2ecf20Sopenharmony_ci return ret; 7398c2ecf20Sopenharmony_ci case TCGETS2: 7408c2ecf20Sopenharmony_ci copy_termios(real_tty, &kterm); 7418c2ecf20Sopenharmony_ci if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm)) 7428c2ecf20Sopenharmony_ci ret = -EFAULT; 7438c2ecf20Sopenharmony_ci return ret; 7448c2ecf20Sopenharmony_ci case TCSETSF2: 7458c2ecf20Sopenharmony_ci return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); 7468c2ecf20Sopenharmony_ci case TCSETSW2: 7478c2ecf20Sopenharmony_ci return set_termios(real_tty, p, TERMIOS_WAIT); 7488c2ecf20Sopenharmony_ci case TCSETS2: 7498c2ecf20Sopenharmony_ci return set_termios(real_tty, p, 0); 7508c2ecf20Sopenharmony_ci#endif 7518c2ecf20Sopenharmony_ci case TCGETA: 7528c2ecf20Sopenharmony_ci return get_termio(real_tty, p); 7538c2ecf20Sopenharmony_ci case TCSETAF: 7548c2ecf20Sopenharmony_ci return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO); 7558c2ecf20Sopenharmony_ci case TCSETAW: 7568c2ecf20Sopenharmony_ci return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO); 7578c2ecf20Sopenharmony_ci case TCSETA: 7588c2ecf20Sopenharmony_ci return set_termios(real_tty, p, TERMIOS_TERMIO); 7598c2ecf20Sopenharmony_ci#ifndef TCGETS2 7608c2ecf20Sopenharmony_ci case TIOCGLCKTRMIOS: 7618c2ecf20Sopenharmony_ci copy_termios_locked(real_tty, &kterm); 7628c2ecf20Sopenharmony_ci if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm)) 7638c2ecf20Sopenharmony_ci ret = -EFAULT; 7648c2ecf20Sopenharmony_ci return ret; 7658c2ecf20Sopenharmony_ci case TIOCSLCKTRMIOS: 7668c2ecf20Sopenharmony_ci if (!checkpoint_restore_ns_capable(&init_user_ns)) 7678c2ecf20Sopenharmony_ci return -EPERM; 7688c2ecf20Sopenharmony_ci copy_termios_locked(real_tty, &kterm); 7698c2ecf20Sopenharmony_ci if (user_termios_to_kernel_termios(&kterm, 7708c2ecf20Sopenharmony_ci (struct termios __user *) arg)) 7718c2ecf20Sopenharmony_ci return -EFAULT; 7728c2ecf20Sopenharmony_ci down_write(&real_tty->termios_rwsem); 7738c2ecf20Sopenharmony_ci real_tty->termios_locked = kterm; 7748c2ecf20Sopenharmony_ci up_write(&real_tty->termios_rwsem); 7758c2ecf20Sopenharmony_ci return 0; 7768c2ecf20Sopenharmony_ci#else 7778c2ecf20Sopenharmony_ci case TIOCGLCKTRMIOS: 7788c2ecf20Sopenharmony_ci copy_termios_locked(real_tty, &kterm); 7798c2ecf20Sopenharmony_ci if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm)) 7808c2ecf20Sopenharmony_ci ret = -EFAULT; 7818c2ecf20Sopenharmony_ci return ret; 7828c2ecf20Sopenharmony_ci case TIOCSLCKTRMIOS: 7838c2ecf20Sopenharmony_ci if (!checkpoint_restore_ns_capable(&init_user_ns)) 7848c2ecf20Sopenharmony_ci return -EPERM; 7858c2ecf20Sopenharmony_ci copy_termios_locked(real_tty, &kterm); 7868c2ecf20Sopenharmony_ci if (user_termios_to_kernel_termios_1(&kterm, 7878c2ecf20Sopenharmony_ci (struct termios __user *) arg)) 7888c2ecf20Sopenharmony_ci return -EFAULT; 7898c2ecf20Sopenharmony_ci down_write(&real_tty->termios_rwsem); 7908c2ecf20Sopenharmony_ci real_tty->termios_locked = kterm; 7918c2ecf20Sopenharmony_ci up_write(&real_tty->termios_rwsem); 7928c2ecf20Sopenharmony_ci return ret; 7938c2ecf20Sopenharmony_ci#endif 7948c2ecf20Sopenharmony_ci#ifdef TCGETX 7958c2ecf20Sopenharmony_ci case TCGETX: 7968c2ecf20Sopenharmony_ci case TCSETX: 7978c2ecf20Sopenharmony_ci case TCSETXW: 7988c2ecf20Sopenharmony_ci case TCSETXF: 7998c2ecf20Sopenharmony_ci return -ENOTTY; 8008c2ecf20Sopenharmony_ci#endif 8018c2ecf20Sopenharmony_ci case TIOCGSOFTCAR: 8028c2ecf20Sopenharmony_ci copy_termios(real_tty, &kterm); 8038c2ecf20Sopenharmony_ci ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0, 8048c2ecf20Sopenharmony_ci (int __user *)arg); 8058c2ecf20Sopenharmony_ci return ret; 8068c2ecf20Sopenharmony_ci case TIOCSSOFTCAR: 8078c2ecf20Sopenharmony_ci if (get_user(arg, (unsigned int __user *) arg)) 8088c2ecf20Sopenharmony_ci return -EFAULT; 8098c2ecf20Sopenharmony_ci return tty_change_softcar(real_tty, arg); 8108c2ecf20Sopenharmony_ci default: 8118c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_mode_ioctl); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci/* Caller guarantees ldisc reference is held */ 8188c2ecf20Sopenharmony_cistatic int __tty_perform_flush(struct tty_struct *tty, unsigned long arg) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct tty_ldisc *ld = tty->ldisc; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci switch (arg) { 8238c2ecf20Sopenharmony_ci case TCIFLUSH: 8248c2ecf20Sopenharmony_ci if (ld && ld->ops->flush_buffer) { 8258c2ecf20Sopenharmony_ci ld->ops->flush_buffer(tty); 8268c2ecf20Sopenharmony_ci tty_unthrottle(tty); 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci case TCIOFLUSH: 8308c2ecf20Sopenharmony_ci if (ld && ld->ops->flush_buffer) { 8318c2ecf20Sopenharmony_ci ld->ops->flush_buffer(tty); 8328c2ecf20Sopenharmony_ci tty_unthrottle(tty); 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci fallthrough; 8358c2ecf20Sopenharmony_ci case TCOFLUSH: 8368c2ecf20Sopenharmony_ci tty_driver_flush_buffer(tty); 8378c2ecf20Sopenharmony_ci break; 8388c2ecf20Sopenharmony_ci default: 8398c2ecf20Sopenharmony_ci return -EINVAL; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci return 0; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ciint tty_perform_flush(struct tty_struct *tty, unsigned long arg) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci struct tty_ldisc *ld; 8478c2ecf20Sopenharmony_ci int retval = tty_check_change(tty); 8488c2ecf20Sopenharmony_ci if (retval) 8498c2ecf20Sopenharmony_ci return retval; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci ld = tty_ldisc_ref_wait(tty); 8528c2ecf20Sopenharmony_ci retval = __tty_perform_flush(tty, arg); 8538c2ecf20Sopenharmony_ci if (ld) 8548c2ecf20Sopenharmony_ci tty_ldisc_deref(ld); 8558c2ecf20Sopenharmony_ci return retval; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tty_perform_flush); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ciint n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, 8608c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci int retval; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci switch (cmd) { 8658c2ecf20Sopenharmony_ci case TCXONC: 8668c2ecf20Sopenharmony_ci retval = tty_check_change(tty); 8678c2ecf20Sopenharmony_ci if (retval) 8688c2ecf20Sopenharmony_ci return retval; 8698c2ecf20Sopenharmony_ci switch (arg) { 8708c2ecf20Sopenharmony_ci case TCOOFF: 8718c2ecf20Sopenharmony_ci spin_lock_irq(&tty->flow_lock); 8728c2ecf20Sopenharmony_ci if (!tty->flow_stopped) { 8738c2ecf20Sopenharmony_ci tty->flow_stopped = 1; 8748c2ecf20Sopenharmony_ci __stop_tty(tty); 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci spin_unlock_irq(&tty->flow_lock); 8778c2ecf20Sopenharmony_ci break; 8788c2ecf20Sopenharmony_ci case TCOON: 8798c2ecf20Sopenharmony_ci spin_lock_irq(&tty->flow_lock); 8808c2ecf20Sopenharmony_ci if (tty->flow_stopped) { 8818c2ecf20Sopenharmony_ci tty->flow_stopped = 0; 8828c2ecf20Sopenharmony_ci __start_tty(tty); 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci spin_unlock_irq(&tty->flow_lock); 8858c2ecf20Sopenharmony_ci break; 8868c2ecf20Sopenharmony_ci case TCIOFF: 8878c2ecf20Sopenharmony_ci if (STOP_CHAR(tty) != __DISABLED_CHAR) 8888c2ecf20Sopenharmony_ci retval = tty_send_xchar(tty, STOP_CHAR(tty)); 8898c2ecf20Sopenharmony_ci break; 8908c2ecf20Sopenharmony_ci case TCION: 8918c2ecf20Sopenharmony_ci if (START_CHAR(tty) != __DISABLED_CHAR) 8928c2ecf20Sopenharmony_ci retval = tty_send_xchar(tty, START_CHAR(tty)); 8938c2ecf20Sopenharmony_ci break; 8948c2ecf20Sopenharmony_ci default: 8958c2ecf20Sopenharmony_ci return -EINVAL; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci return retval; 8988c2ecf20Sopenharmony_ci case TCFLSH: 8998c2ecf20Sopenharmony_ci retval = tty_check_change(tty); 9008c2ecf20Sopenharmony_ci if (retval) 9018c2ecf20Sopenharmony_ci return retval; 9028c2ecf20Sopenharmony_ci return __tty_perform_flush(tty, arg); 9038c2ecf20Sopenharmony_ci default: 9048c2ecf20Sopenharmony_ci /* Try the mode commands */ 9058c2ecf20Sopenharmony_ci return tty_mode_ioctl(tty, file, cmd, arg); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(n_tty_ioctl_helper); 909