aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2007-02-10 04:45:57 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-11 13:51:32 -0500
commit78137e3b34e122949e6de36a894fb5843664b8f9 (patch)
treecca5f5409643bf6adbe8387203ed0fa076d36cb1
parent996a07bcb62c5935248e238a1150089f3d99a6fb (diff)
[PATCH] tty: improve encode_baud_rate logic
Mostly so people can see the work in progress. This enhances the encode function which isn't currently used in the base tree but is when using some of the testing tty patches. This resolves a problem with some hardware where applications got confusing information from the tty ioctls. Correct but confusing. In some situations asking for, say, 9600 baud actually gets you 9595 baud or similar near-miss values. With the old code this meant that a request for B9600 got a return of BOTHER, 9595 which programs interpreted as a failure. The new code now works on the following basis - If you ask for specific rate via BOTHER, you get a precise return - If you ask for a standard Bfoo rate and the result is close you get a Bfoo return - If you ask for a standard Bfoo rate and get something way off you get a BOTHER/rate return This seems to fix up the cases I've found where this broke compatibility. 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>
-rw-r--r--drivers/char/tty_ioctl.c45
1 files changed, 30 insertions, 15 deletions
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index dee47f40c6a3..fd471cb3338f 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -225,7 +225,7 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate);
225 225
226/** 226/**
227 * tty_termios_encode_baud_rate 227 * tty_termios_encode_baud_rate
228 * @termios: termios structure 228 * @termios: ktermios structure holding user requested state
229 * @ispeed: input speed 229 * @ispeed: input speed
230 * @ospeed: output speed 230 * @ospeed: output speed
231 * 231 *
@@ -233,7 +233,10 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate);
233 * used as a library helper for drivers os that they can report back 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 234 * the actual speed selected when it differs from the speed requested
235 * 235 *
236 * For now input and output speed must agree. 236 * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
237 * we need to carefully set the bits when the user does not get the
238 * desired speed. We allow small margins and preserve as much of possible
239 * of the input intent to keep compatiblity.
237 * 240 *
238 * Locking: Caller should hold termios lock. This is already held 241 * Locking: Caller should hold termios lock. This is already held
239 * when calling this function from the driver termios handler. 242 * when calling this function from the driver termios handler.
@@ -242,32 +245,44 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate);
242void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud) 245void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
243{ 246{
244 int i = 0; 247 int i = 0;
245 int ifound = 0, ofound = 0; 248 int ifound = -1, ofound = -1;
249 int iclose = ibaud/50, oclose = obaud/50;
250 int ibinput = 0;
246 251
247 termios->c_ispeed = ibaud; 252 termios->c_ispeed = ibaud;
248 termios->c_ospeed = obaud; 253 termios->c_ospeed = obaud;
249 254
255 /* If the user asked for a precise weird speed give a precise weird
256 answer. If they asked for a Bfoo speed they many have problems
257 digesting non-exact replies so fuzz a bit */
258
259 if ((termios->c_cflag & CBAUD) == BOTHER)
260 oclose = 0;
261 if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
262 iclose = 0;
263 if ((termios->c_cflag >> IBSHIFT) & CBAUD)
264 ibinput = 1; /* An input speed was specified */
265
250 termios->c_cflag &= ~CBAUD; 266 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 267
255 do { 268 do {
256 if (obaud == baud_table[i]) { 269 if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) {
257 termios->c_cflag |= baud_bits[i]; 270 termios->c_cflag |= baud_bits[i];
258 ofound = 1; 271 ofound = i;
259 /* So that if ibaud == obaud we don't set it */
260 continue;
261 } 272 }
262 if (ibaud == baud_table[i]) { 273 if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) {
263 termios->c_cflag |= (baud_bits[i] << IBSHIFT); 274 /* For the case input == output don't set IBAUD bits if the user didn't do so */
264 ifound = 1; 275 if (ofound != i || ibinput)
276 termios->c_cflag |= (baud_bits[i] << IBSHIFT);
277 ifound = i;
265 } 278 }
266 } 279 }
267 while(++i < n_baud_table); 280 while(++i < n_baud_table);
268 if (!ofound) 281 if (ofound == -1)
269 termios->c_cflag |= BOTHER; 282 termios->c_cflag |= BOTHER;
270 if (!ifound) 283 /* Set exact input bits only if the input and output differ or the
284 user already did */
285 if (ifound == -1 && (ibaud != obaud || ibinput))
271 termios->c_cflag |= (BOTHER << IBSHIFT); 286 termios->c_cflag |= (BOTHER << IBSHIFT);
272} 287}
273 288