mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
serial_core: fix uart PORT_UNKNOWN handling
While porting a RS485 driver from 2.6.29 to 3.14, i noticed that the serial tty driver could break it by using uart ports that it does not own : 1. uart_change_pm ist called during uart_open and calls the uart pm function without checking for PORT_UNKNOWN. The fix is to move uart_change_pm from uart_open to uart_port_startup. 2. The return code from the uart request_port call in uart_set_info is not handled properly, leading to the situation that the serial driver also thinks it owns the uart ports. This can triggered by doing following actions : setserial /dev/ttyS0 uart none # release the uart ports modprobe lirc-serial # or any other device that uses the uart setserial /dev/ttyS0 uart 16550 # gives no error and the uart tty driver # can use the ports as well Signed-off-by: Thomas Pfaff <tpfaff@pcs.com> Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
f94b057268
commit
7deb39ed8d
1 changed files with 21 additions and 18 deletions
|
@ -136,6 +136,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
|||
if (uport->type == PORT_UNKNOWN)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Make sure the device is in D0 state.
|
||||
*/
|
||||
uart_change_pm(state, UART_PM_STATE_ON);
|
||||
|
||||
/*
|
||||
* Initialise and allocate the transmit and temporary
|
||||
* buffer.
|
||||
|
@ -825,25 +830,29 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
|
|||
* If we fail to request resources for the
|
||||
* new port, try to restore the old settings.
|
||||
*/
|
||||
if (retval && old_type != PORT_UNKNOWN) {
|
||||
if (retval) {
|
||||
uport->iobase = old_iobase;
|
||||
uport->type = old_type;
|
||||
uport->hub6 = old_hub6;
|
||||
uport->iotype = old_iotype;
|
||||
uport->regshift = old_shift;
|
||||
uport->mapbase = old_mapbase;
|
||||
retval = uport->ops->request_port(uport);
|
||||
/*
|
||||
* If we failed to restore the old settings,
|
||||
* we fail like this.
|
||||
*/
|
||||
if (retval)
|
||||
uport->type = PORT_UNKNOWN;
|
||||
|
||||
/*
|
||||
* We failed anyway.
|
||||
*/
|
||||
retval = -EBUSY;
|
||||
if (old_type != PORT_UNKNOWN) {
|
||||
retval = uport->ops->request_port(uport);
|
||||
/*
|
||||
* If we failed to restore the old settings,
|
||||
* we fail like this.
|
||||
*/
|
||||
if (retval)
|
||||
uport->type = PORT_UNKNOWN;
|
||||
|
||||
/*
|
||||
* We failed anyway.
|
||||
*/
|
||||
retval = -EBUSY;
|
||||
}
|
||||
|
||||
/* Added to return the correct error -Ram Gupta */
|
||||
goto exit;
|
||||
}
|
||||
|
@ -1570,12 +1579,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
|
|||
goto err_dec_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the device is in D0 state.
|
||||
*/
|
||||
if (port->count == 1)
|
||||
uart_change_pm(state, UART_PM_STATE_ON);
|
||||
|
||||
/*
|
||||
* Start up the serial port.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue