diff options
Diffstat (limited to 'drivers/char/tty_ioctl.c')
-rw-r--r-- | drivers/char/tty_ioctl.c | 82 |
1 files changed, 72 insertions, 10 deletions
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 3ee73cf64bd2..745d552620bf 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -206,8 +206,6 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios) | |||
206 | 206 | ||
207 | EXPORT_SYMBOL(tty_termios_input_baud_rate); | 207 | EXPORT_SYMBOL(tty_termios_input_baud_rate); |
208 | 208 | ||
209 | #ifdef BOTHER | ||
210 | |||
211 | /** | 209 | /** |
212 | * tty_termios_encode_baud_rate | 210 | * tty_termios_encode_baud_rate |
213 | * @termios: ktermios structure holding user requested state | 211 | * @termios: ktermios structure holding user requested state |
@@ -225,6 +223,9 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate); | |||
225 | * | 223 | * |
226 | * Locking: Caller should hold termios lock. This is already held | 224 | * Locking: Caller should hold termios lock. This is already held |
227 | * when calling this function from the driver termios handler. | 225 | * when calling this function from the driver termios handler. |
226 | * | ||
227 | * The ifdefs deal with platforms whose owners have yet to update them | ||
228 | * and will all go away once this is done. | ||
228 | */ | 229 | */ |
229 | 230 | ||
230 | void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud) | 231 | void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud) |
@@ -234,9 +235,13 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed | |||
234 | int iclose = ibaud/50, oclose = obaud/50; | 235 | int iclose = ibaud/50, oclose = obaud/50; |
235 | int ibinput = 0; | 236 | int ibinput = 0; |
236 | 237 | ||
238 | if (obaud == 0) /* CD dropped */ | ||
239 | ibaud = 0; /* Clear ibaud to be sure */ | ||
240 | |||
237 | termios->c_ispeed = ibaud; | 241 | termios->c_ispeed = ibaud; |
238 | termios->c_ospeed = obaud; | 242 | termios->c_ospeed = obaud; |
239 | 243 | ||
244 | #ifdef BOTHER | ||
240 | /* If the user asked for a precise weird speed give a precise weird | 245 | /* If the user asked for a precise weird speed give a precise weird |
241 | answer. If they asked for a Bfoo speed they many have problems | 246 | answer. If they asked for a Bfoo speed they many have problems |
242 | digesting non-exact replies so fuzz a bit */ | 247 | digesting non-exact replies so fuzz a bit */ |
@@ -247,32 +252,60 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed | |||
247 | iclose = 0; | 252 | iclose = 0; |
248 | if ((termios->c_cflag >> IBSHIFT) & CBAUD) | 253 | if ((termios->c_cflag >> IBSHIFT) & CBAUD) |
249 | ibinput = 1; /* An input speed was specified */ | 254 | ibinput = 1; /* An input speed was specified */ |
250 | 255 | #endif | |
251 | termios->c_cflag &= ~CBAUD; | 256 | termios->c_cflag &= ~CBAUD; |
252 | 257 | ||
258 | /* | ||
259 | * Our goal is to find a close match to the standard baud rate | ||
260 | * returned. Walk the baud rate table and if we get a very close | ||
261 | * match then report back the speed as a POSIX Bxxxx value by | ||
262 | * preference | ||
263 | */ | ||
264 | |||
253 | do { | 265 | do { |
254 | if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) { | 266 | if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) { |
255 | termios->c_cflag |= baud_bits[i]; | 267 | termios->c_cflag |= baud_bits[i]; |
256 | ofound = i; | 268 | ofound = i; |
257 | } | 269 | } |
258 | if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) { | 270 | if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) { |
259 | /* For the case input == output don't set IBAUD bits if the user didn't do so */ | 271 | if (ofound == i && !ibinput) |
260 | if (ofound != i || ibinput) | 272 | ifound = i; |
273 | #ifdef IBSHIFT | ||
274 | else { | ||
275 | ifound = i; | ||
261 | termios->c_cflag |= (baud_bits[i] << IBSHIFT); | 276 | termios->c_cflag |= (baud_bits[i] << IBSHIFT); |
262 | ifound = i; | 277 | } |
278 | #endif | ||
263 | } | 279 | } |
264 | } while (++i < n_baud_table); | 280 | } while (++i < n_baud_table); |
281 | |||
282 | /* | ||
283 | * If we found no match then use BOTHER if provided or warn | ||
284 | * the user their platform maintainer needs to wake up if not. | ||
285 | */ | ||
286 | #ifdef BOTHER | ||
265 | if (ofound == -1) | 287 | if (ofound == -1) |
266 | termios->c_cflag |= BOTHER; | 288 | termios->c_cflag |= BOTHER; |
267 | /* Set exact input bits only if the input and output differ or the | 289 | /* Set exact input bits only if the input and output differ or the |
268 | user already did */ | 290 | user already did */ |
269 | if (ifound == -1 && (ibaud != obaud || ibinput)) | 291 | if (ifound == -1 && (ibaud != obaud || ibinput)) |
270 | termios->c_cflag |= (BOTHER << IBSHIFT); | 292 | termios->c_cflag |= (BOTHER << IBSHIFT); |
293 | #else | ||
294 | if (ifound == -1 || ofound == -1) { | ||
295 | static int warned; | ||
296 | if (!warned++) | ||
297 | printk(KERN_WARNING "tty: Unable to return correct " | ||
298 | "speed data as your architecture needs updating.\n"); | ||
299 | } | ||
300 | #endif | ||
271 | } | 301 | } |
272 | |||
273 | EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); | 302 | EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); |
274 | 303 | ||
275 | #endif | 304 | void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) |
305 | { | ||
306 | tty_termios_encode_baud_rate(tty->termios, ibaud, obaud); | ||
307 | } | ||
308 | EXPORT_SYMBOL_GPL(tty_encode_baud_rate); | ||
276 | 309 | ||
277 | /** | 310 | /** |
278 | * tty_get_baud_rate - get tty bit rates | 311 | * tty_get_baud_rate - get tty bit rates |
@@ -304,6 +337,29 @@ speed_t tty_get_baud_rate(struct tty_struct *tty) | |||
304 | EXPORT_SYMBOL(tty_get_baud_rate); | 337 | EXPORT_SYMBOL(tty_get_baud_rate); |
305 | 338 | ||
306 | /** | 339 | /** |
340 | * tty_termios_copy_hw - copy hardware settings | ||
341 | * @new: New termios | ||
342 | * @old: Old termios | ||
343 | * | ||
344 | * Propogate the hardware specific terminal setting bits from | ||
345 | * the old termios structure to the new one. This is used in cases | ||
346 | * where the hardware does not support reconfiguration or as a helper | ||
347 | * in some cases where only minimal reconfiguration is supported | ||
348 | */ | ||
349 | |||
350 | void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old) | ||
351 | { | ||
352 | /* The bits a dumb device handles in software. Smart devices need | ||
353 | to always provide a set_termios method */ | ||
354 | new->c_cflag &= HUPCL | CREAD | CLOCAL; | ||
355 | new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL); | ||
356 | new->c_ispeed = old->c_ispeed; | ||
357 | new->c_ospeed = old->c_ospeed; | ||
358 | } | ||
359 | |||
360 | EXPORT_SYMBOL(tty_termios_copy_hw); | ||
361 | |||
362 | /** | ||
307 | * change_termios - update termios values | 363 | * change_termios - update termios values |
308 | * @tty: tty to update | 364 | * @tty: tty to update |
309 | * @new_termios: desired new value | 365 | * @new_termios: desired new value |
@@ -340,13 +396,12 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio | |||
340 | tty->erasing = 0; | 396 | tty->erasing = 0; |
341 | } | 397 | } |
342 | 398 | ||
343 | 399 | /* This bit should be in the ldisc code */ | |
344 | if (canon_change && !L_ICANON(tty) && tty->read_cnt) | 400 | if (canon_change && !L_ICANON(tty) && tty->read_cnt) |
345 | /* Get characters left over from canonical mode. */ | 401 | /* Get characters left over from canonical mode. */ |
346 | wake_up_interruptible(&tty->read_wait); | 402 | wake_up_interruptible(&tty->read_wait); |
347 | 403 | ||
348 | /* See if packet mode change of state. */ | 404 | /* See if packet mode change of state. */ |
349 | |||
350 | if (tty->link && tty->link->packet) { | 405 | if (tty->link && tty->link->packet) { |
351 | int old_flow = ((old_termios.c_iflag & IXON) && | 406 | int old_flow = ((old_termios.c_iflag & IXON) && |
352 | (old_termios.c_cc[VSTOP] == '\023') && | 407 | (old_termios.c_cc[VSTOP] == '\023') && |
@@ -366,6 +421,8 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio | |||
366 | 421 | ||
367 | if (tty->driver->set_termios) | 422 | if (tty->driver->set_termios) |
368 | (*tty->driver->set_termios)(tty, &old_termios); | 423 | (*tty->driver->set_termios)(tty, &old_termios); |
424 | else | ||
425 | tty_termios_copy_hw(tty->termios, &old_termios); | ||
369 | 426 | ||
370 | ld = tty_ldisc_ref(tty); | 427 | ld = tty_ldisc_ref(tty); |
371 | if (ld != NULL) { | 428 | if (ld != NULL) { |
@@ -440,6 +497,11 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt) | |||
440 | } | 497 | } |
441 | 498 | ||
442 | change_termios(tty, &tmp_termios); | 499 | change_termios(tty, &tmp_termios); |
500 | |||
501 | /* FIXME: Arguably if tmp_termios == tty->termios AND the | ||
502 | actual requested termios was not tmp_termios then we may | ||
503 | want to return an error as no user requested change has | ||
504 | succeeded */ | ||
443 | return 0; | 505 | return 0; |
444 | } | 506 | } |
445 | 507 | ||