Commit 66e47e60 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

USB: ftdi_sio: fix DMA buffers on stack

Also remove unnecessary buffer allocations for zero-length transfers.
Reported-by: default avatarMatti Aarnio <matti.aarnio@zmailer.org>
Signed-off-by: default avatarJohan Hovold <jhovold@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 54f328d0
...@@ -935,7 +935,6 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, ...@@ -935,7 +935,6 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
unsigned int clear) unsigned int clear)
{ {
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
char *buf;
unsigned urb_value; unsigned urb_value;
int rv; int rv;
...@@ -944,10 +943,6 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, ...@@ -944,10 +943,6 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
return 0; /* no change */ return 0; /* no change */
} }
buf = kmalloc(1, GFP_NOIO);
if (!buf)
return -ENOMEM;
clear &= ~set; /* 'set' takes precedence over 'clear' */ clear &= ~set; /* 'set' takes precedence over 'clear' */
urb_value = 0; urb_value = 0;
if (clear & TIOCM_DTR) if (clear & TIOCM_DTR)
...@@ -963,9 +958,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, ...@@ -963,9 +958,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
urb_value, priv->interface, urb_value, priv->interface,
buf, 0, WDR_TIMEOUT); NULL, 0, WDR_TIMEOUT);
kfree(buf);
if (rv < 0) { if (rv < 0) {
dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
__func__, __func__,
...@@ -1124,16 +1117,11 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, ...@@ -1124,16 +1117,11 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
{ {
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
char *buf;
__u16 urb_value; __u16 urb_value;
__u16 urb_index; __u16 urb_index;
__u32 urb_index_value; __u32 urb_index_value;
int rv; int rv;
buf = kmalloc(1, GFP_NOIO);
if (!buf)
return -ENOMEM;
urb_index_value = get_ftdi_divisor(tty, port); urb_index_value = get_ftdi_divisor(tty, port);
urb_value = (__u16)urb_index_value; urb_value = (__u16)urb_index_value;
urb_index = (__u16)(urb_index_value >> 16); urb_index = (__u16)(urb_index_value >> 16);
...@@ -1146,9 +1134,7 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) ...@@ -1146,9 +1134,7 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST,
FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
urb_value, urb_index, urb_value, urb_index,
buf, 0, WDR_SHORT_TIMEOUT); NULL, 0, WDR_SHORT_TIMEOUT);
kfree(buf);
return rv; return rv;
} }
...@@ -1156,7 +1142,6 @@ static int write_latency_timer(struct usb_serial_port *port) ...@@ -1156,7 +1142,6 @@ static int write_latency_timer(struct usb_serial_port *port)
{ {
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev = port->serial->dev; struct usb_device *udev = port->serial->dev;
char buf[1];
int rv = 0; int rv = 0;
int l = priv->latency; int l = priv->latency;
...@@ -1170,8 +1155,7 @@ static int write_latency_timer(struct usb_serial_port *port) ...@@ -1170,8 +1155,7 @@ static int write_latency_timer(struct usb_serial_port *port)
FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
l, priv->interface, l, priv->interface,
buf, 0, WDR_TIMEOUT); NULL, 0, WDR_TIMEOUT);
if (rv < 0) if (rv < 0)
dev_err(&port->dev, "Unable to write latency timer: %i\n", rv); dev_err(&port->dev, "Unable to write latency timer: %i\n", rv);
return rv; return rv;
...@@ -1445,7 +1429,6 @@ static ssize_t store_event_char(struct device *dev, ...@@ -1445,7 +1429,6 @@ static ssize_t store_event_char(struct device *dev,
struct usb_serial_port *port = to_usb_serial_port(dev); struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev = port->serial->dev; struct usb_device *udev = port->serial->dev;
char buf[1];
int v = simple_strtoul(valbuf, NULL, 10); int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0; int rv = 0;
...@@ -1456,8 +1439,7 @@ static ssize_t store_event_char(struct device *dev, ...@@ -1456,8 +1439,7 @@ static ssize_t store_event_char(struct device *dev,
FTDI_SIO_SET_EVENT_CHAR_REQUEST, FTDI_SIO_SET_EVENT_CHAR_REQUEST,
FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE, FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
v, priv->interface, v, priv->interface,
buf, 0, WDR_TIMEOUT); NULL, 0, WDR_TIMEOUT);
if (rv < 0) { if (rv < 0) {
dbg("Unable to write event character: %i", rv); dbg("Unable to write event character: %i", rv);
return -EIO; return -EIO;
...@@ -1636,7 +1618,6 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial) ...@@ -1636,7 +1618,6 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial)
struct usb_device *udev = serial->dev; struct usb_device *udev = serial->dev;
int latency = ndi_latency_timer; int latency = ndi_latency_timer;
int rv = 0; int rv = 0;
char buf[1];
if (latency == 0) if (latency == 0)
latency = 1; latency = 1;
...@@ -1649,7 +1630,7 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial) ...@@ -1649,7 +1630,7 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial)
rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
latency, 0, buf, 0, WDR_TIMEOUT); latency, 0, NULL, 0, WDR_TIMEOUT);
return 0; return 0;
} }
...@@ -1737,9 +1718,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) ...@@ -1737,9 +1718,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
struct usb_device *dev = port->serial->dev; struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags; unsigned long flags;
int result = 0; int result = 0;
char buf[1]; /* Needed for the usb_control_msg I think */
dbg("%s", __func__); dbg("%s", __func__);
...@@ -1754,7 +1733,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) ...@@ -1754,7 +1733,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_control_msg(dev, usb_sndctrlpipe(dev, 0), usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
FTDI_SIO_RESET_SIO, FTDI_SIO_RESET_SIO,
priv->interface, buf, 0, WDR_TIMEOUT); priv->interface, NULL, 0, WDR_TIMEOUT);
/* Termios defaults are set by usb_serial_init. We don't change /* Termios defaults are set by usb_serial_init. We don't change
port->tty->termios - this would lose speed settings, etc. port->tty->termios - this would lose speed settings, etc.
...@@ -1782,7 +1761,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) ...@@ -1782,7 +1761,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
static void ftdi_dtr_rts(struct usb_serial_port *port, int on) static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
{ {
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
char buf[1];
mutex_lock(&port->serial->disc_mutex); mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected) { if (!port->serial->disconnected) {
...@@ -1791,7 +1769,7 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on) ...@@ -1791,7 +1769,7 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
usb_sndctrlpipe(port->serial->dev, 0), usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, buf, 0, 0, priv->interface, NULL, 0,
WDR_TIMEOUT) < 0) { WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "error from flowcontrol urb\n"); dev_err(&port->dev, "error from flowcontrol urb\n");
} }
...@@ -2160,7 +2138,6 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) ...@@ -2160,7 +2138,6 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
__u16 urb_value = 0; __u16 urb_value = 0;
char buf[1];
/* break_state = -1 to turn on break, and 0 to turn off break */ /* break_state = -1 to turn on break, and 0 to turn off break */
/* see drivers/char/tty_io.c to see it used */ /* see drivers/char/tty_io.c to see it used */
...@@ -2176,7 +2153,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) ...@@ -2176,7 +2153,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE, FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface, urb_value , priv->interface,
buf, 0, WDR_TIMEOUT) < 0) { NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "%s FAILED to enable/disable break state " dev_err(&port->dev, "%s FAILED to enable/disable break state "
"(state was %d)\n", __func__, break_state); "(state was %d)\n", __func__, break_state);
} }
...@@ -2200,7 +2177,6 @@ static void ftdi_set_termios(struct tty_struct *tty, ...@@ -2200,7 +2177,6 @@ static void ftdi_set_termios(struct tty_struct *tty,
struct ktermios *termios = tty->termios; struct ktermios *termios = tty->termios;
unsigned int cflag = termios->c_cflag; unsigned int cflag = termios->c_cflag;
__u16 urb_value; /* will hold the new flags */ __u16 urb_value; /* will hold the new flags */
char buf[1]; /* Perhaps I should dynamically alloc this? */
/* Added for xon/xoff support */ /* Added for xon/xoff support */
unsigned int iflag = termios->c_iflag; unsigned int iflag = termios->c_iflag;
...@@ -2266,7 +2242,7 @@ static void ftdi_set_termios(struct tty_struct *tty, ...@@ -2266,7 +2242,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE, FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface, urb_value , priv->interface,
buf, 0, WDR_SHORT_TIMEOUT) < 0) { NULL, 0, WDR_SHORT_TIMEOUT) < 0) {
dev_err(&port->dev, "%s FAILED to set " dev_err(&port->dev, "%s FAILED to set "
"databits/stopbits/parity\n", __func__); "databits/stopbits/parity\n", __func__);
} }
...@@ -2278,7 +2254,7 @@ static void ftdi_set_termios(struct tty_struct *tty, ...@@ -2278,7 +2254,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, 0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) { NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev, dev_err(&port->dev,
"%s error from disable flowcontrol urb\n", "%s error from disable flowcontrol urb\n",
__func__); __func__);
...@@ -2304,7 +2280,7 @@ static void ftdi_set_termios(struct tty_struct *tty, ...@@ -2304,7 +2280,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
buf, 0, WDR_TIMEOUT) < 0) { NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev, dev_err(&port->dev,
"urb failed to set to rts/cts flow control\n"); "urb failed to set to rts/cts flow control\n");
} }
...@@ -2336,7 +2312,7 @@ static void ftdi_set_termios(struct tty_struct *tty, ...@@ -2336,7 +2312,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
urb_value , (FTDI_SIO_XON_XOFF_HS urb_value , (FTDI_SIO_XON_XOFF_HS
| priv->interface), | priv->interface),
buf, 0, WDR_TIMEOUT) < 0) { NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "urb failed to set to " dev_err(&port->dev, "urb failed to set to "
"xon/xoff flow control\n"); "xon/xoff flow control\n");
} }
...@@ -2350,7 +2326,7 @@ static void ftdi_set_termios(struct tty_struct *tty, ...@@ -2350,7 +2326,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, 0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) { NULL, 0, WDR_TIMEOUT) < 0) {
dev_err(&port->dev, dev_err(&port->dev,
"urb failed to clear flow control\n"); "urb failed to clear flow control\n");
} }
...@@ -2364,10 +2340,15 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) ...@@ -2364,10 +2340,15 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned char buf[2]; unsigned char *buf;
int ret; int ret;
dbg("%s TIOCMGET", __func__); dbg("%s TIOCMGET", __func__);
buf = kmalloc(2, GFP_KERNEL);
if (!buf)
return -ENOMEM;
switch (priv->chip_type) { switch (priv->chip_type) {
case SIO: case SIO:
/* Request the status from the device */ /* Request the status from the device */
...@@ -2378,7 +2359,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) ...@@ -2378,7 +2359,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
0, 0, 0, 0,
buf, 1, WDR_TIMEOUT); buf, 1, WDR_TIMEOUT);
if (ret < 0) if (ret < 0)
return ret; goto out;
break; break;
case FT8U232AM: case FT8U232AM:
case FT232BM: case FT232BM:
...@@ -2396,17 +2377,21 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) ...@@ -2396,17 +2377,21 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
0, priv->interface, 0, priv->interface,
buf, 2, WDR_TIMEOUT); buf, 2, WDR_TIMEOUT);
if (ret < 0) if (ret < 0)
return ret; goto out;
break; break;
default: default:
return -EFAULT; ret = -EFAULT;
goto out;
} }
return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
(buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
(buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) |
priv->last_dtr_rts; priv->last_dtr_rts;
out:
kfree(buf);
return ret;
} }
static int ftdi_tiocmset(struct tty_struct *tty, struct file *file, static int ftdi_tiocmset(struct tty_struct *tty, struct file *file,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment