Commit a622ee99 authored by Lu Baolu's avatar Lu Baolu Committed by Felipe Balbi

usb: gadget: u_serial: Use kfifo instead of homemade circular buffer

The kernel FIFO implementation, kfifo, provides interfaces to manipulate
a first-in-first-out circular buffer.  Use kfifo instead of the homemade
one to make the code more concise and readable.
Signed-off-by: default avatarLu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 204ec1af
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/kfifo.h>
#include "u_serial.h" #include "u_serial.h"
...@@ -80,19 +81,11 @@ ...@@ -80,19 +81,11 @@
#define WRITE_BUF_SIZE 8192 /* TX only */ #define WRITE_BUF_SIZE 8192 /* TX only */
#define GS_CONSOLE_BUF_SIZE 8192 #define GS_CONSOLE_BUF_SIZE 8192
/* circular buffer */
struct gs_buf {
unsigned buf_size;
char *buf_buf;
char *buf_get;
char *buf_put;
};
/* console info */ /* console info */
struct gscons_info { struct gscons_info {
struct gs_port *port; struct gs_port *port;
struct task_struct *console_thread; struct task_struct *console_thread;
struct gs_buf con_buf; struct kfifo con_buf;
/* protect the buf and busy flag */ /* protect the buf and busy flag */
spinlock_t con_lock; spinlock_t con_lock;
int req_busy; int req_busy;
...@@ -122,7 +115,7 @@ struct gs_port { ...@@ -122,7 +115,7 @@ struct gs_port {
struct list_head write_pool; struct list_head write_pool;
int write_started; int write_started;
int write_allocated; int write_allocated;
struct gs_buf port_write_buf; struct kfifo port_write_buf;
wait_queue_head_t drain_wait; /* wait while writes drain */ wait_queue_head_t drain_wait; /* wait while writes drain */
bool write_busy; bool write_busy;
wait_queue_head_t close_wait; wait_queue_head_t close_wait;
...@@ -154,144 +147,6 @@ static struct portmaster { ...@@ -154,144 +147,6 @@ static struct portmaster {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* Circular Buffer */
/*
* gs_buf_alloc
*
* Allocate a circular buffer and all associated memory.
*/
static int gs_buf_alloc(struct gs_buf *gb, unsigned size)
{
gb->buf_buf = kmalloc(size, GFP_KERNEL);
if (gb->buf_buf == NULL)
return -ENOMEM;
gb->buf_size = size;
gb->buf_put = gb->buf_buf;
gb->buf_get = gb->buf_buf;
return 0;
}
/*
* gs_buf_free
*
* Free the buffer and all associated memory.
*/
static void gs_buf_free(struct gs_buf *gb)
{
kfree(gb->buf_buf);
gb->buf_buf = NULL;
}
/*
* gs_buf_clear
*
* Clear out all data in the circular buffer.
*/
static void gs_buf_clear(struct gs_buf *gb)
{
gb->buf_get = gb->buf_put;
/* equivalent to a get of all data available */
}
/*
* gs_buf_data_avail
*
* Return the number of bytes of data written into the circular
* buffer.
*/
static unsigned gs_buf_data_avail(struct gs_buf *gb)
{
return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
}
/*
* gs_buf_space_avail
*
* Return the number of bytes of space available in the circular
* buffer.
*/
static unsigned gs_buf_space_avail(struct gs_buf *gb)
{
return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
}
/*
* gs_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
gs_buf_put(struct gs_buf *gb, const char *buf, unsigned count)
{
unsigned len;
len = gs_buf_space_avail(gb);
if (count > len)
count = len;
if (count == 0)
return 0;
len = gb->buf_buf + gb->buf_size - gb->buf_put;
if (count > len) {
memcpy(gb->buf_put, buf, len);
memcpy(gb->buf_buf, buf+len, count - len);
gb->buf_put = gb->buf_buf + count - len;
} else {
memcpy(gb->buf_put, buf, count);
if (count < len)
gb->buf_put += count;
else /* count == len */
gb->buf_put = gb->buf_buf;
}
return count;
}
/*
* gs_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
gs_buf_get(struct gs_buf *gb, char *buf, unsigned count)
{
unsigned len;
len = gs_buf_data_avail(gb);
if (count > len)
count = len;
if (count == 0)
return 0;
len = gb->buf_buf + gb->buf_size - gb->buf_get;
if (count > len) {
memcpy(buf, gb->buf_get, len);
memcpy(buf+len, gb->buf_buf, count - len);
gb->buf_get = gb->buf_buf + count - len;
} else {
memcpy(buf, gb->buf_get, count);
if (count < len)
gb->buf_get += count;
else /* count == len */
gb->buf_get = gb->buf_buf;
}
return count;
}
/*-------------------------------------------------------------------------*/
/* I/O glue between TTY (upper) and USB function (lower) driver layers */ /* I/O glue between TTY (upper) and USB function (lower) driver layers */
/* /*
...@@ -346,11 +201,11 @@ gs_send_packet(struct gs_port *port, char *packet, unsigned size) ...@@ -346,11 +201,11 @@ gs_send_packet(struct gs_port *port, char *packet, unsigned size)
{ {
unsigned len; unsigned len;
len = gs_buf_data_avail(&port->port_write_buf); len = kfifo_len(&port->port_write_buf);
if (len < size) if (len < size)
size = len; size = len;
if (size != 0) if (size != 0)
size = gs_buf_get(&port->port_write_buf, packet, size); size = kfifo_out(&port->port_write_buf, packet, size);
return size; return size;
} }
...@@ -398,7 +253,7 @@ __acquires(&port->port_lock) ...@@ -398,7 +253,7 @@ __acquires(&port->port_lock)
req->length = len; req->length = len;
list_del(&req->list); list_del(&req->list);
req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0); req->zero = kfifo_is_empty(&port->port_write_buf);
pr_vdebug("ttyGS%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n", pr_vdebug("ttyGS%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n",
port->port_num, len, *((u8 *)req->buf), port->port_num, len, *((u8 *)req->buf),
...@@ -787,10 +642,11 @@ static int gs_open(struct tty_struct *tty, struct file *file) ...@@ -787,10 +642,11 @@ static int gs_open(struct tty_struct *tty, struct file *file)
spin_lock_irq(&port->port_lock); spin_lock_irq(&port->port_lock);
/* allocate circular buffer on first open */ /* allocate circular buffer on first open */
if (port->port_write_buf.buf_buf == NULL) { if (!kfifo_initialized(&port->port_write_buf)) {
spin_unlock_irq(&port->port_lock); spin_unlock_irq(&port->port_lock);
status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE); status = kfifo_alloc(&port->port_write_buf,
WRITE_BUF_SIZE, GFP_KERNEL);
spin_lock_irq(&port->port_lock); spin_lock_irq(&port->port_lock);
if (status) { if (status) {
...@@ -839,7 +695,7 @@ static int gs_writes_finished(struct gs_port *p) ...@@ -839,7 +695,7 @@ static int gs_writes_finished(struct gs_port *p)
/* return true on disconnect or empty buffer */ /* return true on disconnect or empty buffer */
spin_lock_irq(&p->port_lock); spin_lock_irq(&p->port_lock);
cond = (p->port_usb == NULL) || !gs_buf_data_avail(&p->port_write_buf); cond = (p->port_usb == NULL) || !kfifo_len(&p->port_write_buf);
spin_unlock_irq(&p->port_lock); spin_unlock_irq(&p->port_lock);
return cond; return cond;
...@@ -875,7 +731,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) ...@@ -875,7 +731,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
/* wait for circular write buffer to drain, disconnect, or at /* wait for circular write buffer to drain, disconnect, or at
* most GS_CLOSE_TIMEOUT seconds; then discard the rest * most GS_CLOSE_TIMEOUT seconds; then discard the rest
*/ */
if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) { if (kfifo_len(&port->port_write_buf) > 0 && gser) {
spin_unlock_irq(&port->port_lock); spin_unlock_irq(&port->port_lock);
wait_event_interruptible_timeout(port->drain_wait, wait_event_interruptible_timeout(port->drain_wait,
gs_writes_finished(port), gs_writes_finished(port),
...@@ -889,9 +745,9 @@ static void gs_close(struct tty_struct *tty, struct file *file) ...@@ -889,9 +745,9 @@ static void gs_close(struct tty_struct *tty, struct file *file)
* let the push tasklet fire again until we're re-opened. * let the push tasklet fire again until we're re-opened.
*/ */
if (gser == NULL) if (gser == NULL)
gs_buf_free(&port->port_write_buf); kfifo_free(&port->port_write_buf);
else else
gs_buf_clear(&port->port_write_buf); kfifo_reset(&port->port_write_buf);
port->port.tty = NULL; port->port.tty = NULL;
...@@ -915,7 +771,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) ...@@ -915,7 +771,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
spin_lock_irqsave(&port->port_lock, flags); spin_lock_irqsave(&port->port_lock, flags);
if (count) if (count)
count = gs_buf_put(&port->port_write_buf, buf, count); count = kfifo_in(&port->port_write_buf, buf, count);
/* treat count == 0 as flush_chars() */ /* treat count == 0 as flush_chars() */
if (port->port_usb) if (port->port_usb)
gs_start_tx(port); gs_start_tx(port);
...@@ -934,7 +790,7 @@ static int gs_put_char(struct tty_struct *tty, unsigned char ch) ...@@ -934,7 +790,7 @@ static int gs_put_char(struct tty_struct *tty, unsigned char ch)
port->port_num, tty, ch, __builtin_return_address(0)); port->port_num, tty, ch, __builtin_return_address(0));
spin_lock_irqsave(&port->port_lock, flags); spin_lock_irqsave(&port->port_lock, flags);
status = gs_buf_put(&port->port_write_buf, &ch, 1); status = kfifo_put(&port->port_write_buf, ch);
spin_unlock_irqrestore(&port->port_lock, flags); spin_unlock_irqrestore(&port->port_lock, flags);
return status; return status;
...@@ -961,7 +817,7 @@ static int gs_write_room(struct tty_struct *tty) ...@@ -961,7 +817,7 @@ static int gs_write_room(struct tty_struct *tty)
spin_lock_irqsave(&port->port_lock, flags); spin_lock_irqsave(&port->port_lock, flags);
if (port->port_usb) if (port->port_usb)
room = gs_buf_space_avail(&port->port_write_buf); room = kfifo_avail(&port->port_write_buf);
spin_unlock_irqrestore(&port->port_lock, flags); spin_unlock_irqrestore(&port->port_lock, flags);
pr_vdebug("gs_write_room: (%d,%p) room=%d\n", pr_vdebug("gs_write_room: (%d,%p) room=%d\n",
...@@ -977,7 +833,7 @@ static int gs_chars_in_buffer(struct tty_struct *tty) ...@@ -977,7 +833,7 @@ static int gs_chars_in_buffer(struct tty_struct *tty)
int chars = 0; int chars = 0;
spin_lock_irqsave(&port->port_lock, flags); spin_lock_irqsave(&port->port_lock, flags);
chars = gs_buf_data_avail(&port->port_write_buf); chars = kfifo_len(&port->port_write_buf);
spin_unlock_irqrestore(&port->port_lock, flags); spin_unlock_irqrestore(&port->port_lock, flags);
pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n", pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n",
...@@ -1148,7 +1004,7 @@ static int gs_console_thread(void *data) ...@@ -1148,7 +1004,7 @@ static int gs_console_thread(void *data)
ep = port->port_usb->in; ep = port->port_usb->in;
spin_lock_irq(&info->con_lock); spin_lock_irq(&info->con_lock);
count = gs_buf_data_avail(&info->con_buf); count = kfifo_len(&info->con_buf);
size = ep->maxpacket; size = ep->maxpacket;
if (count > 0 && !info->req_busy) { if (count > 0 && !info->req_busy) {
...@@ -1156,7 +1012,7 @@ static int gs_console_thread(void *data) ...@@ -1156,7 +1012,7 @@ static int gs_console_thread(void *data)
if (count < size) if (count < size)
size = count; size = count;
xfer = gs_buf_get(&info->con_buf, req->buf, size); xfer = kfifo_out(&info->con_buf, req->buf, size);
req->length = xfer; req->length = xfer;
spin_unlock(&info->con_lock); spin_unlock(&info->con_lock);
...@@ -1192,7 +1048,7 @@ static int gs_console_setup(struct console *co, char *options) ...@@ -1192,7 +1048,7 @@ static int gs_console_setup(struct console *co, char *options)
info->req_busy = 0; info->req_busy = 0;
spin_lock_init(&info->con_lock); spin_lock_init(&info->con_lock);
status = gs_buf_alloc(&info->con_buf, GS_CONSOLE_BUF_SIZE); status = kfifo_alloc(&info->con_buf, GS_CONSOLE_BUF_SIZE, GFP_KERNEL);
if (status) { if (status) {
pr_err("%s: allocate console buffer failed\n", __func__); pr_err("%s: allocate console buffer failed\n", __func__);
return status; return status;
...@@ -1202,7 +1058,7 @@ static int gs_console_setup(struct console *co, char *options) ...@@ -1202,7 +1058,7 @@ static int gs_console_setup(struct console *co, char *options)
co, "gs_console"); co, "gs_console");
if (IS_ERR(info->console_thread)) { if (IS_ERR(info->console_thread)) {
pr_err("%s: cannot create console thread\n", __func__); pr_err("%s: cannot create console thread\n", __func__);
gs_buf_free(&info->con_buf); kfifo_free(&info->con_buf);
return PTR_ERR(info->console_thread); return PTR_ERR(info->console_thread);
} }
wake_up_process(info->console_thread); wake_up_process(info->console_thread);
...@@ -1217,7 +1073,7 @@ static void gs_console_write(struct console *co, ...@@ -1217,7 +1073,7 @@ static void gs_console_write(struct console *co,
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&info->con_lock, flags); spin_lock_irqsave(&info->con_lock, flags);
gs_buf_put(&info->con_buf, buf, count); kfifo_in(&info->con_buf, buf, count);
spin_unlock_irqrestore(&info->con_lock, flags); spin_unlock_irqrestore(&info->con_lock, flags);
wake_up_process(info->console_thread); wake_up_process(info->console_thread);
...@@ -1256,7 +1112,7 @@ static void gserial_console_exit(void) ...@@ -1256,7 +1112,7 @@ static void gserial_console_exit(void)
unregister_console(&gserial_cons); unregister_console(&gserial_cons);
if (!IS_ERR_OR_NULL(info->console_thread)) if (!IS_ERR_OR_NULL(info->console_thread))
kthread_stop(info->console_thread); kthread_stop(info->console_thread);
gs_buf_free(&info->con_buf); kfifo_free(&info->con_buf);
} }
#else #else
...@@ -1529,7 +1385,7 @@ void gserial_disconnect(struct gserial *gser) ...@@ -1529,7 +1385,7 @@ void gserial_disconnect(struct gserial *gser)
/* finally, free any unused/unusable I/O buffers */ /* finally, free any unused/unusable I/O buffers */
spin_lock_irqsave(&port->port_lock, flags); spin_lock_irqsave(&port->port_lock, flags);
if (port->port.count == 0 && !port->openclose) if (port->port.count == 0 && !port->openclose)
gs_buf_free(&port->port_write_buf); kfifo_free(&port->port_write_buf);
gs_free_requests(gser->out, &port->read_pool, NULL); gs_free_requests(gser->out, &port->read_pool, NULL);
gs_free_requests(gser->out, &port->read_queue, NULL); gs_free_requests(gser->out, &port->read_queue, NULL);
gs_free_requests(gser->in, &port->write_pool, NULL); gs_free_requests(gser->in, &port->write_pool, NULL);
......
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