aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/tty_ioctl.c82
-rw-r--r--include/linux/tty.h3
2 files changed, 75 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
207EXPORT_SYMBOL(tty_termios_input_baud_rate); 207EXPORT_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
230void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud) 231void 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
273EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); 302EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
274 303
275#endif 304void 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}
308EXPORT_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)
304EXPORT_SYMBOL(tty_get_baud_rate); 337EXPORT_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
350void 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
360EXPORT_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
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 274b40ff0cd8..56164d7ba0ad 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -316,6 +316,9 @@ extern void tty_flip_buffer_push(struct tty_struct *tty);
316extern speed_t tty_get_baud_rate(struct tty_struct *tty); 316extern speed_t tty_get_baud_rate(struct tty_struct *tty);
317extern speed_t tty_termios_baud_rate(struct ktermios *termios); 317extern speed_t tty_termios_baud_rate(struct ktermios *termios);
318extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); 318extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
319extern void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud);
320extern void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud);
321extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
319 322
320extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *); 323extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
321extern void tty_ldisc_deref(struct tty_ldisc *); 324extern void tty_ldisc_deref(struct tty_ldisc *);