Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 195438
b: refs/heads/master
c: d3901a0
h: refs/heads/master
v: v3
  • Loading branch information
Johan Hovold authored and Greg Kroah-Hartman committed May 20, 2010
1 parent 22dd95d commit c707e47
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 173 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e07afd3fb906647d37108206075834f8c670b7e3
refs/heads/master: d3901a064cfedf892c00704aa4e51d119f04a65e
191 changes: 19 additions & 172 deletions trunk/drivers/usb/serial/ftdi_sio.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/*
* USB FTDI SIO driver
*
* Copyright (C) 2009 - 2010
* Johan Hovold (jhovold@gmail.com)
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
* Bill Ryder (bryder@sgi.com)
Expand Down Expand Up @@ -49,8 +51,8 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v1.5.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr"
#define DRIVER_VERSION "v1.6.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"

static int debug;
Expand Down Expand Up @@ -87,9 +89,6 @@ struct ftdi_private {
be enabled */

unsigned int latency; /* latency setting in use */
spinlock_t tx_lock; /* spinlock for transmit state */
unsigned long tx_outstanding_bytes;
unsigned long tx_outstanding_urbs;
unsigned short max_packet_size;
struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */
};
Expand Down Expand Up @@ -784,12 +783,9 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port);
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port);
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);
static int ftdi_chars_in_buffer(struct tty_struct *tty);
static void ftdi_write_bulk_callback(struct urb *urb);
static void ftdi_process_read_urb(struct urb *urb);
static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
void **dest, size_t size, const void *buf, size_t count);
static void ftdi_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int ftdi_tiocmget(struct tty_struct *tty, struct file *file);
Expand All @@ -816,6 +812,8 @@ static struct usb_serial_driver ftdi_sio_device = {
.id_table = id_table_combined,
.num_ports = 1,
.bulk_in_size = 512,
/* Must modify prepare_write_buffer if multi_urb_write is changed. */
.multi_urb_write = 1,
.probe = ftdi_sio_probe,
.port_probe = ftdi_sio_port_probe,
.port_remove = ftdi_sio_port_remove,
Expand All @@ -824,11 +822,8 @@ static struct usb_serial_driver ftdi_sio_device = {
.dtr_rts = ftdi_dtr_rts,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
.write = ftdi_write,
.write_room = ftdi_write_room,
.chars_in_buffer = ftdi_chars_in_buffer,
.process_read_urb = ftdi_process_read_urb,
.write_bulk_callback = ftdi_write_bulk_callback,
.prepare_write_buffer = ftdi_prepare_write_buffer,
.tiocmget = ftdi_tiocmget,
.tiocmset = ftdi_tiocmset,
.ioctl = ftdi_ioctl,
Expand All @@ -844,9 +839,6 @@ static struct usb_serial_driver ftdi_sio_device = {
#define HIGH 1
#define LOW 0

/* number of outstanding urbs to prevent userspace DoS from happening */
#define URB_UPPER_LIMIT 42

/*
* ***************************************************************************
* Utility functions
Expand Down Expand Up @@ -1536,7 +1528,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
}

kref_init(&priv->kref);
spin_lock_init(&priv->tx_lock);
mutex_init(&priv->cfg_lock);
init_waitqueue_head(&priv->delta_msr_wait);

Expand Down Expand Up @@ -1761,31 +1752,15 @@ static void ftdi_close(struct usb_serial_port *port)
*
* The new devices do not require this byte
*/
static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
void **dest, size_t size, const void *src, size_t count)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
struct urb *urb;
struct ftdi_private *priv;
unsigned char *buffer;
int data_offset ; /* will be 1 for the SIO and 0 otherwise */
int status;
int transfer_size;
unsigned long flags;

dbg("%s port %d, %d bytes", __func__, port->number, count);

if (count == 0) {
dbg("write request of 0 bytes");
return 0;
}
spin_lock_irqsave(&priv->tx_lock, flags);
if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
spin_unlock_irqrestore(&priv->tx_lock, flags);
dbg("%s - write limit hit", __func__);
return 0;
}
priv->tx_outstanding_urbs++;
spin_unlock_irqrestore(&priv->tx_lock, flags);
priv = usb_get_serial_port_data(port);

data_offset = priv->write_offset;
dbg("data_offset set to %d", data_offset);
Expand All @@ -1801,17 +1776,9 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,

buffer = kmalloc(transfer_size, GFP_ATOMIC);
if (!buffer) {
dev_err(&port->dev,
"%s ran out of kernel memory for urb ...\n", __func__);
count = -ENOMEM;
goto error_no_buffer;
}

urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
dev_err(&port->dev, "%s - no more free urbs\n", __func__);
count = -ENOMEM;
goto error_no_urb;
dev_err(&port->dev, "%s - could not allocate buffer\n",
__func__);
return -ENOMEM;
}

