diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/tty_ioctl.c | 45 |
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); | |||
242 | void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud) | 245 | void 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 | ||