Commit 335f8514 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds
Browse files

tty: Bring the usb tty port structure into more use



This allows us to clean stuff up, but is probably also going to cause
some app breakage with buggy apps as we now implement proper POSIX behaviour
for USB ports matching all the other ports. This does also mean other apps
that break on USB will now work properly.

Signed-off-by: default avatarAlan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 1ec739be
......@@ -93,8 +93,7 @@ static int belkin_sa_startup(struct usb_serial *serial);
static void belkin_sa_shutdown(struct usb_serial *serial);
static int belkin_sa_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void belkin_sa_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void belkin_sa_close(struct usb_serial_port *port);
static void belkin_sa_read_int_callback(struct urb *urb);
static void belkin_sa_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios * old);
......@@ -244,8 +243,7 @@ static int belkin_sa_open(struct tty_struct *tty,
} /* belkin_sa_open */
static void belkin_sa_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void belkin_sa_close(struct usb_serial_port *port)
{
dbg("%s port %d", __func__, port->number);
......
......@@ -262,13 +262,33 @@ error: kfree(priv);
return r;
}
static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static int ch341_carrier_raised(struct usb_serial_port *port)
{
struct ch341_private *priv = usb_get_serial_port_data(port);
if (priv->line_status & CH341_BIT_DCD)
return 1;
return 0;
}
static void ch341_dtr_rts(struct usb_serial_port *port, int on)
{
struct ch341_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int c_cflag;
dbg("%s - port %d", __func__, port->number);
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
if (on)
priv->line_control |= CH341_BIT_RTS | CH341_BIT_DTR;
else
priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, priv->line_control);
wake_up_interruptible(&priv->delta_msr_wait);
}
static void ch341_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
/* shutdown our urbs */
......@@ -276,18 +296,6 @@ static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port,
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
if (tty) {
c_cflag = tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, 0);
}
}
wake_up_interruptible(&priv->delta_msr_wait);
}
......@@ -302,7 +310,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
dbg("ch341_open()");
priv->baud_rate = DEFAULT_BAUD_RATE;
priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
r = ch341_configure(serial->dev, priv);
if (r)
......@@ -322,7 +329,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
if (r) {
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
" error %d\n", __func__, r);
ch341_close(tty, port, NULL);
ch341_close(port);
return -EPROTO;
}
......@@ -343,9 +350,6 @@ static void ch341_set_termios(struct tty_struct *tty,
dbg("ch341_set_termios()");
if (!tty || !tty->termios)
return;
baud_rate = tty_get_baud_rate(tty);
priv->baud_rate = baud_rate;
......@@ -568,6 +572,8 @@ static struct usb_serial_driver ch341_device = {
.usb_driver = &ch341_driver,
.num_ports = 1,
.open = ch341_open,
.dtr_rts = ch341_dtr_rts,
.carrier_raised = ch341_carrier_raised,
.close = ch341_close,
.ioctl = ch341_ioctl,
.set_termios = ch341_set_termios,
......
......@@ -169,7 +169,9 @@ static int usb_console_setup(struct console *co, char *options)
kfree(tty);
}
}
/* So we know not to kill the hardware on a hangup on this
port. We have also bumped the use count by one so it won't go
idle */
port->console = 1;
retval = 0;
......@@ -182,7 +184,7 @@ static int usb_console_setup(struct console *co, char *options)
kfree(tty);
reset_open_count:
port->port.count = 0;
goto out;
goto out;
}
static void usb_console_write(struct console *co,
......
......@@ -36,8 +36,7 @@
static int cp2101_open(struct tty_struct *, struct usb_serial_port *,
struct file *);
static void cp2101_cleanup(struct usb_serial_port *);
static void cp2101_close(struct tty_struct *, struct usb_serial_port *,
struct file*);
static void cp2101_close(struct usb_serial_port *);
static void cp2101_get_termios(struct tty_struct *,
struct usb_serial_port *port);
static void cp2101_get_termios_port(struct usb_serial_port *port,
......@@ -398,8 +397,7 @@ static void cp2101_cleanup(struct usb_serial_port *port)
}
}
static void cp2101_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static void cp2101_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
......
......@@ -61,8 +61,7 @@ static int cyberjack_startup(struct usb_serial *serial);
static void cyberjack_shutdown(struct usb_serial *serial);
static int cyberjack_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cyberjack_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cyberjack_close(struct usb_serial_port *port);
static int cyberjack_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count);
static int cyberjack_write_room(struct tty_struct *tty);
......@@ -185,8 +184,7 @@ static int cyberjack_open(struct tty_struct *tty,
return result;
}
static void cyberjack_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void cyberjack_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
......
......@@ -174,8 +174,8 @@ static int cypress_ca42v2_startup(struct usb_serial *serial);
static void cypress_shutdown(struct usb_serial *serial);
static int cypress_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cypress_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cypress_close(struct usb_serial_port *port);
static void cypress_dtr_rts(struct usb_serial_port *port, int on);
static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
......@@ -218,6 +218,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
.shutdown = cypress_shutdown,
.open = cypress_open,
.close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
.ioctl = cypress_ioctl,
......@@ -244,6 +245,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
.shutdown = cypress_shutdown,
.open = cypress_open,
.close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
.ioctl = cypress_ioctl,
......@@ -270,6 +272,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.shutdown = cypress_shutdown,
.open = cypress_open,
.close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
.ioctl = cypress_ioctl,
......@@ -656,11 +659,7 @@ static int cypress_open(struct tty_struct *tty,
priv->rx_flags = 0;
spin_unlock_irqrestore(&priv->lock, flags);
/* raise both lines and set termios */
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = CONTROL_DTR | CONTROL_RTS;
priv->cmd_ctrl = 1;
spin_unlock_irqrestore(&priv->lock, flags);
/* Set termios */
result = cypress_write(tty, port, NULL, 0);
if (result) {
......@@ -694,76 +693,42 @@ static int cypress_open(struct tty_struct *tty,
__func__, result);
cypress_set_dead(port);
}
port->port.drain_delay = 256;
return result;
} /* cypress_open */
static void cypress_dtr_rts(struct usb_serial_port *port, int on)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
/* drop dtr and rts */
priv = usb_get_serial_port_data(port);
spin_lock_irq(&priv->lock);
if (on == 0)
priv->line_control = 0;
else
priv->line_control = CONTROL_DTR | CONTROL_RTS;
priv->cmd_ctrl = 1;
spin_unlock_irq(&priv->lock);
cypress_write(NULL, port, NULL, 0);
}
static void cypress_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void cypress_close(struct usb_serial_port *port)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned int c_cflag;
int bps;
long timeout;
wait_queue_t wait;
dbg("%s - port %d", __func__, port->number);
/* wait for data to drain from buffer */
spin_lock_irq(&priv->lock);
timeout = CYPRESS_CLOSING_WAIT;
init_waitqueue_entry(&wait, current);
add_wait_queue(&tty->write_wait, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (cypress_buf_data_avail(priv->buf) == 0
|| timeout == 0 || signal_pending(current)
/* without mutex, allowed due to harmless failure mode */
|| port->serial->disconnected)
break;
spin_unlock_irq(&priv->lock);
timeout = schedule_timeout(timeout);
spin_lock_irq(&priv->lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
/* clear out any remaining data in the buffer */
cypress_buf_clear(priv->buf);
spin_unlock_irq(&priv->lock);
/* writing is potentially harmful, lock must be taken */
mutex_lock(&port->serial->disc_mutex);
if (port->serial->disconnected) {
mutex_unlock(&port->serial->disc_mutex);
return;
}
/* wait for characters to drain from device */
if (tty) {
bps = tty_get_baud_rate(tty);
if (bps > 1200)
timeout = max((HZ * 2560) / bps, HZ / 10);
else
timeout = 2 * HZ;
schedule_timeout_interruptible(timeout);
}
cypress_buf_clear(priv->buf);
dbg("%s - stopping urbs", __func__);
usb_kill_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb);
if (tty) {
c_cflag = tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop dtr and rts */
priv = usb_get_serial_port_data(port);
spin_lock_irq(&priv->lock);
priv->line_control = 0;
priv->cmd_ctrl = 1;
spin_unlock_irq(&priv->lock);
cypress_write(tty, port, NULL, 0);
}
}
if (stats)
dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
......
......@@ -422,7 +422,6 @@ struct digi_port {
int dp_throttled;
int dp_throttle_restart;
wait_queue_head_t dp_flush_wait;
int dp_in_close; /* close in progress */
wait_queue_head_t dp_close_wait; /* wait queue for close */
struct work_struct dp_wakeup_work;
struct usb_serial_port *dp_port;
......@@ -456,8 +455,9 @@ static int digi_write_room(struct tty_struct *tty);
static int digi_chars_in_buffer(struct tty_struct *tty);
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void digi_close(struct usb_serial_port *port);
static int digi_carrier_raised(struct usb_serial_port *port);
static void digi_dtr_rts(struct usb_serial_port *port, int on);
static int digi_startup_device(struct usb_serial *serial);
static int digi_startup(struct usb_serial *serial);
static void digi_shutdown(struct usb_serial *serial);
......@@ -510,6 +510,8 @@ static struct usb_serial_driver digi_acceleport_2_device = {
.num_ports = 3,
.open = digi_open,
.close = digi_close,
.dtr_rts = digi_dtr_rts,
.carrier_raised = digi_carrier_raised,
.write = digi_write,
.write_room = digi_write_room,
.write_bulk_callback = digi_write_bulk_callback,
......@@ -1328,6 +1330,19 @@ static int digi_chars_in_buffer(struct tty_struct *tty)
}
static void digi_dtr_rts(struct usb_serial_port *port, int on)
{
/* Adjust DTR and RTS */
digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1);
}
static int digi_carrier_raised(struct usb_serial_port *port)
{
struct digi_port *priv = usb_get_serial_port_data(port);
if (priv->dp_modem_signals & TIOCM_CD)
return 1;
return 0;
}
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
......@@ -1336,7 +1351,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
struct ktermios not_termios;
unsigned long flags = 0;
dbg("digi_open: TOP: port=%d, open_count=%d",
priv->dp_port_num, port->port.count);
......@@ -1345,26 +1359,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
if (digi_startup_device(port->serial) != 0)
return -ENXIO;
spin_lock_irqsave(&priv->dp_port_lock, flags);
/* don't wait on a close in progress for non-blocking opens */
if (priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) {
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
return -EAGAIN;
}
/* wait for a close in progress to finish */
while (priv->dp_in_close) {
cond_wait_interruptible_timeout_irqrestore(
&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags);
if (signal_pending(current))
return -EINTR;
spin_lock_irqsave(&priv->dp_port_lock, flags);
}
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
/* read modem signals automatically whenever they change */
buf[0] = DIGI_CMD_READ_INPUT_SIGNALS;
buf[1] = priv->dp_port_num;
......@@ -1387,16 +1381,11 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
not_termios.c_iflag = ~tty->termios->c_iflag;
digi_set_termios(tty, port, &not_termios);
}
/* set DTR and RTS */
digi_set_modem_signals(port, TIOCM_DTR|TIOCM_RTS, 1);
return 0;
}
static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static void digi_close(struct usb_serial_port *port)
{
DEFINE_WAIT(wait);
int ret;
......@@ -1411,28 +1400,9 @@ static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
if (port->serial->disconnected)
goto exit;
/* do cleanup only after final close on this port */
spin_lock_irq(&priv->dp_port_lock);
priv->dp_in_close = 1;
spin_unlock_irq(&priv->dp_port_lock);
/* tell line discipline to process only XON/XOFF */
tty->closing = 1;
/* wait for output to drain */
if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0)
tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT);
/* flush driver and line discipline buffers */
tty_driver_flush_buffer(tty);
tty_ldisc_flush(tty);
if (port->serial->dev) {
/* wait for transmit idle */
if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0)
digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
/* drop DTR and RTS */
digi_set_modem_signals(port, 0, 0);
/* FIXME: Transmit idle belongs in the wait_unti_sent path */
digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
/* disable input flow control */
buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
......@@ -1477,11 +1447,9 @@ static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
/* shutdown any outstanding bulk writes */
usb_kill_urb(port->write_urb);
}
tty->closing = 0;
exit:
spin_lock_irq(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
priv->dp_in_close = 0;
wake_up_interruptible(&priv->dp_close_wait);
spin_unlock_irq(&priv->dp_port_lock);
mutex_unlock(&port->serial->disc_mutex);
......@@ -1560,7 +1528,6 @@ static int digi_startup(struct usb_serial *serial)
priv->dp_throttled = 0;
priv->dp_throttle_restart = 0;
init_waitqueue_head(&priv->dp_flush_wait);
priv->dp_in_close = 0;
init_waitqueue_head(&priv->dp_close_wait);
INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
priv->dp_port = serial->port[i];
......
......@@ -81,8 +81,7 @@ static int debug;
/* function prototypes for an empeg-car player */
static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void empeg_close(struct usb_serial_port *port);
static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf,
int count);
......@@ -181,8 +180,7 @@ static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
}
static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static void empeg_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
......
......@@ -719,8 +719,8 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port);
static int ftdi_sio_port_remove(struct usb_serial_port *port);
static int ftdi_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void ftdi_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void ftdi_close(struct usb_serial_port *port);
static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static int ftdi_write_room(struct tty_struct *tty);
......@@ -758,6 +758,7 @@ static struct usb_serial_driver ftdi_sio_device = {
.port_remove = ftdi_sio_port_remove,
.open = ftdi_open,
.close = ftdi_close,
.dtr_rts = ftdi_dtr_rts,
.throttle = ftdi_throttle,
.unthrottle = ftdi_unthrottle,
.write = ftdi_write,
......@@ -1558,6 +1559,30 @@ static int ftdi_open(struct tty_struct *tty,
} /* ftdi_open */
static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
char buf[1];
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected) {
/* Disable flow control */
if (!on && usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, buf, 0,
WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "error from flowcontrol urb\n");
}
/* drop RTS and DTR */
if (on)
set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
else
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
}
mutex_unlock(&port->serial->disc_mutex);
}
/*
* usbserial:__serial_close only calls ftdi_close if the point is open
......@@ -1567,31 +1592,12 @@ static int ftdi_open(struct tty_struct *tty,
*
*/
static void ftdi_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void ftdi_close(struct usb_serial_port *port)
{ /* ftdi_close */
unsigned int c_cflag = tty->termios->c_cflag;
struct ftdi_private *priv = usb_get_serial_port_data(port);
char buf[1];
dbg("%s", __func__);
mutex_lock(&port->serial->disc_mutex);
if (c_cflag & HUPCL && !port->serial->disconnected) {
/* Disable flow control */
if (usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, buf, 0,
WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "error from flowcontrol urb\n");
}
/* drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} /* Note change no line if hupcl is off */
mutex_unlock(&port->serial->disc_mutex);
/* cancel any scheduled reading */
cancel_delayed_work_sync(&priv->rx_work);
......
......@@ -993,8 +993,7 @@ static int garmin_open(struct tty_struct *tty,
}
static void garmin_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void garmin_close(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
......
......@@ -184,8 +184,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
}
EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
void usb_serial_generic_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
void usb_serial_generic_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
generic_cleanup(port);
......
......@@ -207,8 +207,7 @@ static void edge_bulk_out_cmd_callback(struct urb *urb);
/* function prototypes for the usbserial callbacks */
static int edge_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void edge_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void edge_close(struct usb_serial_port *port);
static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static int edge_write_room(struct tty_struct *tty);
......@@ -965,7 +964,7 @@ static int edge_open(struct tty_struct *tty,
if (!edge_port->txfifo.fifo) {
dbg("%s - no memory", __func__);
edge_close(tty, port, filp);
edge_close(port);
return -ENOMEM;
}