/* Copy data */
Expand All @@ -1821,7 +1788,7 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
int user_pktsz = priv->max_packet_size - data_offset;
int todo = count;
unsigned char *first_byte = buffer;
const unsigned char *current_position = buf;
const unsigned char *current_position = src;

while (todo > 0) {
if (user_pktsz > todo)
Expand All @@ -1836,134 +1803,14 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
todo -= user_pktsz;
}
} else {
/* No control byte required. */
/* Copy in the data to send */
memcpy(buffer, buf, count);
memcpy(buffer, src, count);
}

usb_serial_debug_data(debug, &port->dev, __func__,
transfer_size, buffer);

/* fill the buffer and send it */
usb_fill_bulk_urb(urb, port->serial->dev,
usb_sndbulkpipe(port->serial->dev,
port->bulk_out_endpointAddress),
buffer, transfer_size,
ftdi_write_bulk_callback, port);

status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
dev_err(&port->dev,
"%s - failed submitting write urb, error %d\n",
__func__, status);
count = status;
goto error;
} else {
spin_lock_irqsave(&priv->tx_lock, flags);
priv->tx_outstanding_bytes += count;
spin_unlock_irqrestore(&priv->tx_lock, flags);
}
*dest = buffer;

/* we are done with this urb, so let the host driver
* really free it when it is finished with it */
usb_free_urb(urb);

dbg("%s write returning: %d", __func__, count);
return count;
error:
usb_free_urb(urb);
error_no_urb:
kfree(buffer);
error_no_buffer:
spin_lock_irqsave(&priv->tx_lock, flags);
priv->tx_outstanding_urbs--;
spin_unlock_irqrestore(&priv->tx_lock, flags);
return count;
}

/* This function may get called when the device is closed */
static void ftdi_write_bulk_callback(struct urb *urb)
{
unsigned long flags;
struct usb_serial_port *port = urb->context;
struct ftdi_private *priv;
int data_offset; /* will be 1 for the SIO and 0 otherwise */
unsigned long countback;
int status = urb->status;

/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree(urb->transfer_buffer);

dbg("%s - port %d", __func__, port->number);

priv = usb_get_serial_port_data(port);
if (!priv) {
dbg("%s - bad port private data pointer - exiting", __func__);
return;
}
/* account for transferred data */
countback = urb->transfer_buffer_length;
data_offset = priv->write_offset;
if (data_offset > 0) {
/* Subtract the control bytes */
countback -= (data_offset * DIV_ROUND_UP(countback, priv->max_packet_size));
}
spin_lock_irqsave(&priv->tx_lock, flags);
--priv->tx_outstanding_urbs;
priv->tx_outstanding_bytes -= countback;
spin_unlock_irqrestore(&priv->tx_lock, flags);

if (status) {
dbg("nonzero write bulk status received: %d", status);
}

usb_serial_port_softint(port);
}

static int ftdi_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
int room;
unsigned long flags;

dbg("%s - port %d", __func__, port->number);

spin_lock_irqsave(&priv->tx_lock, flags);
if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) {
/*
* We really can take anything the user throws at us
* but let's pick a nice big number to tell the tty
* layer that we have lots of free space
*/
room = 2048;
} else {
room = 0;
}
spin_unlock_irqrestore(&priv->tx_lock, flags);
return room;
}

static int ftdi_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
int buffered;
unsigned long flags;

dbg("%s - port %d", __func__, port->number);

spin_lock_irqsave(&priv->tx_lock, flags);
buffered = (int)priv->tx_outstanding_bytes;
spin_unlock_irqrestore(&priv->tx_lock, flags);
if (buffered < 0) {
dev_err(&port->dev, "%s outstanding tx bytes is negative!\n",
__func__);
buffered = 0;
}
return buffered;
}

static int ftdi_process_packet(struct tty_struct *tty,
struct usb_serial_port *port, struct ftdi_private *priv,
char *packet, int len)
Expand Down

0 comments on commit c707e47

Please sign in to comment.