Skip to content

Commit

Permalink
USB: oti6858: use kfifo to implement write buffering
Browse files Browse the repository at this point in the history
Kill custom fifo implementation.

Use private write fifo to minimise changes to lock handling.

Compile-only tested.

Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Johan Hovold authored and Greg Kroah-Hartman committed May 20, 2010
1 parent 117fb8d commit e3c1803
Showing 1 changed file with 17 additions and 201 deletions.
218 changes: 17 additions & 201 deletions drivers/usb/serial/oti6858.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/uaccess.h>
#include <linux/kfifo.h>
#include "oti6858.h"

#define OTI6858_DESCRIPTION \
"Ours Technology Inc. OTi-6858 USB to serial adapter driver"
#define OTI6858_AUTHOR "Tomasz Michal Lukaszewski <FIXME@FIXME>"
#define OTI6858_VERSION "0.1"
#define OTI6858_VERSION "0.2"

static const struct usb_device_id id_table[] = {
{ USB_DEVICE(OTI6858_VENDOR_ID, OTI6858_PRODUCT_ID) },
Expand All @@ -75,17 +76,7 @@ static struct usb_driver oti6858_driver = {

static int debug;


/* buffering code, copied from pl2303 driver */
#define PL2303_BUF_SIZE 1024
#define PL2303_TMP_BUF_SIZE 1024

struct oti6858_buf {
unsigned int buf_size;
char *buf_buf;
char *buf_get;
char *buf_put;
};
#define OTI6858_FIFO_SIZE 1024

/* requests */
#define OTI6858_REQ_GET_STATUS (USB_DIR_IN | USB_TYPE_VENDOR | 0x00)
Expand Down Expand Up @@ -161,18 +152,6 @@ static int oti6858_tiocmset(struct tty_struct *tty, struct file *file,
static int oti6858_startup(struct usb_serial *serial);
static void oti6858_release(struct usb_serial *serial);

/* functions operating on buffers */
static struct oti6858_buf *oti6858_buf_alloc(unsigned int size);
static void oti6858_buf_free(struct oti6858_buf *pb);
static void oti6858_buf_clear(struct oti6858_buf *pb);
static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb);
static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb);
static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
unsigned int count);
static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
unsigned int count);


/* device info */
static struct usb_serial_driver oti6858_device = {
.driver = {
Expand Down Expand Up @@ -201,7 +180,7 @@ static struct usb_serial_driver oti6858_device = {
struct oti6858_private {
spinlock_t lock;

struct oti6858_buf *buf;
struct kfifo write_fifo;
struct oti6858_control_pkt status;

struct {
Expand Down Expand Up @@ -315,7 +294,7 @@ static void send_data(struct work_struct *work)
}
priv->flags.write_urb_in_use = 1;

count = oti6858_buf_data_avail(priv->buf);
count = kfifo_len(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
if (count > port->bulk_out_size)
count = port->bulk_out_size;
Expand Down Expand Up @@ -350,10 +329,9 @@ static void send_data(struct work_struct *work)
return;
}

spin_lock_irqsave(&priv->lock, flags);
oti6858_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
spin_unlock_irqrestore(&priv->lock, flags);

count = kfifo_out_locked(&priv->write_fifo,
port->write_urb->transfer_buffer,
count, &priv->lock);
port->write_urb->transfer_buffer_length = count;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_NOIO);
Expand All @@ -376,8 +354,8 @@ static int oti6858_startup(struct usb_serial *serial)
priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL);
if (!priv)
break;
priv->buf = oti6858_buf_alloc(PL2303_BUF_SIZE);
if (priv->buf == NULL) {
if (kfifo_alloc(&priv->write_fifo, OTI6858_FIFO_SIZE,
GFP_KERNEL)) {
kfree(priv);
break;
}
Expand All @@ -397,7 +375,7 @@ static int oti6858_startup(struct usb_serial *serial)

for (--i; i >= 0; --i) {
priv = usb_get_serial_port_data(serial->port[i]);
oti6858_buf_free(priv->buf);
kfifo_free(&priv->write_fifo);
kfree(priv);
usb_set_serial_port_data(serial->port[i], NULL);
}
Expand All @@ -408,16 +386,13 @@ static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
{
struct oti6858_private *priv = usb_get_serial_port_data(port);
unsigned long flags;

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

if (!count)
return count;

spin_lock_irqsave(&priv->lock, flags);
count = oti6858_buf_put(priv->buf, buf, count);
spin_unlock_irqrestore(&priv->lock, flags);
count = kfifo_in_locked(&priv->write_fifo, buf, count, &priv->lock);

return count;
}
Expand All @@ -432,7 +407,7 @@ static int oti6858_write_room(struct tty_struct *tty)
dbg("%s(port = %d)", __func__, port->number);

spin_lock_irqsave(&priv->lock, flags);
room = oti6858_buf_space_avail(priv->buf);
room = kfifo_avail(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);

return room;
Expand All @@ -448,7 +423,7 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty)
dbg("%s(port = %d)", __func__, port->number);

spin_lock_irqsave(&priv->lock, flags);
chars = oti6858_buf_data_avail(priv->buf);
chars = kfifo_len(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);

return chars;
Expand Down Expand Up @@ -642,7 +617,7 @@ static void oti6858_close(struct usb_serial_port *port)

spin_lock_irqsave(&priv->lock, flags);
/* clear out any remaining data in the buffer */
oti6858_buf_clear(priv->buf);
kfifo_reset_out(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);

dbg("%s(): after buf_clear()", __func__);
Expand Down Expand Up @@ -793,7 +768,7 @@ static void oti6858_release(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
priv = usb_get_serial_port_data(serial->port[i]);
if (priv) {
oti6858_buf_free(priv->buf);
kfifo_free(&priv->write_fifo);
kfree(priv);
}
}
Expand Down Expand Up @@ -892,7 +867,7 @@ static void oti6858_read_int_callback(struct urb *urb)

spin_lock_irqsave(&priv->lock, flags);
if (priv->flags.write_urb_in_use == 0
&& oti6858_buf_data_avail(priv->buf) != 0) {
&& kfifo_len(&priv->write_fifo) != 0) {
schedule_delayed_work(&priv->delayed_write_work, 0);
resubmit = 0;
}
Expand Down Expand Up @@ -1014,165 +989,6 @@ static void oti6858_write_bulk_callback(struct urb *urb)
}
}


/*
* oti6858_buf_alloc
*
* Allocate a circular buffer and all associated memory.
*/
static struct oti6858_buf *oti6858_buf_alloc(unsigned int size)
{
struct oti6858_buf *pb;

if (size == 0)
return NULL;

pb = kmalloc(sizeof(struct oti6858_buf), GFP_KERNEL);
if (pb == NULL)
return NULL;

pb->buf_buf = kmalloc(size, GFP_KERNEL);
if (pb->buf_buf == NULL) {
kfree(pb);
return NULL;
}

pb->buf_size = size;
pb->buf_get = pb->buf_put = pb->buf_buf;

return pb;
}

/*
* oti6858_buf_free
*
* Free the buffer and all associated memory.
*/
static void oti6858_buf_free(struct oti6858_buf *pb)
{
if (pb) {
kfree(pb->buf_buf);
kfree(pb);
}
}

/*
* oti6858_buf_clear
*
* Clear out all data in the circular buffer.
*/
static void oti6858_buf_clear(struct oti6858_buf *pb)
{
if (pb != NULL) {
/* equivalent to a get of all data available */
pb->buf_get = pb->buf_put;
}
}

/*
* oti6858_buf_data_avail
*
* Return the number of bytes of data available in the circular
* buffer.
*/
static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb)
{
if (pb == NULL)
return 0;
return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
}

/*
* oti6858_buf_space_avail
*
* Return the number of bytes of space available in the circular
* buffer.
*/
static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb)
{
if (pb == NULL)
return 0;
return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
}

/*
* oti6858_buf_put
*
* Copy data data from a user buffer and put it into the circular buffer.
* Restrict to the amount of space available.
*
* Return the number of bytes copied.
*/
static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
unsigned int count)
{
unsigned int len;

if (pb == NULL)
return 0;

len = oti6858_buf_space_avail(pb);
if (count > len)
count = len;

if (count == 0)
return 0;

len = pb->buf_buf + pb->buf_size - pb->buf_put;
if (count > len) {
memcpy(pb->buf_put, buf, len);
memcpy(pb->buf_buf, buf+len, count - len);
pb->buf_put = pb->buf_buf + count - len;
} else {
memcpy(pb->buf_put, buf, count);
if (count < len)
pb->buf_put += count;
else /* count == len */
pb->buf_put = pb->buf_buf;
}

return count;
}

/*
* oti6858_buf_get
*
* Get data from the circular buffer and copy to the given buffer.
* Restrict to the amount of data available.
*
* Return the number of bytes copied.
*/
static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
unsigned int count)
{
unsigned int len;

if (pb == NULL)
return 0;

len = oti6858_buf_data_avail(pb);
if (count > len)
count = len;

if (count == 0)
return 0;

len = pb->buf_buf + pb->buf_size - pb->buf_get;
if (count > len) {
memcpy(buf, pb->buf_get, len);
memcpy(buf+len, pb->buf_buf, count - len);
pb->buf_get = pb->buf_buf + count - len;
} else {
memcpy(buf, pb->buf_get, count);
if (count < len)
pb->buf_get += count;
else /* count == len */
pb->buf_get = pb->buf_buf;
}

return count;
}

/* module description and (de)initialization */

static int __init oti6858_init(void)
Expand Down

0 comments on commit e3c1803

Please sign in to comment.