diff options
Diffstat (limited to 'drivers/char/tty_ioctl.c')
-rw-r--r-- | drivers/char/tty_ioctl.c | 299 |
1 files changed, 269 insertions, 30 deletions
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 4ad47d321bd4..dee47f40c6a3 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/bitops.h> | 22 | #include <linux/bitops.h> |
23 | #include <linux/mutex.h> | ||
23 | 24 | ||
24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
25 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
@@ -35,6 +36,7 @@ | |||
35 | #define TERMIOS_FLUSH 1 | 36 | #define TERMIOS_FLUSH 1 |
36 | #define TERMIOS_WAIT 2 | 37 | #define TERMIOS_WAIT 2 |
37 | #define TERMIOS_TERMIO 4 | 38 | #define TERMIOS_TERMIO 4 |
39 | #define TERMIOS_OLD 8 | ||
38 | 40 | ||
39 | 41 | ||
40 | /** | 42 | /** |
@@ -83,9 +85,9 @@ stop_waiting: | |||
83 | 85 | ||
84 | EXPORT_SYMBOL(tty_wait_until_sent); | 86 | EXPORT_SYMBOL(tty_wait_until_sent); |
85 | 87 | ||
86 | static void unset_locked_termios(struct termios *termios, | 88 | static void unset_locked_termios(struct ktermios *termios, |
87 | struct termios *old, | 89 | struct ktermios *old, |
88 | struct termios *locked) | 90 | struct ktermios *locked) |
89 | { | 91 | { |
90 | int i; | 92 | int i; |
91 | 93 | ||
@@ -104,8 +106,204 @@ static void unset_locked_termios(struct termios *termios, | |||
104 | for (i=0; i < NCCS; i++) | 106 | for (i=0; i < NCCS; i++) |
105 | termios->c_cc[i] = locked->c_cc[i] ? | 107 | termios->c_cc[i] = locked->c_cc[i] ? |
106 | old->c_cc[i] : termios->c_cc[i]; | 108 | old->c_cc[i] : termios->c_cc[i]; |
109 | /* FIXME: What should we do for i/ospeed */ | ||
107 | } | 110 | } |
108 | 111 | ||
112 | /* | ||
113 | * Routine which returns the baud rate of the tty | ||
114 | * | ||
115 | * Note that the baud_table needs to be kept in sync with the | ||
116 | * include/asm/termbits.h file. | ||
117 | */ | ||
118 | static const speed_t baud_table[] = { | ||
119 | 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, | ||
120 | 9600, 19200, 38400, 57600, 115200, 230400, 460800, | ||
121 | #ifdef __sparc__ | ||
122 | 76800, 153600, 307200, 614400, 921600 | ||
123 | #else | ||
124 | 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, | ||
125 | 2500000, 3000000, 3500000, 4000000 | ||
126 | #endif | ||
127 | }; | ||
128 | |||
129 | #ifndef __sparc__ | ||
130 | static const tcflag_t baud_bits[] = { | ||
131 | B0, B50, B75, B110, B134, B150, B200, B300, B600, | ||
132 | B1200, B1800, B2400, B4800, B9600, B19200, B38400, | ||
133 | B57600, B115200, B230400, B460800, B500000, B576000, | ||
134 | B921600, B1000000, B1152000, B1500000, B2000000, B2500000, | ||
135 | B3000000, B3500000, B4000000 | ||
136 | }; | ||
137 | #else | ||
138 | static const tcflag_t baud_bits[] = { | ||
139 | B0, B50, B75, B110, B134, B150, B200, B300, B600, | ||
140 | B1200, B1800, B2400, B4800, B9600, B19200, B38400, | ||
141 | B57600, B115200, B230400, B460800, B76800, B153600, | ||
142 | B307200, B614400, B921600 | ||
143 | }; | ||
144 | #endif | ||
145 | |||
146 | static int n_baud_table = ARRAY_SIZE(baud_table); | ||
147 | |||
148 | /** | ||
149 | * tty_termios_baud_rate | ||
150 | * @termios: termios structure | ||
151 | * | ||
152 | * Convert termios baud rate data into a speed. This should be called | ||
153 | * with the termios lock held if this termios is a terminal termios | ||
154 | * structure. May change the termios data. Device drivers can call this | ||
155 | * function but should use ->c_[io]speed directly as they are updated. | ||
156 | * | ||
157 | * Locking: none | ||
158 | */ | ||
159 | |||
160 | speed_t tty_termios_baud_rate(struct ktermios *termios) | ||
161 | { | ||
162 | unsigned int cbaud; | ||
163 | |||
164 | cbaud = termios->c_cflag & CBAUD; | ||
165 | |||
166 | #ifdef BOTHER | ||
167 | /* Magic token for arbitary speed via c_ispeed/c_ospeed */ | ||
168 | if (cbaud == BOTHER) | ||
169 | return termios->c_ospeed; | ||
170 | #endif | ||
171 | if (cbaud & CBAUDEX) { | ||
172 | cbaud &= ~CBAUDEX; | ||
173 | |||
174 | if (cbaud < 1 || cbaud + 15 > n_baud_table) | ||
175 | termios->c_cflag &= ~CBAUDEX; | ||
176 | else | ||
177 | cbaud += 15; | ||
178 | } | ||
179 | return baud_table[cbaud]; | ||
180 | } | ||
181 | |||
182 | EXPORT_SYMBOL(tty_termios_baud_rate); | ||
183 | |||
184 | /** | ||
185 | * tty_termios_input_baud_rate | ||
186 | * @termios: termios structure | ||
187 | * | ||
188 | * Convert termios baud rate data into a speed. This should be called | ||
189 | * with the termios lock held if this termios is a terminal termios | ||
190 | * structure. May change the termios data. Device drivers can call this | ||
191 | * function but should use ->c_[io]speed directly as they are updated. | ||
192 | * | ||
193 | * Locking: none | ||
194 | */ | ||
195 | |||
196 | speed_t tty_termios_input_baud_rate(struct ktermios *termios) | ||
197 | { | ||
198 | #ifdef IBSHIFT | ||
199 | unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD; | ||
200 | |||
201 | if (cbaud == B0) | ||
202 | return tty_termios_baud_rate(termios); | ||
203 | |||
204 | /* Magic token for arbitary speed via c_ispeed*/ | ||
205 | if (cbaud == BOTHER) | ||
206 | return termios->c_ispeed; | ||
207 | |||
208 | if (cbaud & CBAUDEX) { | ||
209 | cbaud &= ~CBAUDEX; | ||
210 | |||
211 | if (cbaud < 1 || cbaud + 15 > n_baud_table) | ||
212 | termios->c_cflag &= ~(CBAUDEX << IBSHIFT); | ||
213 | else | ||
214 | cbaud += 15; | ||
215 | } | ||
216 | return baud_table[cbaud]; | ||
217 | #else | ||
218 | return tty_termios_baud_rate(termios); | ||
219 | #endif | ||
220 | } | ||
221 | |||
222 | EXPORT_SYMBOL(tty_termios_input_baud_rate); | ||
223 | |||
224 | #ifdef BOTHER | ||
225 | |||
226 | /** | ||
227 | * tty_termios_encode_baud_rate | ||
228 | * @termios: termios structure | ||
229 | * @ispeed: input speed | ||
230 | * @ospeed: output speed | ||
231 | * | ||
232 | * Encode the speeds set into the passed termios structure. This is | ||
233 | * used as a library helper for drivers os that they can report back | ||
234 | * the actual speed selected when it differs from the speed requested | ||
235 | * | ||
236 | * For now input and output speed must agree. | ||
237 | * | ||
238 | * Locking: Caller should hold termios lock. This is already held | ||
239 | * when calling this function from the driver termios handler. | ||
240 | */ | ||
241 | |||
242 | void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud) | ||
243 | { | ||
244 | int i = 0; | ||
245 | int ifound = 0, ofound = 0; | ||
246 | |||
247 | termios->c_ispeed = ibaud; | ||
248 | termios->c_ospeed = obaud; | ||
249 | |||
250 | termios->c_cflag &= ~CBAUD; | ||
251 | /* Identical speed means no input encoding (ie B0 << IBSHIFT)*/ | ||
252 | if (termios->c_ispeed == termios->c_ospeed) | ||
253 | ifound = 1; | ||
254 | |||
255 | do { | ||
256 | if (obaud == baud_table[i]) { | ||
257 | termios->c_cflag |= baud_bits[i]; | ||
258 | ofound = 1; | ||
259 | /* So that if ibaud == obaud we don't set it */ | ||
260 | continue; | ||
261 | } | ||
262 | if (ibaud == baud_table[i]) { | ||
263 | termios->c_cflag |= (baud_bits[i] << IBSHIFT); | ||
264 | ifound = 1; | ||
265 | } | ||
266 | } | ||
267 | while(++i < n_baud_table); | ||
268 | if (!ofound) | ||
269 | termios->c_cflag |= BOTHER; | ||
270 | if (!ifound) | ||
271 | termios->c_cflag |= (BOTHER << IBSHIFT); | ||
272 | } | ||
273 | |||
274 | EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); | ||
275 | |||
276 | #endif | ||
277 | |||
278 | /** | ||
279 | * tty_get_baud_rate - get tty bit rates | ||
280 | * @tty: tty to query | ||
281 | * | ||
282 | * Returns the baud rate as an integer for this terminal. The | ||
283 | * termios lock must be held by the caller and the terminal bit | ||
284 | * flags may be updated. | ||
285 | * | ||
286 | * Locking: none | ||
287 | */ | ||
288 | |||
289 | speed_t tty_get_baud_rate(struct tty_struct *tty) | ||
290 | { | ||
291 | speed_t baud = tty_termios_baud_rate(tty->termios); | ||
292 | |||
293 | if (baud == 38400 && tty->alt_speed) { | ||
294 | if (!tty->warned) { | ||
295 | printk(KERN_WARNING "Use of setserial/setrocket to " | ||
296 | "set SPD_* flags is deprecated\n"); | ||
297 | tty->warned = 1; | ||
298 | } | ||
299 | baud = tty->alt_speed; | ||
300 | } | ||
301 | |||
302 | return baud; | ||
303 | } | ||
304 | |||
305 | EXPORT_SYMBOL(tty_get_baud_rate); | ||
306 | |||
109 | /** | 307 | /** |
110 | * change_termios - update termios values | 308 | * change_termios - update termios values |
111 | * @tty: tty to update | 309 | * @tty: tty to update |
@@ -118,10 +316,10 @@ static void unset_locked_termios(struct termios *termios, | |||
118 | * Locking: termios_sem | 316 | * Locking: termios_sem |
119 | */ | 317 | */ |
120 | 318 | ||
121 | static void change_termios(struct tty_struct * tty, struct termios * new_termios) | 319 | static void change_termios(struct tty_struct * tty, struct ktermios * new_termios) |
122 | { | 320 | { |
123 | int canon_change; | 321 | int canon_change; |
124 | struct termios old_termios = *tty->termios; | 322 | struct ktermios old_termios = *tty->termios; |
125 | struct tty_ldisc *ld; | 323 | struct tty_ldisc *ld; |
126 | 324 | ||
127 | /* | 325 | /* |
@@ -131,7 +329,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios | |||
131 | 329 | ||
132 | /* FIXME: we need to decide on some locking/ordering semantics | 330 | /* FIXME: we need to decide on some locking/ordering semantics |
133 | for the set_termios notification eventually */ | 331 | for the set_termios notification eventually */ |
134 | down(&tty->termios_sem); | 332 | mutex_lock(&tty->termios_mutex); |
135 | 333 | ||
136 | *tty->termios = *new_termios; | 334 | *tty->termios = *new_termios; |
137 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); | 335 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); |
@@ -176,7 +374,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios | |||
176 | (ld->set_termios)(tty, &old_termios); | 374 | (ld->set_termios)(tty, &old_termios); |
177 | tty_ldisc_deref(ld); | 375 | tty_ldisc_deref(ld); |
178 | } | 376 | } |
179 | up(&tty->termios_sem); | 377 | mutex_unlock(&tty->termios_mutex); |
180 | } | 378 | } |
181 | 379 | ||
182 | /** | 380 | /** |
@@ -194,23 +392,39 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios | |||
194 | 392 | ||
195 | static int set_termios(struct tty_struct * tty, void __user *arg, int opt) | 393 | static int set_termios(struct tty_struct * tty, void __user *arg, int opt) |
196 | { | 394 | { |
197 | struct termios tmp_termios; | 395 | struct ktermios tmp_termios; |
198 | struct tty_ldisc *ld; | 396 | struct tty_ldisc *ld; |
199 | int retval = tty_check_change(tty); | 397 | int retval = tty_check_change(tty); |
200 | 398 | ||
201 | if (retval) | 399 | if (retval) |
202 | return retval; | 400 | return retval; |
203 | 401 | ||
402 | memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios)); | ||
403 | |||
204 | if (opt & TERMIOS_TERMIO) { | 404 | if (opt & TERMIOS_TERMIO) { |
205 | memcpy(&tmp_termios, tty->termios, sizeof(struct termios)); | ||
206 | if (user_termio_to_kernel_termios(&tmp_termios, | 405 | if (user_termio_to_kernel_termios(&tmp_termios, |
207 | (struct termio __user *)arg)) | 406 | (struct termio __user *)arg)) |
208 | return -EFAULT; | 407 | return -EFAULT; |
408 | #ifdef TCGETS2 | ||
409 | } else if (opt & TERMIOS_OLD) { | ||
410 | if (user_termios_to_kernel_termios_1(&tmp_termios, | ||
411 | (struct termios __user *)arg)) | ||
412 | return -EFAULT; | ||
209 | } else { | 413 | } else { |
210 | if (user_termios_to_kernel_termios(&tmp_termios, | 414 | if (user_termios_to_kernel_termios(&tmp_termios, |
211 | (struct termios __user *)arg)) | 415 | (struct termios2 __user *)arg)) |
212 | return -EFAULT; | 416 | return -EFAULT; |
213 | } | 417 | } |
418 | #else | ||
419 | } else if (user_termios_to_kernel_termios(&tmp_termios, | ||
420 | (struct termios __user *)arg)) | ||
421 | return -EFAULT; | ||
422 | #endif | ||
423 | |||
424 | /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed | ||
425 | so its unconditionally usable */ | ||
426 | tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); | ||
427 | tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); | ||
214 | 428 | ||
215 | ld = tty_ldisc_ref(tty); | 429 | ld = tty_ldisc_ref(tty); |
216 | 430 | ||
@@ -284,18 +498,18 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) | |||
284 | { | 498 | { |
285 | struct sgttyb tmp; | 499 | struct sgttyb tmp; |
286 | 500 | ||
287 | down(&tty->termios_sem); | 501 | mutex_lock(&tty->termios_mutex); |
288 | tmp.sg_ispeed = 0; | 502 | tmp.sg_ispeed = tty->termios->c_ispeed; |
289 | tmp.sg_ospeed = 0; | 503 | tmp.sg_ospeed = tty->termios->c_ospeed; |
290 | tmp.sg_erase = tty->termios->c_cc[VERASE]; | 504 | tmp.sg_erase = tty->termios->c_cc[VERASE]; |
291 | tmp.sg_kill = tty->termios->c_cc[VKILL]; | 505 | tmp.sg_kill = tty->termios->c_cc[VKILL]; |
292 | tmp.sg_flags = get_sgflags(tty); | 506 | tmp.sg_flags = get_sgflags(tty); |
293 | up(&tty->termios_sem); | 507 | mutex_unlock(&tty->termios_mutex); |
294 | 508 | ||
295 | return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; | 509 | return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; |
296 | } | 510 | } |
297 | 511 | ||
298 | static void set_sgflags(struct termios * termios, int flags) | 512 | static void set_sgflags(struct ktermios * termios, int flags) |
299 | { | 513 | { |
300 | termios->c_iflag = ICRNL | IXON; | 514 | termios->c_iflag = ICRNL | IXON; |
301 | termios->c_oflag = 0; | 515 | termios->c_oflag = 0; |
@@ -336,7 +550,7 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) | |||
336 | { | 550 | { |
337 | int retval; | 551 | int retval; |
338 | struct sgttyb tmp; | 552 | struct sgttyb tmp; |
339 | struct termios termios; | 553 | struct ktermios termios; |
340 | 554 | ||
341 | retval = tty_check_change(tty); | 555 | retval = tty_check_change(tty); |
342 | if (retval) | 556 | if (retval) |
@@ -345,12 +559,16 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) | |||
345 | if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) | 559 | if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) |
346 | return -EFAULT; | 560 | return -EFAULT; |
347 | 561 | ||
348 | down(&tty->termios_sem); | 562 | mutex_lock(&tty->termios_mutex); |
349 | termios = *tty->termios; | 563 | termios = *tty->termios; |
350 | termios.c_cc[VERASE] = tmp.sg_erase; | 564 | termios.c_cc[VERASE] = tmp.sg_erase; |
351 | termios.c_cc[VKILL] = tmp.sg_kill; | 565 | termios.c_cc[VKILL] = tmp.sg_kill; |
352 | set_sgflags(&termios, tmp.sg_flags); | 566 | set_sgflags(&termios, tmp.sg_flags); |
353 | up(&tty->termios_sem); | 567 | /* Try and encode into Bfoo format */ |
568 | #ifdef BOTHER | ||
569 | tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed); | ||
570 | #endif | ||
571 | mutex_unlock(&tty->termios_mutex); | ||
354 | change_termios(tty, &termios); | 572 | change_termios(tty, &termios); |
355 | return 0; | 573 | return 0; |
356 | } | 574 | } |
@@ -422,24 +640,28 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) | |||
422 | * | 640 | * |
423 | * Send a high priority character to the tty even if stopped | 641 | * Send a high priority character to the tty even if stopped |
424 | * | 642 | * |
425 | * Locking: none | 643 | * Locking: none for xchar method, write ordering for write method. |
426 | * | ||
427 | * FIXME: overlapping calls with start/stop tty lose state of tty | ||
428 | */ | 644 | */ |
429 | 645 | ||
430 | static void send_prio_char(struct tty_struct *tty, char ch) | 646 | static int send_prio_char(struct tty_struct *tty, char ch) |
431 | { | 647 | { |
432 | int was_stopped = tty->stopped; | 648 | int was_stopped = tty->stopped; |
433 | 649 | ||
434 | if (tty->driver->send_xchar) { | 650 | if (tty->driver->send_xchar) { |
435 | tty->driver->send_xchar(tty, ch); | 651 | tty->driver->send_xchar(tty, ch); |
436 | return; | 652 | return 0; |
437 | } | 653 | } |
654 | |||
655 | if (mutex_lock_interruptible(&tty->atomic_write_lock)) | ||
656 | return -ERESTARTSYS; | ||
657 | |||
438 | if (was_stopped) | 658 | if (was_stopped) |
439 | start_tty(tty); | 659 | start_tty(tty); |
440 | tty->driver->write(tty, &ch, 1); | 660 | tty->driver->write(tty, &ch, 1); |
441 | if (was_stopped) | 661 | if (was_stopped) |
442 | stop_tty(tty); | 662 | stop_tty(tty); |
663 | mutex_unlock(&tty->atomic_write_lock); | ||
664 | return 0; | ||
443 | } | 665 | } |
444 | 666 | ||
445 | int n_tty_ioctl(struct tty_struct * tty, struct file * file, | 667 | int n_tty_ioctl(struct tty_struct * tty, struct file * file, |
@@ -476,16 +698,33 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, | |||
476 | case TIOCSLTC: | 698 | case TIOCSLTC: |
477 | return set_ltchars(real_tty, p); | 699 | return set_ltchars(real_tty, p); |
478 | #endif | 700 | #endif |
701 | case TCSETSF: | ||
702 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD); | ||
703 | case TCSETSW: | ||
704 | return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD); | ||
705 | case TCSETS: | ||
706 | return set_termios(real_tty, p, TERMIOS_OLD); | ||
707 | #ifndef TCGETS2 | ||
479 | case TCGETS: | 708 | case TCGETS: |
480 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) | 709 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) |
481 | return -EFAULT; | 710 | return -EFAULT; |
482 | return 0; | 711 | return 0; |
483 | case TCSETSF: | 712 | #else |
713 | case TCGETS: | ||
714 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) | ||
715 | return -EFAULT; | ||
716 | return 0; | ||
717 | case TCGETS2: | ||
718 | if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) | ||
719 | return -EFAULT; | ||
720 | return 0; | ||
721 | case TCSETSF2: | ||
484 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); | 722 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); |
485 | case TCSETSW: | 723 | case TCSETSW2: |
486 | return set_termios(real_tty, p, TERMIOS_WAIT); | 724 | return set_termios(real_tty, p, TERMIOS_WAIT); |
487 | case TCSETS: | 725 | case TCSETS2: |
488 | return set_termios(real_tty, p, 0); | 726 | return set_termios(real_tty, p, 0); |
727 | #endif | ||
489 | case TCGETA: | 728 | case TCGETA: |
490 | return get_termio(real_tty, p); | 729 | return get_termio(real_tty, p); |
491 | case TCSETAF: | 730 | case TCSETAF: |
@@ -513,11 +752,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, | |||
513 | break; | 752 | break; |
514 | case TCIOFF: | 753 | case TCIOFF: |
515 | if (STOP_CHAR(tty) != __DISABLED_CHAR) | 754 | if (STOP_CHAR(tty) != __DISABLED_CHAR) |
516 | send_prio_char(tty, STOP_CHAR(tty)); | 755 | return send_prio_char(tty, STOP_CHAR(tty)); |
517 | break; | 756 | break; |
518 | case TCION: | 757 | case TCION: |
519 | if (START_CHAR(tty) != __DISABLED_CHAR) | 758 | if (START_CHAR(tty) != __DISABLED_CHAR) |
520 | send_prio_char(tty, START_CHAR(tty)); | 759 | return send_prio_char(tty, START_CHAR(tty)); |
521 | break; | 760 | break; |
522 | default: | 761 | default: |
523 | return -EINVAL; | 762 | return -EINVAL; |
@@ -592,11 +831,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, | |||
592 | case TIOCSSOFTCAR: | 831 | case TIOCSSOFTCAR: |
593 | if (get_user(arg, (unsigned int __user *) arg)) | 832 | if (get_user(arg, (unsigned int __user *) arg)) |
594 | return -EFAULT; | 833 | return -EFAULT; |
595 | down(&tty->termios_sem); | 834 | mutex_lock(&tty->termios_mutex); |
596 | tty->termios->c_cflag = | 835 | tty->termios->c_cflag = |
597 | ((tty->termios->c_cflag & ~CLOCAL) | | 836 | ((tty->termios->c_cflag & ~CLOCAL) | |
598 | (arg ? CLOCAL : 0)); | 837 | (arg ? CLOCAL : 0)); |
599 | up(&tty->termios_sem); | 838 | mutex_unlock(&tty->termios_mutex); |
600 | return 0; | 839 | return 0; |
601 | default: | 840 | default: |
602 | return -ENOIOCTLCMD; | 841 | return -ENOIOCTLCMD; |