diff options
Diffstat (limited to 'drivers/char/tty_ioctl.c')
-rw-r--r-- | drivers/char/tty_ioctl.c | 258 |
1 files changed, 244 insertions, 14 deletions
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 3b6fa7b0be8b..0ffba4e911ca 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #define TERMIOS_FLUSH 1 | 36 | #define TERMIOS_FLUSH 1 |
37 | #define TERMIOS_WAIT 2 | 37 | #define TERMIOS_WAIT 2 |
38 | #define TERMIOS_TERMIO 4 | 38 | #define TERMIOS_TERMIO 4 |
39 | #define TERMIOS_OLD 8 | ||
39 | 40 | ||
40 | 41 | ||
41 | /** | 42 | /** |
@@ -84,9 +85,9 @@ stop_waiting: | |||
84 | 85 | ||
85 | EXPORT_SYMBOL(tty_wait_until_sent); | 86 | EXPORT_SYMBOL(tty_wait_until_sent); |
86 | 87 | ||
87 | static void unset_locked_termios(struct termios *termios, | 88 | static void unset_locked_termios(struct ktermios *termios, |
88 | struct termios *old, | 89 | struct ktermios *old, |
89 | struct termios *locked) | 90 | struct ktermios *locked) |
90 | { | 91 | { |
91 | int i; | 92 | int i; |
92 | 93 | ||
@@ -105,8 +106,204 @@ static void unset_locked_termios(struct termios *termios, | |||
105 | for (i=0; i < NCCS; i++) | 106 | for (i=0; i < NCCS; i++) |
106 | termios->c_cc[i] = locked->c_cc[i] ? | 107 | termios->c_cc[i] = locked->c_cc[i] ? |
107 | 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 */ | ||
108 | } | 110 | } |
109 | 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 | |||
110 | /** | 307 | /** |
111 | * change_termios - update termios values | 308 | * change_termios - update termios values |
112 | * @tty: tty to update | 309 | * @tty: tty to update |
@@ -119,10 +316,10 @@ static void unset_locked_termios(struct termios *termios, | |||
119 | * Locking: termios_sem | 316 | * Locking: termios_sem |
120 | */ | 317 | */ |
121 | 318 | ||
122 | 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) |
123 | { | 320 | { |
124 | int canon_change; | 321 | int canon_change; |
125 | struct termios old_termios = *tty->termios; | 322 | struct ktermios old_termios = *tty->termios; |
126 | struct tty_ldisc *ld; | 323 | struct tty_ldisc *ld; |
127 | 324 | ||
128 | /* | 325 | /* |
@@ -195,7 +392,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios | |||
195 | 392 | ||
196 | 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) |
197 | { | 394 | { |
198 | struct termios tmp_termios; | 395 | struct ktermios tmp_termios; |
199 | struct tty_ldisc *ld; | 396 | struct tty_ldisc *ld; |
200 | int retval = tty_check_change(tty); | 397 | int retval = tty_check_change(tty); |
201 | 398 | ||
@@ -203,16 +400,28 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt) | |||
203 | return retval; | 400 | return retval; |
204 | 401 | ||
205 | if (opt & TERMIOS_TERMIO) { | 402 | if (opt & TERMIOS_TERMIO) { |
206 | memcpy(&tmp_termios, tty->termios, sizeof(struct termios)); | 403 | memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios)); |
207 | if (user_termio_to_kernel_termios(&tmp_termios, | 404 | if (user_termio_to_kernel_termios(&tmp_termios, |
208 | (struct termio __user *)arg)) | 405 | (struct termio __user *)arg)) |
209 | return -EFAULT; | 406 | return -EFAULT; |
407 | #ifdef TCGETS2 | ||
408 | } else if (opt & TERMIOS_OLD) { | ||
409 | memcpy(&tmp_termios, tty->termios, sizeof(struct termios)); | ||
410 | if (user_termios_to_kernel_termios_1(&tmp_termios, | ||
411 | (struct termios_v1 __user *)arg)) | ||
412 | return -EFAULT; | ||
413 | #endif | ||
210 | } else { | 414 | } else { |
211 | if (user_termios_to_kernel_termios(&tmp_termios, | 415 | if (user_termios_to_kernel_termios(&tmp_termios, |
212 | (struct termios __user *)arg)) | 416 | (struct termios __user *)arg)) |
213 | return -EFAULT; | 417 | return -EFAULT; |
214 | } | 418 | } |
215 | 419 | ||
420 | /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed | ||
421 | so its unconditionally usable */ | ||
422 | tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); | ||
423 | tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); | ||
424 | |||
216 | ld = tty_ldisc_ref(tty); | 425 | ld = tty_ldisc_ref(tty); |
217 | 426 | ||
218 | if (ld != NULL) { | 427 | if (ld != NULL) { |
@@ -286,8 +495,8 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) | |||
286 | struct sgttyb tmp; | 495 | struct sgttyb tmp; |
287 | 496 | ||
288 | mutex_lock(&tty->termios_mutex); | 497 | mutex_lock(&tty->termios_mutex); |
289 | tmp.sg_ispeed = 0; | 498 | tmp.sg_ispeed = tty->c_ispeed; |
290 | tmp.sg_ospeed = 0; | 499 | tmp.sg_ospeed = tty->c_ospeed; |
291 | tmp.sg_erase = tty->termios->c_cc[VERASE]; | 500 | tmp.sg_erase = tty->termios->c_cc[VERASE]; |
292 | tmp.sg_kill = tty->termios->c_cc[VKILL]; | 501 | tmp.sg_kill = tty->termios->c_cc[VKILL]; |
293 | tmp.sg_flags = get_sgflags(tty); | 502 | tmp.sg_flags = get_sgflags(tty); |
@@ -296,7 +505,7 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) | |||
296 | return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; | 505 | return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; |
297 | } | 506 | } |
298 | 507 | ||
299 | static void set_sgflags(struct termios * termios, int flags) | 508 | static void set_sgflags(struct ktermios * termios, int flags) |
300 | { | 509 | { |
301 | termios->c_iflag = ICRNL | IXON; | 510 | termios->c_iflag = ICRNL | IXON; |
302 | termios->c_oflag = 0; | 511 | termios->c_oflag = 0; |
@@ -337,7 +546,7 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) | |||
337 | { | 546 | { |
338 | int retval; | 547 | int retval; |
339 | struct sgttyb tmp; | 548 | struct sgttyb tmp; |
340 | struct termios termios; | 549 | struct ktermios termios; |
341 | 550 | ||
342 | retval = tty_check_change(tty); | 551 | retval = tty_check_change(tty); |
343 | if (retval) | 552 | if (retval) |
@@ -351,6 +560,10 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) | |||
351 | termios.c_cc[VERASE] = tmp.sg_erase; | 560 | termios.c_cc[VERASE] = tmp.sg_erase; |
352 | termios.c_cc[VKILL] = tmp.sg_kill; | 561 | termios.c_cc[VKILL] = tmp.sg_kill; |
353 | set_sgflags(&termios, tmp.sg_flags); | 562 | set_sgflags(&termios, tmp.sg_flags); |
563 | /* Try and encode into Bfoo format */ | ||
564 | #ifdef BOTHER | ||
565 | tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed); | ||
566 | #endif | ||
354 | mutex_unlock(&tty->termios_mutex); | 567 | mutex_unlock(&tty->termios_mutex); |
355 | change_termios(tty, &termios); | 568 | change_termios(tty, &termios); |
356 | return 0; | 569 | return 0; |
@@ -481,16 +694,33 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, | |||
481 | case TIOCSLTC: | 694 | case TIOCSLTC: |
482 | return set_ltchars(real_tty, p); | 695 | return set_ltchars(real_tty, p); |
483 | #endif | 696 | #endif |
697 | case TCSETSF: | ||
698 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD); | ||
699 | case TCSETSW: | ||
700 | return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD); | ||
701 | case TCSETS: | ||
702 | return set_termios(real_tty, p, TERMIOS_OLD); | ||
703 | #ifndef TCGETS2 | ||
484 | case TCGETS: | 704 | case TCGETS: |
485 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) | 705 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) |
486 | return -EFAULT; | 706 | return -EFAULT; |
487 | return 0; | 707 | return 0; |
488 | case TCSETSF: | 708 | #else |
709 | case TCGETS: | ||
710 | if (kernel_termios_to_user_termios_1((struct termios_v1 __user *)arg, real_tty->termios)) | ||
711 | return -EFAULT; | ||
712 | return 0; | ||
713 | case TCGETS2: | ||
714 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) | ||
715 | return -EFAULT; | ||
716 | return 0; | ||
717 | case TCSETSF2: | ||
489 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); | 718 | return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); |
490 | case TCSETSW: | 719 | case TCSETSW2: |
491 | return set_termios(real_tty, p, TERMIOS_WAIT); | 720 | return set_termios(real_tty, p, TERMIOS_WAIT); |
492 | case TCSETS: | 721 | case TCSETS2: |
493 | return set_termios(real_tty, p, 0); | 722 | return set_termios(real_tty, p, 0); |
723 | #endif | ||
494 | case TCGETA: | 724 | case TCGETA: |
495 | return get_termio(real_tty, p); | 725 | return get_termio(real_tty, p); |
496 | case TCSETAF: | 726 | case TCSETAF: |