aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-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