aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_ioctl.c
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2007-10-17 02:30:07 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 11:42:58 -0400
commit5f519d728169fa9975bcba001de425f11e18e8e3 (patch)
tree41631c3b5a7a2fb5273dc758a3f4e1bb0fdcd540 /drivers/char/tty_ioctl.c
parentca025282e9f13471cd4bf44d854bbd6dcbcb39c1 (diff)
tty: expose new methods needed for drivers to get termios right
This adds three new functions (or in one case to be more exact makes it always available) tty_termios_copy_hw Copies all the hardware settings from one termios structure to the other. This is intended for drivers that support little or no hardware setting tty_termios_encode_baud_rate Allows you to set the input and output baud rate in a termios structure. A driver is supposed to set the resulting baud rate from a request so most will want to use this function to set the resulting input and output rates to match the hardware values. Internally it knows about keeping Bxxx encoding when possible to maximise compatibility. tty_encode_baud_rate As above but for the tty's own current termios structure I suspect this will initially need some tweaking as it gets enabled by driver patches over the next few mm cycles so consider this lot -mm only for the moment so it can stabilize and end up neat before it goes to base. I've tried not to break any obscure architectures - if you get a speed you can't represent the code will print warnings on non updated termios systems but not break. Once this is merged and seems sane I've got a growing pile of driver updates to use it - notably for USB serial drivers. [akpm@linux-foundation.org: cleanups] Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/tty_ioctl.c')
-rw-r--r--drivers/char/tty_ioctl.c82
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
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