Blame view

drivers/char/tty_ioctl.c 30.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /*
   *  linux/drivers/char/tty_ioctl.c
   *
   *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
   *
   * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
   * which can be dynamically activated and de-activated by the line
   * discipline handling modules (like SLIP).
   */
  
  #include <linux/types.h>
  #include <linux/termios.h>
  #include <linux/errno.h>
  #include <linux/sched.h>
  #include <linux/kernel.h>
  #include <linux/major.h>
  #include <linux/tty.h>
  #include <linux/fcntl.h>
  #include <linux/string.h>
  #include <linux/mm.h>
  #include <linux/module.h>
  #include <linux/bitops.h>
5785c95ba   Arjan van de Ven   [PATCH] tty: make...
23
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  
  #include <asm/io.h>
  #include <asm/uaccess.h>
  #include <asm/system.h>
  
  #undef TTY_DEBUG_WAIT_UNTIL_SENT
  
  #undef	DEBUG
  
  /*
   * Internal flag options for termios setting behavior
   */
  #define TERMIOS_FLUSH	1
  #define TERMIOS_WAIT	2
  #define TERMIOS_TERMIO	4
edc6afc54   Alan Cox   [PATCH] tty: swit...
39
  #define TERMIOS_OLD	8
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40

af9b897ee   Alan Cox   [PATCH] tty layer...
41

d81ed1030   Alan Cox   tty: Remove more ...
42
43
44
45
46
47
48
49
  /**
   *	tty_chars_in_buffer	-	characters pending
   *	@tty: terminal
   *
   *	Return the number of bytes of data in the device private
   *	output queue. If no private method is supplied there is assumed
   *	to be no queue on the device.
   */
f34d7a5b7   Alan Cox   tty: The big oper...
50
51
52
53
54
55
56
  int tty_chars_in_buffer(struct tty_struct *tty)
  {
  	if (tty->ops->chars_in_buffer)
  		return tty->ops->chars_in_buffer(tty);
  	else
  		return 0;
  }
f34d7a5b7   Alan Cox   tty: The big oper...
57
  EXPORT_SYMBOL(tty_chars_in_buffer);
d81ed1030   Alan Cox   tty: Remove more ...
58
59
60
61
62
63
64
65
66
67
68
  /**
   *	tty_write_room		-	write queue space
   *	@tty: terminal
   *
   *	Return the number of bytes that can be queued to this device
   *	at the present time. The result should be treated as a guarantee
   *	and the driver cannot offer a value it later shrinks by more than
   *	the number of bytes written. If no method is provided 2K is always
   *	returned and data may be lost as there will be no flow control.
   */
   
f34d7a5b7   Alan Cox   tty: The big oper...
69
70
71
72
73
74
  int tty_write_room(struct tty_struct *tty)
  {
  	if (tty->ops->write_room)
  		return tty->ops->write_room(tty);
  	return 2048;
  }
f34d7a5b7   Alan Cox   tty: The big oper...
75
  EXPORT_SYMBOL(tty_write_room);
d81ed1030   Alan Cox   tty: Remove more ...
76
77
78
79
80
81
82
83
  /**
   *	tty_driver_flush_buffer	-	discard internal buffer
   *	@tty: terminal
   *
   *	Discard the internal output buffer for this device. If no method
   *	is provided then either the buffer cannot be hardware flushed or
   *	there is no buffer driver side.
   */
f34d7a5b7   Alan Cox   tty: The big oper...
84
85
86
87
88
  void tty_driver_flush_buffer(struct tty_struct *tty)
  {
  	if (tty->ops->flush_buffer)
  		tty->ops->flush_buffer(tty);
  }
f34d7a5b7   Alan Cox   tty: The big oper...
89
  EXPORT_SYMBOL(tty_driver_flush_buffer);
d81ed1030   Alan Cox   tty: Remove more ...
90
91
92
93
94
  /**
   *	tty_throttle		-	flow control
   *	@tty: terminal
   *
   *	Indicate that a tty should stop transmitting data down the stack.
38db89799   Alan Cox   tty: throttling r...
95
96
97
   *	Takes the termios mutex to protect against parallel throttle/unthrottle
   *	and also to ensure the driver can consistently reference its own
   *	termios data at this point when implementing software flow control.
d81ed1030   Alan Cox   tty: Remove more ...
98
   */
39c2e60f8   Alan Cox   tty: add throttle...
99
100
  void tty_throttle(struct tty_struct *tty)
  {
38db89799   Alan Cox   tty: throttling r...
101
  	mutex_lock(&tty->termios_mutex);
39c2e60f8   Alan Cox   tty: add throttle...
102
103
104
105
  	/* check TTY_THROTTLED first so it indicates our state */
  	if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
  	    tty->ops->throttle)
  		tty->ops->throttle(tty);
38db89799   Alan Cox   tty: throttling r...
106
  	mutex_unlock(&tty->termios_mutex);
39c2e60f8   Alan Cox   tty: add throttle...
107
108
  }
  EXPORT_SYMBOL(tty_throttle);
d81ed1030   Alan Cox   tty: Remove more ...
109
110
111
112
113
  /**
   *	tty_unthrottle		-	flow control
   *	@tty: terminal
   *
   *	Indicate that a tty may continue transmitting data down the stack.
38db89799   Alan Cox   tty: throttling r...
114
115
116
117
118
119
   *	Takes the termios mutex to protect against parallel throttle/unthrottle
   *	and also to ensure the driver can consistently reference its own
   *	termios data at this point when implementing software flow control.
   *
   *	Drivers should however remember that the stack can issue a throttle,
   *	then change flow control method, then unthrottle.
d81ed1030   Alan Cox   tty: Remove more ...
120
   */
39c2e60f8   Alan Cox   tty: add throttle...
121
122
  void tty_unthrottle(struct tty_struct *tty)
  {
38db89799   Alan Cox   tty: throttling r...
123
  	mutex_lock(&tty->termios_mutex);
39c2e60f8   Alan Cox   tty: add throttle...
124
125
126
  	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
  	    tty->ops->unthrottle)
  		tty->ops->unthrottle(tty);
38db89799   Alan Cox   tty: throttling r...
127
  	mutex_unlock(&tty->termios_mutex);
39c2e60f8   Alan Cox   tty: add throttle...
128
129
  }
  EXPORT_SYMBOL(tty_unthrottle);
f34d7a5b7   Alan Cox   tty: The big oper...
130

af9b897ee   Alan Cox   [PATCH] tty layer...
131
132
133
134
135
136
137
138
139
140
  /**
   *	tty_wait_until_sent	-	wait for I/O to finish
   *	@tty: tty we are waiting for
   *	@timeout: how long we will wait
   *
   *	Wait for characters pending in a tty driver to hit the wire, or
   *	for a timeout to occur (eg due to flow control)
   *
   *	Locking: none
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
141
  void tty_wait_until_sent(struct tty_struct *tty, long timeout)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
  #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
  	char buf[64];
355d95a1c   Alan Cox   tty_ioctl: drag s...
145

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
  	printk(KERN_DEBUG "%s wait until sent...
  ", tty_name(tty, buf));
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
  	if (!timeout)
  		timeout = MAX_SCHEDULE_TIMEOUT;
5a52bd4a2   Jiri Slaby   Char: tty_ioctl, ...
151
  	if (wait_event_interruptible_timeout(tty->write_wait,
f34d7a5b7   Alan Cox   tty: The big oper...
152
153
154
  			!tty_chars_in_buffer(tty), timeout) >= 0) {
  		if (tty->ops->wait_until_sent)
  			tty->ops->wait_until_sent(tty, timeout);
0ee9cbb3c   Alan Cox   tty_ioctl: lockin...
155
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  EXPORT_SYMBOL(tty_wait_until_sent);
d81ed1030   Alan Cox   tty: Remove more ...
158
159
160
161
  
  /*
   *		Termios Helper Methods
   */
edc6afc54   Alan Cox   [PATCH] tty: swit...
162
163
164
  static void unset_locked_termios(struct ktermios *termios,
  				 struct ktermios *old,
  				 struct ktermios *locked)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
  {
  	int	i;
355d95a1c   Alan Cox   tty_ioctl: drag s...
167
168
  
  #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
176
177
178
179
180
  
  	if (!locked) {
  		printk(KERN_WARNING "Warning?!? termios_locked is NULL.
  ");
  		return;
  	}
  
  	NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
  	NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
  	NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
  	NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
  	termios->c_line = locked->c_line ? old->c_line : termios->c_line;
355d95a1c   Alan Cox   tty_ioctl: drag s...
181
  	for (i = 0; i < NCCS; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
  		termios->c_cc[i] = locked->c_cc[i] ?
  			old->c_cc[i] : termios->c_cc[i];
edc6afc54   Alan Cox   [PATCH] tty: swit...
184
  	/* FIXME: What should we do for i/ospeed */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  }
edc6afc54   Alan Cox   [PATCH] tty: swit...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  /*
   * Routine which returns the baud rate of the tty
   *
   * Note that the baud_table needs to be kept in sync with the
   * include/asm/termbits.h file.
   */
  static const speed_t baud_table[] = {
  	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
  	9600, 19200, 38400, 57600, 115200, 230400, 460800,
  #ifdef __sparc__
  	76800, 153600, 307200, 614400, 921600
  #else
  	500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
  	2500000, 3000000, 3500000, 4000000
  #endif
  };
  
  #ifndef __sparc__
  static const tcflag_t baud_bits[] = {
  	B0, B50, B75, B110, B134, B150, B200, B300, B600,
  	B1200, B1800, B2400, B4800, B9600, B19200, B38400,
  	B57600, B115200, B230400, B460800, B500000, B576000,
  	B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
  	B3000000, B3500000, B4000000
  };
  #else
  static const tcflag_t baud_bits[] = {
  	B0, B50, B75, B110, B134, B150, B200, B300, B600,
  	B1200, B1800, B2400, B4800, B9600, B19200, B38400,
  	B57600, B115200, B230400, B460800, B76800, B153600,
  	B307200, B614400, B921600
  };
  #endif
  
  static int n_baud_table = ARRAY_SIZE(baud_table);
  
  /**
   *	tty_termios_baud_rate
   *	@termios: termios structure
   *
   *	Convert termios baud rate data into a speed. This should be called
   *	with the termios lock held if this termios is a terminal termios
   *	structure. May change the termios data. Device drivers can call this
   *	function but should use ->c_[io]speed directly as they are updated.
   *
   *	Locking: none
   */
  
  speed_t tty_termios_baud_rate(struct ktermios *termios)
  {
  	unsigned int cbaud;
  
  	cbaud = termios->c_cflag & CBAUD;
  
  #ifdef BOTHER
  	/* Magic token for arbitary speed via c_ispeed/c_ospeed */
  	if (cbaud == BOTHER)
  		return termios->c_ospeed;
  #endif
  	if (cbaud & CBAUDEX) {
  		cbaud &= ~CBAUDEX;
  
  		if (cbaud < 1 || cbaud + 15 > n_baud_table)
  			termios->c_cflag &= ~CBAUDEX;
  		else
  			cbaud += 15;
  	}
  	return baud_table[cbaud];
  }
edc6afc54   Alan Cox   [PATCH] tty: swit...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  EXPORT_SYMBOL(tty_termios_baud_rate);
  
  /**
   *	tty_termios_input_baud_rate
   *	@termios: termios structure
   *
   *	Convert termios baud rate data into a speed. This should be called
   *	with the termios lock held if this termios is a terminal termios
   *	structure. May change the termios data. Device drivers can call this
   *	function but should use ->c_[io]speed directly as they are updated.
   *
   *	Locking: none
   */
  
  speed_t tty_termios_input_baud_rate(struct ktermios *termios)
  {
  #ifdef IBSHIFT
  	unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
  
  	if (cbaud == B0)
  		return tty_termios_baud_rate(termios);
  
  	/* Magic token for arbitary speed via c_ispeed*/
  	if (cbaud == BOTHER)
  		return termios->c_ispeed;
  
  	if (cbaud & CBAUDEX) {
  		cbaud &= ~CBAUDEX;
  
  		if (cbaud < 1 || cbaud + 15 > n_baud_table)
  			termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
  		else
  			cbaud += 15;
  	}
  	return baud_table[cbaud];
  #else
  	return tty_termios_baud_rate(termios);
  #endif
  }
edc6afc54   Alan Cox   [PATCH] tty: swit...
294
  EXPORT_SYMBOL(tty_termios_input_baud_rate);
edc6afc54   Alan Cox   [PATCH] tty: swit...
295
296
  /**
   *	tty_termios_encode_baud_rate
78137e3b3   Alan Cox   [PATCH] tty: impr...
297
   *	@termios: ktermios structure holding user requested state
edc6afc54   Alan Cox   [PATCH] tty: swit...
298
299
300
301
302
303
304
   *	@ispeed: input speed
   *	@ospeed: output speed
   *
   *	Encode the speeds set into the passed termios structure. This is
   *	used as a library helper for drivers os that they can report back
   *	the actual speed selected when it differs from the speed requested
   *
78137e3b3   Alan Cox   [PATCH] tty: impr...
305
306
307
308
   *	For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
   *	we need to carefully set the bits when the user does not get the
   *	desired speed. We allow small margins and preserve as much of possible
   *	of the input intent to keep compatiblity.
edc6afc54   Alan Cox   [PATCH] tty: swit...
309
310
311
   *
   *	Locking: Caller should hold termios lock. This is already held
   *	when calling this function from the driver termios handler.
5f519d728   Alan Cox   tty: expose new m...
312
313
314
   *
   *	The ifdefs deal with platforms whose owners have yet to update them
   *	and will all go away once this is done.
edc6afc54   Alan Cox   [PATCH] tty: swit...
315
   */
75e8b71d5   Maciej W. Rozycki   tty_ioctl: fix th...
316
317
  void tty_termios_encode_baud_rate(struct ktermios *termios,
  				  speed_t ibaud, speed_t obaud)
edc6afc54   Alan Cox   [PATCH] tty: swit...
318
319
  {
  	int i = 0;
78137e3b3   Alan Cox   [PATCH] tty: impr...
320
321
322
  	int ifound = -1, ofound = -1;
  	int iclose = ibaud/50, oclose = obaud/50;
  	int ibinput = 0;
edc6afc54   Alan Cox   [PATCH] tty: swit...
323

5f519d728   Alan Cox   tty: expose new m...
324
325
  	if (obaud == 0)			/* CD dropped 		  */
  		ibaud = 0;		/* Clear ibaud to be sure */
edc6afc54   Alan Cox   [PATCH] tty: swit...
326
327
  	termios->c_ispeed = ibaud;
  	termios->c_ospeed = obaud;
5f519d728   Alan Cox   tty: expose new m...
328
  #ifdef BOTHER
78137e3b3   Alan Cox   [PATCH] tty: impr...
329
330
331
332
333
334
335
336
337
338
  	/* If the user asked for a precise weird speed give a precise weird
  	   answer. If they asked for a Bfoo speed they many have problems
  	   digesting non-exact replies so fuzz a bit */
  
  	if ((termios->c_cflag & CBAUD) == BOTHER)
  		oclose = 0;
  	if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
  		iclose = 0;
  	if ((termios->c_cflag >> IBSHIFT) & CBAUD)
  		ibinput = 1;	/* An input speed was specified */
5f519d728   Alan Cox   tty: expose new m...
339
  #endif
edc6afc54   Alan Cox   [PATCH] tty: swit...
340
  	termios->c_cflag &= ~CBAUD;
edc6afc54   Alan Cox   [PATCH] tty: swit...
341

5f519d728   Alan Cox   tty: expose new m...
342
343
344
345
346
347
  	/*
  	 *	Our goal is to find a close match to the standard baud rate
  	 *	returned. Walk the baud rate table and if we get a very close
  	 *	match then report back the speed as a POSIX Bxxxx value by
  	 *	preference
  	 */
edc6afc54   Alan Cox   [PATCH] tty: swit...
348
  	do {
75e8b71d5   Maciej W. Rozycki   tty_ioctl: fix th...
349
350
  		if (obaud - oclose <= baud_table[i] &&
  		    obaud + oclose >= baud_table[i]) {
edc6afc54   Alan Cox   [PATCH] tty: swit...
351
  			termios->c_cflag |= baud_bits[i];
78137e3b3   Alan Cox   [PATCH] tty: impr...
352
  			ofound = i;
edc6afc54   Alan Cox   [PATCH] tty: swit...
353
  		}
75e8b71d5   Maciej W. Rozycki   tty_ioctl: fix th...
354
355
356
357
  		if (ibaud - iclose <= baud_table[i] &&
  		    ibaud + iclose >= baud_table[i]) {
  			/* For the case input == output don't set IBAUD bits
  			   if the user didn't do so */
5f519d728   Alan Cox   tty: expose new m...
358
359
360
361
362
  			if (ofound == i && !ibinput)
  				ifound  = i;
  #ifdef IBSHIFT
  			else {
  				ifound = i;
78137e3b3   Alan Cox   [PATCH] tty: impr...
363
  				termios->c_cflag |= (baud_bits[i] << IBSHIFT);
5f519d728   Alan Cox   tty: expose new m...
364
365
  			}
  #endif
edc6afc54   Alan Cox   [PATCH] tty: swit...
366
  		}
6804396f1   Jiri Slaby   Char: tty_ioctl, ...
367
  	} while (++i < n_baud_table);
5f519d728   Alan Cox   tty: expose new m...
368
369
370
371
372
373
  
  	/*
  	 *	If we found no match then use BOTHER if provided or warn
  	 *	the user their platform maintainer needs to wake up if not.
  	 */
  #ifdef BOTHER
78137e3b3   Alan Cox   [PATCH] tty: impr...
374
  	if (ofound == -1)
edc6afc54   Alan Cox   [PATCH] tty: swit...
375
  		termios->c_cflag |= BOTHER;
78137e3b3   Alan Cox   [PATCH] tty: impr...
376
377
  	/* Set exact input bits only if the input and output differ or the
  	   user already did */
6804396f1   Jiri Slaby   Char: tty_ioctl, ...
378
  	if (ifound == -1 && (ibaud != obaud || ibinput))
edc6afc54   Alan Cox   [PATCH] tty: swit...
379
  		termios->c_cflag |= (BOTHER << IBSHIFT);
5f519d728   Alan Cox   tty: expose new m...
380
381
382
383
384
385
386
387
388
  #else
  	if (ifound == -1 || ofound == -1) {
  		static int warned;
  		if (!warned++)
  			printk(KERN_WARNING "tty: Unable to return correct "
  			  "speed data as your architecture needs updating.
  ");
  	}
  #endif
edc6afc54   Alan Cox   [PATCH] tty: swit...
389
  }
edc6afc54   Alan Cox   [PATCH] tty: swit...
390
  EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
d81ed1030   Alan Cox   tty: Remove more ...
391
392
393
394
395
396
397
398
399
  /**
   *	tty_encode_baud_rate		-	set baud rate of the tty
   *	@ibaud: input baud rate
   *	@obad: output baud rate
   *
   *	Update the current termios data for the tty with the new speed
   *	settings. The caller must hold the termios_mutex for the tty in
   *	question.
   */
5f519d728   Alan Cox   tty: expose new m...
400
401
402
403
404
  void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
  {
  	tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
  }
  EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
edc6afc54   Alan Cox   [PATCH] tty: swit...
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
  
  /**
   *	tty_get_baud_rate	-	get tty bit rates
   *	@tty: tty to query
   *
   *	Returns the baud rate as an integer for this terminal. The
   *	termios lock must be held by the caller and the terminal bit
   *	flags may be updated.
   *
   *	Locking: none
   */
  
  speed_t tty_get_baud_rate(struct tty_struct *tty)
  {
  	speed_t baud = tty_termios_baud_rate(tty->termios);
  
  	if (baud == 38400 && tty->alt_speed) {
  		if (!tty->warned) {
  			printk(KERN_WARNING "Use of setserial/setrocket to "
  					    "set SPD_* flags is deprecated
  ");
  			tty->warned = 1;
  		}
  		baud = tty->alt_speed;
  	}
  
  	return baud;
  }
edc6afc54   Alan Cox   [PATCH] tty: swit...
433
  EXPORT_SYMBOL(tty_get_baud_rate);
af9b897ee   Alan Cox   [PATCH] tty layer...
434
  /**
5f519d728   Alan Cox   tty: expose new m...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
   *	tty_termios_copy_hw	-	copy hardware settings
   *	@new: New termios
   *	@old: Old termios
   *
   *	Propogate the hardware specific terminal setting bits from
   *	the old termios structure to the new one. This is used in cases
   *	where the hardware does not support reconfiguration or as a helper
   *	in some cases where only minimal reconfiguration is supported
   */
  
  void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
  {
  	/* The bits a dumb device handles in software. Smart devices need
  	   to always provide a set_termios method */
  	new->c_cflag &= HUPCL | CREAD | CLOCAL;
  	new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
  	new->c_ispeed = old->c_ispeed;
  	new->c_ospeed = old->c_ospeed;
  }
5f519d728   Alan Cox   tty: expose new m...
454
455
456
  EXPORT_SYMBOL(tty_termios_copy_hw);
  
  /**
bf5e5834b   Alan Cox   pl2303: Fix mode ...
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
   *	tty_termios_hw_change	-	check for setting change
   *	@a: termios
   *	@b: termios to compare
   *
   *	Check if any of the bits that affect a dumb device have changed
   *	between the two termios structures, or a speed change is needed.
   */
  
  int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
  {
  	if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
  		return 1;
  	if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
  		return 1;
  	return 0;
  }
  EXPORT_SYMBOL(tty_termios_hw_change);
  
  /**
af9b897ee   Alan Cox   [PATCH] tty layer...
476
477
478
479
480
481
482
483
   *	change_termios		-	update termios values
   *	@tty: tty to update
   *	@new_termios: desired new value
   *
   *	Perform updates to the termios values set on this terminal. There
   *	is a bit of layering violation here with n_tty in terms of the
   *	internal knowledge of this function.
   *
d81ed1030   Alan Cox   tty: Remove more ...
484
   *	Locking: termios_mutex
af9b897ee   Alan Cox   [PATCH] tty layer...
485
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
486
  static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  {
978e595f8   Alan Cox   tty/serial: lay t...
488
  	struct ktermios old_termios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  	struct tty_ldisc *ld;
04f378b19   Alan Cox   tty: BKL pushdown
490
  	unsigned long flags;
355d95a1c   Alan Cox   tty_ioctl: drag s...
491

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
494
  	/*
  	 *	Perform the actual termios internal changes under lock.
  	 */
355d95a1c   Alan Cox   tty_ioctl: drag s...
495

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
498
  
  	/* FIXME: we need to decide on some locking/ordering semantics
  	   for the set_termios notification eventually */
5785c95ba   Arjan van de Ven   [PATCH] tty: make...
499
  	mutex_lock(&tty->termios_mutex);
978e595f8   Alan Cox   tty/serial: lay t...
500
  	old_termios = *tty->termios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
  	*tty->termios = *new_termios;
  	unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
  
  	/* See if packet mode change of state. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
509
510
511
512
  	if (tty->link && tty->link->packet) {
  		int old_flow = ((old_termios.c_iflag & IXON) &&
  				(old_termios.c_cc[VSTOP] == '\023') &&
  				(old_termios.c_cc[VSTART] == '\021'));
  		int new_flow = (I_IXON(tty) &&
  				STOP_CHAR(tty) == '\023' &&
  				START_CHAR(tty) == '\021');
  		if (old_flow != new_flow) {
04f378b19   Alan Cox   tty: BKL pushdown
513
  			spin_lock_irqsave(&tty->ctrl_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
  			tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
  			if (new_flow)
  				tty->ctrl_status |= TIOCPKT_DOSTOP;
  			else
  				tty->ctrl_status |= TIOCPKT_NOSTOP;
04f378b19   Alan Cox   tty: BKL pushdown
519
  			spin_unlock_irqrestore(&tty->ctrl_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
522
  			wake_up_interruptible(&tty->link->read_wait);
  		}
  	}
355d95a1c   Alan Cox   tty_ioctl: drag s...
523

f34d7a5b7   Alan Cox   tty: The big oper...
524
525
  	if (tty->ops->set_termios)
  		(*tty->ops->set_termios)(tty, &old_termios);
5f519d728   Alan Cox   tty: expose new m...
526
527
  	else
  		tty_termios_copy_hw(tty->termios, &old_termios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
  
  	ld = tty_ldisc_ref(tty);
  	if (ld != NULL) {
a352def21   Alan Cox   tty: Ldisc revamp
531
532
  		if (ld->ops->set_termios)
  			(ld->ops->set_termios)(tty, &old_termios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
  		tty_ldisc_deref(ld);
  	}
5785c95ba   Arjan van de Ven   [PATCH] tty: make...
535
  	mutex_unlock(&tty->termios_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  }
af9b897ee   Alan Cox   [PATCH] tty layer...
537
538
539
540
541
542
  /**
   *	set_termios		-	set termios values for a tty
   *	@tty: terminal device
   *	@arg: user data
   *	@opt: option information
   *
3a4fa0a25   Robert P. J. Day   Fix misspellings ...
543
   *	Helper function to prepare termios data and run necessary other
af9b897ee   Alan Cox   [PATCH] tty layer...
544
545
546
   *	functions before using change_termios to do the actual changes.
   *
   *	Locking:
d81ed1030   Alan Cox   tty: Remove more ...
547
   *		Called functions take ldisc and termios_mutex locks
af9b897ee   Alan Cox   [PATCH] tty layer...
548
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
549
  static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  {
edc6afc54   Alan Cox   [PATCH] tty: swit...
551
  	struct ktermios tmp_termios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
555
556
  	struct tty_ldisc *ld;
  	int retval = tty_check_change(tty);
  
  	if (retval)
  		return retval;
978e595f8   Alan Cox   tty/serial: lay t...
557
  	mutex_lock(&tty->termios_mutex);
64bb6c5e1   Alan Cox   [PATCH] tty_ioctl...
558
  	memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
978e595f8   Alan Cox   tty/serial: lay t...
559
  	mutex_unlock(&tty->termios_mutex);
64bb6c5e1   Alan Cox   [PATCH] tty_ioctl...
560

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  	if (opt & TERMIOS_TERMIO) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
  		if (user_termio_to_kernel_termios(&tmp_termios,
  						(struct termio __user *)arg))
  			return -EFAULT;
edc6afc54   Alan Cox   [PATCH] tty: swit...
565
566
  #ifdef TCGETS2
  	} else if (opt & TERMIOS_OLD) {
edc6afc54   Alan Cox   [PATCH] tty: swit...
567
  		if (user_termios_to_kernel_termios_1(&tmp_termios,
64bb6c5e1   Alan Cox   [PATCH] tty_ioctl...
568
  						(struct termios __user *)arg))
edc6afc54   Alan Cox   [PATCH] tty: swit...
569
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
  	} else {
  		if (user_termios_to_kernel_termios(&tmp_termios,
64bb6c5e1   Alan Cox   [PATCH] tty_ioctl...
572
  						(struct termios2 __user *)arg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
  			return -EFAULT;
  	}
64bb6c5e1   Alan Cox   [PATCH] tty_ioctl...
575
576
577
578
579
  #else
  	} else if (user_termios_to_kernel_termios(&tmp_termios,
  					(struct termios __user *)arg))
  		return -EFAULT;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580

355d95a1c   Alan Cox   tty_ioctl: drag s...
581
582
  	/* If old style Bfoo values are used then load c_ispeed/c_ospeed
  	 * with the real speed so its unconditionally usable */
edc6afc54   Alan Cox   [PATCH] tty: swit...
583
584
  	tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
  	tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
  	ld = tty_ldisc_ref(tty);
355d95a1c   Alan Cox   tty_ioctl: drag s...
586

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  	if (ld != NULL) {
a352def21   Alan Cox   tty: Ldisc revamp
588
589
  		if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
  			ld->ops->flush_buffer(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
  		tty_ldisc_deref(ld);
  	}
355d95a1c   Alan Cox   tty_ioctl: drag s...
592

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
596
597
598
599
  	if (opt & TERMIOS_WAIT) {
  		tty_wait_until_sent(tty, 0);
  		if (signal_pending(current))
  			return -EINTR;
  	}
  
  	change_termios(tty, &tmp_termios);
5f519d728   Alan Cox   tty: expose new m...
600
601
602
603
604
  
  	/* FIXME: Arguably if tmp_termios == tty->termios AND the
  	   actual requested termios was not tmp_termios then we may
  	   want to return an error as no user requested change has
  	   succeeded */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
  	return 0;
  }
26a2e20f4   Alan Cox   tty: Untangle ter...
607
608
609
610
611
612
613
614
615
616
617
618
619
  static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
  {
  	mutex_lock(&tty->termios_mutex);
  	memcpy(kterm, tty->termios, sizeof(struct ktermios));
  	mutex_unlock(&tty->termios_mutex);
  }
  
  static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
  {
  	mutex_lock(&tty->termios_mutex);
  	memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
  	mutex_unlock(&tty->termios_mutex);
  }
355d95a1c   Alan Cox   tty_ioctl: drag s...
620
  static int get_termio(struct tty_struct *tty, struct termio __user *termio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  {
26a2e20f4   Alan Cox   tty: Untangle ter...
622
623
624
  	struct ktermios kterm;
  	copy_termios(tty, &kterm);
  	if (kernel_termios_to_user_termio(termio, &kterm))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
  		return -EFAULT;
  	return 0;
  }
1d65b4a08   Alan Cox   tty: Add termiox
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
  
  #ifdef TCGETX
  
  /**
   *	set_termiox	-	set termiox fields if possible
   *	@tty: terminal
   *	@arg: termiox structure from user
   *	@opt: option flags for ioctl type
   *
   *	Implement the device calling points for the SYS5 termiox ioctl
   *	interface in Linux
   */
  
  static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
  {
  	struct termiox tnew;
  	struct tty_ldisc *ld;
  
  	if (tty->termiox == NULL)
  		return -EINVAL;
  	if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
  		return -EFAULT;
  
  	ld = tty_ldisc_ref(tty);
  	if (ld != NULL) {
  		if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
  			ld->ops->flush_buffer(tty);
  		tty_ldisc_deref(ld);
  	}
  	if (opt & TERMIOS_WAIT) {
  		tty_wait_until_sent(tty, 0);
  		if (signal_pending(current))
  			return -EINTR;
  	}
  
  	mutex_lock(&tty->termios_mutex);
  	if (tty->ops->set_termiox)
  		tty->ops->set_termiox(tty, &tnew);
  	mutex_unlock(&tty->termios_mutex);
  	return 0;
  }
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
673
674
675
676
677
  
  #ifdef TIOCGETP
  /*
   * These are deprecated, but there is limited support..
   *
   * The "sg_flags" translation is a joke..
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
678
  static int get_sgflags(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
  {
  	int flags = 0;
  
  	if (!(tty->termios->c_lflag & ICANON)) {
  		if (tty->termios->c_lflag & ISIG)
  			flags |= 0x02;		/* cbreak */
  		else
  			flags |= 0x20;		/* raw */
  	}
  	if (tty->termios->c_lflag & ECHO)
  		flags |= 0x08;			/* echo */
  	if (tty->termios->c_oflag & OPOST)
  		if (tty->termios->c_oflag & ONLCR)
  			flags |= 0x10;		/* crmod */
  	return flags;
  }
355d95a1c   Alan Cox   tty_ioctl: drag s...
695
  static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
  {
  	struct sgttyb tmp;
5785c95ba   Arjan van de Ven   [PATCH] tty: make...
698
  	mutex_lock(&tty->termios_mutex);
606d099cd   Alan Cox   [PATCH] tty: swit...
699
700
  	tmp.sg_ispeed = tty->termios->c_ispeed;
  	tmp.sg_ospeed = tty->termios->c_ospeed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
  	tmp.sg_erase = tty->termios->c_cc[VERASE];
  	tmp.sg_kill = tty->termios->c_cc[VKILL];
  	tmp.sg_flags = get_sgflags(tty);
5785c95ba   Arjan van de Ven   [PATCH] tty: make...
704
  	mutex_unlock(&tty->termios_mutex);
355d95a1c   Alan Cox   tty_ioctl: drag s...
705

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
  	return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
  }
355d95a1c   Alan Cox   tty_ioctl: drag s...
708
  static void set_sgflags(struct ktermios *termios, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
  {
  	termios->c_iflag = ICRNL | IXON;
  	termios->c_oflag = 0;
  	termios->c_lflag = ISIG | ICANON;
  	if (flags & 0x02) {	/* cbreak */
  		termios->c_iflag = 0;
  		termios->c_lflag &= ~ICANON;
  	}
  	if (flags & 0x08) {		/* echo */
  		termios->c_lflag |= ECHO | ECHOE | ECHOK |
  				    ECHOCTL | ECHOKE | IEXTEN;
  	}
  	if (flags & 0x10) {		/* crmod */
  		termios->c_oflag |= OPOST | ONLCR;
  	}
  	if (flags & 0x20) {	/* raw */
  		termios->c_iflag = 0;
  		termios->c_lflag &= ~(ISIG | ICANON);
  	}
  	if (!(termios->c_lflag & ICANON)) {
  		termios->c_cc[VMIN] = 1;
  		termios->c_cc[VTIME] = 0;
  	}
  }
af9b897ee   Alan Cox   [PATCH] tty layer...
733
734
735
736
737
738
739
740
  /**
   *	set_sgttyb		-	set legacy terminal values
   *	@tty: tty structure
   *	@sgttyb: pointer to old style terminal structure
   *
   *	Updates a terminal from the legacy BSD style terminal information
   *	structure.
   *
d81ed1030   Alan Cox   tty: Remove more ...
741
   *	Locking: termios_mutex
af9b897ee   Alan Cox   [PATCH] tty layer...
742
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
743
  static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
  {
  	int retval;
  	struct sgttyb tmp;
edc6afc54   Alan Cox   [PATCH] tty: swit...
747
  	struct ktermios termios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
749
750
751
  
  	retval = tty_check_change(tty);
  	if (retval)
  		return retval;
355d95a1c   Alan Cox   tty_ioctl: drag s...
752

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
  	if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
  		return -EFAULT;
5785c95ba   Arjan van de Ven   [PATCH] tty: make...
755
  	mutex_lock(&tty->termios_mutex);
6804396f1   Jiri Slaby   Char: tty_ioctl, ...
756
  	termios = *tty->termios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
  	termios.c_cc[VERASE] = tmp.sg_erase;
  	termios.c_cc[VKILL] = tmp.sg_kill;
  	set_sgflags(&termios, tmp.sg_flags);
edc6afc54   Alan Cox   [PATCH] tty: swit...
760
761
  	/* Try and encode into Bfoo format */
  #ifdef BOTHER
355d95a1c   Alan Cox   tty_ioctl: drag s...
762
763
  	tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
  						termios.c_ospeed);
edc6afc54   Alan Cox   [PATCH] tty: swit...
764
  #endif
5785c95ba   Arjan van de Ven   [PATCH] tty: make...
765
  	mutex_unlock(&tty->termios_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
768
769
770
771
  	change_termios(tty, &termios);
  	return 0;
  }
  #endif
  
  #ifdef TIOCGETC
355d95a1c   Alan Cox   tty_ioctl: drag s...
772
  static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
  {
  	struct tchars tmp;
978e595f8   Alan Cox   tty/serial: lay t...
775
  	mutex_lock(&tty->termios_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
778
779
780
781
  	tmp.t_intrc = tty->termios->c_cc[VINTR];
  	tmp.t_quitc = tty->termios->c_cc[VQUIT];
  	tmp.t_startc = tty->termios->c_cc[VSTART];
  	tmp.t_stopc = tty->termios->c_cc[VSTOP];
  	tmp.t_eofc = tty->termios->c_cc[VEOF];
  	tmp.t_brkc = tty->termios->c_cc[VEOL2];	/* what is brkc anyway? */
978e595f8   Alan Cox   tty/serial: lay t...
782
  	mutex_unlock(&tty->termios_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
  	return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
  }
355d95a1c   Alan Cox   tty_ioctl: drag s...
785
  static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
  {
  	struct tchars tmp;
  
  	if (copy_from_user(&tmp, tchars, sizeof(tmp)))
  		return -EFAULT;
978e595f8   Alan Cox   tty/serial: lay t...
791
  	mutex_lock(&tty->termios_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
796
797
  	tty->termios->c_cc[VINTR] = tmp.t_intrc;
  	tty->termios->c_cc[VQUIT] = tmp.t_quitc;
  	tty->termios->c_cc[VSTART] = tmp.t_startc;
  	tty->termios->c_cc[VSTOP] = tmp.t_stopc;
  	tty->termios->c_cc[VEOF] = tmp.t_eofc;
  	tty->termios->c_cc[VEOL2] = tmp.t_brkc;	/* what is brkc anyway? */
978e595f8   Alan Cox   tty/serial: lay t...
798
  	mutex_unlock(&tty->termios_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
801
802
803
  	return 0;
  }
  #endif
  
  #ifdef TIOCGLTC
355d95a1c   Alan Cox   tty_ioctl: drag s...
804
  static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
806
  {
  	struct ltchars tmp;
978e595f8   Alan Cox   tty/serial: lay t...
807
  	mutex_lock(&tty->termios_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  	tmp.t_suspc = tty->termios->c_cc[VSUSP];
355d95a1c   Alan Cox   tty_ioctl: drag s...
809
810
  	/* what is dsuspc anyway? */
  	tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
  	tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
355d95a1c   Alan Cox   tty_ioctl: drag s...
812
813
  	/* what is flushc anyway? */
  	tmp.t_flushc = tty->termios->c_cc[VEOL2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
  	tmp.t_werasc = tty->termios->c_cc[VWERASE];
  	tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
978e595f8   Alan Cox   tty/serial: lay t...
816
  	mutex_unlock(&tty->termios_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
  	return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
  }
355d95a1c   Alan Cox   tty_ioctl: drag s...
819
  static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
823
824
  {
  	struct ltchars tmp;
  
  	if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
  		return -EFAULT;
978e595f8   Alan Cox   tty/serial: lay t...
825
  	mutex_lock(&tty->termios_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  	tty->termios->c_cc[VSUSP] = tmp.t_suspc;
355d95a1c   Alan Cox   tty_ioctl: drag s...
827
828
  	/* what is dsuspc anyway? */
  	tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  	tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
355d95a1c   Alan Cox   tty_ioctl: drag s...
830
831
  	/* what is flushc anyway? */
  	tty->termios->c_cc[VEOL2] = tmp.t_flushc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
833
  	tty->termios->c_cc[VWERASE] = tmp.t_werasc;
  	tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
978e595f8   Alan Cox   tty/serial: lay t...
834
  	mutex_unlock(&tty->termios_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
  	return 0;
  }
  #endif
af9b897ee   Alan Cox   [PATCH] tty layer...
838
839
840
841
842
  /**
   *	send_prio_char		-	send priority character
   *
   *	Send a high priority character to the tty even if stopped
   *
5f412b242   Alan Cox   [PATCH] Fix locki...
843
   *	Locking: none for xchar method, write ordering for write method.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
   */
af9b897ee   Alan Cox   [PATCH] tty layer...
845

5f412b242   Alan Cox   [PATCH] Fix locki...
846
  static int send_prio_char(struct tty_struct *tty, char ch)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
  {
  	int	was_stopped = tty->stopped;
f34d7a5b7   Alan Cox   tty: The big oper...
849
850
  	if (tty->ops->send_xchar) {
  		tty->ops->send_xchar(tty, ch);
5f412b242   Alan Cox   [PATCH] Fix locki...
851
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
  	}
5f412b242   Alan Cox   [PATCH] Fix locki...
853

9c1729db3   Alan Cox   Prevent an O_NDEL...
854
  	if (tty_write_lock(tty, 0) < 0)
5f412b242   Alan Cox   [PATCH] Fix locki...
855
  		return -ERESTARTSYS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
857
  	if (was_stopped)
  		start_tty(tty);
f34d7a5b7   Alan Cox   tty: The big oper...
858
  	tty->ops->write(tty, &ch, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
  	if (was_stopped)
  		stop_tty(tty);
9c1729db3   Alan Cox   Prevent an O_NDEL...
861
  	tty_write_unlock(tty);
5f412b242   Alan Cox   [PATCH] Fix locki...
862
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  }
0fc00e244   Alan Cox   [TTY]: Fix networ...
864
  /**
1c2630ccf   Alan Cox   tty_ioctl: soft c...
865
866
867
868
869
870
871
872
873
874
875
876
   *	tty_change_softcar	-	carrier change ioctl helper
   *	@tty: tty to update
   *	@arg: enable/disable CLOCAL
   *
   *	Perform a change to the CLOCAL state and call into the driver
   *	layer to make it visible. All done with the termios mutex
   */
  
  static int tty_change_softcar(struct tty_struct *tty, int arg)
  {
  	int ret = 0;
  	int bit = arg ? CLOCAL : 0;
f34d7a5b7   Alan Cox   tty: The big oper...
877
  	struct ktermios old;
1c2630ccf   Alan Cox   tty_ioctl: soft c...
878
879
  
  	mutex_lock(&tty->termios_mutex);
f34d7a5b7   Alan Cox   tty: The big oper...
880
  	old = *tty->termios;
1c2630ccf   Alan Cox   tty_ioctl: soft c...
881
882
  	tty->termios->c_cflag &= ~CLOCAL;
  	tty->termios->c_cflag |= bit;
f34d7a5b7   Alan Cox   tty: The big oper...
883
884
  	if (tty->ops->set_termios)
  		tty->ops->set_termios(tty, &old);
1c2630ccf   Alan Cox   tty_ioctl: soft c...
885
886
887
888
889
890
891
  	if ((tty->termios->c_cflag & CLOCAL) != bit)
  		ret = -EINVAL;
  	mutex_unlock(&tty->termios_mutex);
  	return ret;
  }
  
  /**
0fc00e244   Alan Cox   [TTY]: Fix networ...
892
893
894
895
896
897
898
899
900
901
   *	tty_mode_ioctl		-	mode related ioctls
   *	@tty: tty for the ioctl
   *	@file: file pointer for the tty
   *	@cmd: command
   *	@arg: ioctl argument
   *
   *	Perform non line discipline specific mode control ioctls. This
   *	is designed to be called by line disciplines to ensure they provide
   *	consistent mode setting.
   */
355d95a1c   Alan Cox   tty_ioctl: drag s...
902
  int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
0fc00e244   Alan Cox   [TTY]: Fix networ...
903
  			unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
  {
355d95a1c   Alan Cox   tty_ioctl: drag s...
905
  	struct tty_struct *real_tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
  	void __user *p = (void __user *)arg;
8f5200218   Alan Cox   tty: Termios lock...
907
  	int ret = 0;
26a2e20f4   Alan Cox   tty: Untangle ter...
908
  	struct ktermios kterm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
911
912
913
914
915
916
917
  
  	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
  	    tty->driver->subtype == PTY_TYPE_MASTER)
  		real_tty = tty->link;
  	else
  		real_tty = tty;
  
  	switch (cmd) {
  #ifdef TIOCGETP
355d95a1c   Alan Cox   tty_ioctl: drag s...
918
919
920
921
922
  	case TIOCGETP:
  		return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
  	case TIOCSETP:
  	case TIOCSETN:
  		return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
  #endif
  #ifdef TIOCGETC
355d95a1c   Alan Cox   tty_ioctl: drag s...
925
926
927
928
  	case TIOCGETC:
  		return get_tchars(real_tty, p);
  	case TIOCSETC:
  		return set_tchars(real_tty, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
  #endif
  #ifdef TIOCGLTC
355d95a1c   Alan Cox   tty_ioctl: drag s...
931
932
933
934
  	case TIOCGLTC:
  		return get_ltchars(real_tty, p);
  	case TIOCSLTC:
  		return set_ltchars(real_tty, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
  #endif
355d95a1c   Alan Cox   tty_ioctl: drag s...
936
937
938
939
940
941
  	case TCSETSF:
  		return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
  	case TCSETSW:
  		return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
  	case TCSETS:
  		return set_termios(real_tty, p, TERMIOS_OLD);
edc6afc54   Alan Cox   [PATCH] tty: swit...
942
  #ifndef TCGETS2
355d95a1c   Alan Cox   tty_ioctl: drag s...
943
  	case TCGETS:
26a2e20f4   Alan Cox   tty: Untangle ter...
944
945
  		copy_termios(real_tty, &kterm);
  		if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
8f5200218   Alan Cox   tty: Termios lock...
946
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
947
  		return ret;
edc6afc54   Alan Cox   [PATCH] tty: swit...
948
  #else
355d95a1c   Alan Cox   tty_ioctl: drag s...
949
  	case TCGETS:
26a2e20f4   Alan Cox   tty: Untangle ter...
950
951
  		copy_termios(real_tty, &kterm);
  		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
8f5200218   Alan Cox   tty: Termios lock...
952
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
953
  		return ret;
355d95a1c   Alan Cox   tty_ioctl: drag s...
954
  	case TCGETS2:
26a2e20f4   Alan Cox   tty: Untangle ter...
955
956
  		copy_termios(real_tty, &kterm);
  		if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
8f5200218   Alan Cox   tty: Termios lock...
957
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
958
  		return ret;
355d95a1c   Alan Cox   tty_ioctl: drag s...
959
960
961
962
963
964
  	case TCSETSF2:
  		return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
  	case TCSETSW2:
  		return set_termios(real_tty, p, TERMIOS_WAIT);
  	case TCSETS2:
  		return set_termios(real_tty, p, 0);
edc6afc54   Alan Cox   [PATCH] tty: swit...
965
  #endif
355d95a1c   Alan Cox   tty_ioctl: drag s...
966
967
968
969
970
971
972
973
  	case TCGETA:
  		return get_termio(real_tty, p);
  	case TCSETAF:
  		return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
  	case TCSETAW:
  		return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
  	case TCSETA:
  		return set_termios(real_tty, p, TERMIOS_TERMIO);
0fc00e244   Alan Cox   [TTY]: Fix networ...
974
  #ifndef TCGETS2
355d95a1c   Alan Cox   tty_ioctl: drag s...
975
  	case TIOCGLCKTRMIOS:
26a2e20f4   Alan Cox   tty: Untangle ter...
976
977
  		copy_termios_locked(real_tty, &kterm);
  		if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
8f5200218   Alan Cox   tty: Termios lock...
978
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
979
  		return ret;
355d95a1c   Alan Cox   tty_ioctl: drag s...
980
981
982
  	case TIOCSLCKTRMIOS:
  		if (!capable(CAP_SYS_ADMIN))
  			return -EPERM;
26a2e20f4   Alan Cox   tty: Untangle ter...
983
984
  		copy_termios_locked(real_tty, &kterm);
  		if (user_termios_to_kernel_termios(&kterm,
355d95a1c   Alan Cox   tty_ioctl: drag s...
985
  					       (struct termios __user *) arg))
26a2e20f4   Alan Cox   tty: Untangle ter...
986
987
988
  			return -EFAULT;
  		mutex_lock(&real_tty->termios_mutex);
  		memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
8f5200218   Alan Cox   tty: Termios lock...
989
  		mutex_unlock(&real_tty->termios_mutex);
26a2e20f4   Alan Cox   tty: Untangle ter...
990
  		return 0;
0fc00e244   Alan Cox   [TTY]: Fix networ...
991
  #else
355d95a1c   Alan Cox   tty_ioctl: drag s...
992
  	case TIOCGLCKTRMIOS:
26a2e20f4   Alan Cox   tty: Untangle ter...
993
994
  		copy_termios_locked(real_tty, &kterm);
  		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
8f5200218   Alan Cox   tty: Termios lock...
995
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
996
  		return ret;
355d95a1c   Alan Cox   tty_ioctl: drag s...
997
998
  	case TIOCSLCKTRMIOS:
  		if (!capable(CAP_SYS_ADMIN))
26a2e20f4   Alan Cox   tty: Untangle ter...
999
1000
1001
  			return -EPERM;
  		copy_termios_locked(real_tty, &kterm);
  		if (user_termios_to_kernel_termios_1(&kterm,
355d95a1c   Alan Cox   tty_ioctl: drag s...
1002
  					       (struct termios __user *) arg))
26a2e20f4   Alan Cox   tty: Untangle ter...
1003
1004
1005
  			return -EFAULT;
  		mutex_lock(&real_tty->termios_mutex);
  		memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
8f5200218   Alan Cox   tty: Termios lock...
1006
1007
  		mutex_unlock(&real_tty->termios_mutex);
  		return ret;
0fc00e244   Alan Cox   [TTY]: Fix networ...
1008
  #endif
1d65b4a08   Alan Cox   tty: Add termiox
1009
  #ifdef TCGETX
5dca607bc   Mike Frysinger   tty: fix unused w...
1010
1011
  	case TCGETX: {
  		struct termiox ktermx;
1d65b4a08   Alan Cox   tty: Add termiox
1012
1013
  		if (real_tty->termiox == NULL)
  			return -EINVAL;
8f5200218   Alan Cox   tty: Termios lock...
1014
  		mutex_lock(&real_tty->termios_mutex);
26a2e20f4   Alan Cox   tty: Untangle ter...
1015
  		memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
8f5200218   Alan Cox   tty: Termios lock...
1016
  		mutex_unlock(&real_tty->termios_mutex);
26a2e20f4   Alan Cox   tty: Untangle ter...
1017
1018
  		if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
  			ret = -EFAULT;
8f5200218   Alan Cox   tty: Termios lock...
1019
  		return ret;
5dca607bc   Mike Frysinger   tty: fix unused w...
1020
  	}
1d65b4a08   Alan Cox   tty: Add termiox
1021
1022
1023
1024
1025
1026
1027
  	case TCSETX:
  		return set_termiox(real_tty, p, 0);
  	case TCSETXW:
  		return set_termiox(real_tty, p, TERMIOS_WAIT);
  	case TCSETXF:
  		return set_termiox(real_tty, p, TERMIOS_FLUSH);
  #endif		
355d95a1c   Alan Cox   tty_ioctl: drag s...
1028
  	case TIOCGSOFTCAR:
26a2e20f4   Alan Cox   tty: Untangle ter...
1029
1030
  		copy_termios(real_tty, &kterm);
  		ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
355d95a1c   Alan Cox   tty_ioctl: drag s...
1031
  						(int __user *)arg);
8f5200218   Alan Cox   tty: Termios lock...
1032
  		return ret;
355d95a1c   Alan Cox   tty_ioctl: drag s...
1033
1034
1035
  	case TIOCSSOFTCAR:
  		if (get_user(arg, (unsigned int __user *) arg))
  			return -EFAULT;
f753f3272   Alan Cox   tty: TIOCGSOFTCAR...
1036
  		return tty_change_softcar(real_tty, arg);
355d95a1c   Alan Cox   tty_ioctl: drag s...
1037
1038
  	default:
  		return -ENOIOCTLCMD;
0fc00e244   Alan Cox   [TTY]: Fix networ...
1039
1040
  	}
  }
0fc00e244   Alan Cox   [TTY]: Fix networ...
1041
1042
1043
1044
1045
1046
1047
1048
  EXPORT_SYMBOL_GPL(tty_mode_ioctl);
  
  int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
  {
  	struct tty_ldisc *ld;
  	int retval = tty_check_change(tty);
  	if (retval)
  		return retval;
c0253eec2   Alan Cox   tty: Fix race in ...
1049
  	ld = tty_ldisc_ref_wait(tty);
0fc00e244   Alan Cox   [TTY]: Fix networ...
1050
1051
  	switch (arg) {
  	case TCIFLUSH:
a352def21   Alan Cox   tty: Ldisc revamp
1052
1053
  		if (ld && ld->ops->flush_buffer)
  			ld->ops->flush_buffer(tty);
0fc00e244   Alan Cox   [TTY]: Fix networ...
1054
1055
  		break;
  	case TCIOFLUSH:
a352def21   Alan Cox   tty: Ldisc revamp
1056
1057
  		if (ld && ld->ops->flush_buffer)
  			ld->ops->flush_buffer(tty);
0fc00e244   Alan Cox   [TTY]: Fix networ...
1058
1059
  		/* fall through */
  	case TCOFLUSH:
f34d7a5b7   Alan Cox   tty: The big oper...
1060
  		tty_driver_flush_buffer(tty);
0fc00e244   Alan Cox   [TTY]: Fix networ...
1061
1062
1063
1064
1065
1066
1067
1068
  		break;
  	default:
  		tty_ldisc_deref(ld);
  		return -EINVAL;
  	}
  	tty_ldisc_deref(ld);
  	return 0;
  }
0fc00e244   Alan Cox   [TTY]: Fix networ...
1069
  EXPORT_SYMBOL_GPL(tty_perform_flush);
47afa7a5a   Alan Cox   tty: some ICANON ...
1070
  int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
0fc00e244   Alan Cox   [TTY]: Fix networ...
1071
1072
  		       unsigned int cmd, unsigned long arg)
  {
04f378b19   Alan Cox   tty: BKL pushdown
1073
  	unsigned long flags;
0fc00e244   Alan Cox   [TTY]: Fix networ...
1074
  	int retval;
0fc00e244   Alan Cox   [TTY]: Fix networ...
1075
  	switch (cmd) {
355d95a1c   Alan Cox   tty_ioctl: drag s...
1076
1077
1078
1079
1080
1081
1082
1083
1084
  	case TCXONC:
  		retval = tty_check_change(tty);
  		if (retval)
  			return retval;
  		switch (arg) {
  		case TCOOFF:
  			if (!tty->flow_stopped) {
  				tty->flow_stopped = 1;
  				stop_tty(tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
  			}
355d95a1c   Alan Cox   tty_ioctl: drag s...
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  			break;
  		case TCOON:
  			if (tty->flow_stopped) {
  				tty->flow_stopped = 0;
  				start_tty(tty);
  			}
  			break;
  		case TCIOFF:
  			if (STOP_CHAR(tty) != __DISABLED_CHAR)
  				return send_prio_char(tty, STOP_CHAR(tty));
  			break;
  		case TCION:
  			if (START_CHAR(tty) != __DISABLED_CHAR)
  				return send_prio_char(tty, START_CHAR(tty));
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
  		default:
355d95a1c   Alan Cox   tty_ioctl: drag s...
1102
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
  		}
355d95a1c   Alan Cox   tty_ioctl: drag s...
1104
1105
1106
  		return 0;
  	case TCFLSH:
  		return tty_perform_flush(tty, arg);
355d95a1c   Alan Cox   tty_ioctl: drag s...
1107
1108
1109
1110
1111
1112
1113
1114
1115
  	case TIOCPKT:
  	{
  		int pktmode;
  
  		if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
  		    tty->driver->subtype != PTY_TYPE_MASTER)
  			return -ENOTTY;
  		if (get_user(pktmode, (int __user *) arg))
  			return -EFAULT;
04f378b19   Alan Cox   tty: BKL pushdown
1116
  		spin_lock_irqsave(&tty->ctrl_lock, flags);
355d95a1c   Alan Cox   tty_ioctl: drag s...
1117
1118
1119
1120
1121
1122
1123
  		if (pktmode) {
  			if (!tty->packet) {
  				tty->packet = 1;
  				tty->link->ctrl_status = 0;
  			}
  		} else
  			tty->packet = 0;
04f378b19   Alan Cox   tty: BKL pushdown
1124
  		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
355d95a1c   Alan Cox   tty_ioctl: drag s...
1125
1126
1127
1128
1129
1130
  		return 0;
  	}
  	default:
  		/* Try the mode commands */
  		return tty_mode_ioctl(tty, file, cmd, arg);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
  }
47afa7a5a   Alan Cox   tty: some ICANON ...
1132
  EXPORT_SYMBOL(n_tty_ioctl_helper);