|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/console.h>
|
|
|
#include <linux/kthread.h>
|
|
|
+#include <linux/kfifo.h>
|
|
|
|
|
|
#include "u_serial.h"
|
|
|
|
|
@@ -80,19 +81,11 @@
|
|
|
#define WRITE_BUF_SIZE 8192 /* TX only */
|
|
|
#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 */
|
|
|
struct gscons_info {
|
|
|
struct gs_port *port;
|
|
|
struct task_struct *console_thread;
|
|
|
- struct gs_buf con_buf;
|
|
|
+ struct kfifo con_buf;
|
|
|
/* protect the buf and busy flag */
|
|
|
spinlock_t con_lock;
|
|
|
int req_busy;
|
|
@@ -122,7 +115,7 @@ struct gs_port {
|
|
|
struct list_head write_pool;
|
|
|
int write_started;
|
|
|
int write_allocated;
|
|
|
- struct gs_buf port_write_buf;
|
|
|
+ struct kfifo port_write_buf;
|
|
|
wait_queue_head_t drain_wait; /* wait while writes drain */
|
|
|
bool write_busy;
|
|
|
wait_queue_head_t close_wait;
|
|
@@ -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 */
|
|
|
|
|
|
/*
|
|
@@ -346,11 +201,11 @@ gs_send_packet(struct gs_port *port, char *packet, unsigned size)
|
|
|
{
|
|
|
unsigned len;
|
|
|
|
|
|
- len = gs_buf_data_avail(&port->port_write_buf);
|
|
|
+ len = kfifo_len(&port->port_write_buf);
|
|
|
if (len < size)
|
|
|
size = len;
|
|
|
if (size != 0)
|
|
|
- size = gs_buf_get(&port->port_write_buf, packet, size);
|
|
|
+ size = kfifo_out(&port->port_write_buf, packet, size);
|
|
|
return size;
|
|
|
}
|
|
|
|
|
@@ -398,7 +253,7 @@ __acquires(&port->port_lock)
|
|
|
|
|
|
req->length = len;
|
|
|
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",
|
|
|
port->port_num, len, *((u8 *)req->buf),
|
|
@@ -787,10 +642,11 @@ static int gs_open(struct tty_struct *tty, struct file *file)
|
|
|
spin_lock_irq(&port->port_lock);
|
|
|
|
|
|
/* 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);
|
|
|
- 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);
|
|
|
|
|
|
if (status) {
|
|
@@ -839,7 +695,7 @@ static int gs_writes_finished(struct gs_port *p)
|
|
|
|
|
|
/* return true on disconnect or empty buffer */
|
|
|
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);
|
|
|
|
|
|
return cond;
|
|
@@ -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
|
|
|
* 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);
|
|
|
wait_event_interruptible_timeout(port->drain_wait,
|
|
|
gs_writes_finished(port),
|
|
@@ -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.
|
|
|
*/
|
|
|
if (gser == NULL)
|
|
|
- gs_buf_free(&port->port_write_buf);
|
|
|
+ kfifo_free(&port->port_write_buf);
|
|
|
else
|
|
|
- gs_buf_clear(&port->port_write_buf);
|
|
|
+ kfifo_reset(&port->port_write_buf);
|
|
|
|
|
|
port->port.tty = NULL;
|
|
|
|
|
@@ -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);
|
|
|
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() */
|
|
|
if (port->port_usb)
|
|
|
gs_start_tx(port);
|
|
@@ -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));
|
|
|
|
|
|
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);
|
|
|
|
|
|
return status;
|
|
@@ -961,7 +817,7 @@ static int gs_write_room(struct tty_struct *tty)
|
|
|
|
|
|
spin_lock_irqsave(&port->port_lock, flags);
|
|
|
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);
|
|
|
|
|
|
pr_vdebug("gs_write_room: (%d,%p) room=%d\n",
|
|
@@ -977,7 +833,7 @@ static int gs_chars_in_buffer(struct tty_struct *tty)
|
|
|
int chars = 0;
|
|
|
|
|
|
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);
|
|
|
|
|
|
pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n",
|
|
@@ -1148,7 +1004,7 @@ static int gs_console_thread(void *data)
|
|
|
ep = port->port_usb->in;
|
|
|
|
|
|
spin_lock_irq(&info->con_lock);
|
|
|
- count = gs_buf_data_avail(&info->con_buf);
|
|
|
+ count = kfifo_len(&info->con_buf);
|
|
|
size = ep->maxpacket;
|
|
|
|
|
|
if (count > 0 && !info->req_busy) {
|
|
@@ -1156,7 +1012,7 @@ static int gs_console_thread(void *data)
|
|
|
if (count < size)
|
|
|
size = count;
|
|
|
|
|
|
- xfer = gs_buf_get(&info->con_buf, req->buf, size);
|
|
|
+ xfer = kfifo_out(&info->con_buf, req->buf, size);
|
|
|
req->length = xfer;
|
|
|
|
|
|
spin_unlock(&info->con_lock);
|
|
@@ -1192,7 +1048,7 @@ static int gs_console_setup(struct console *co, char *options)
|
|
|
info->req_busy = 0;
|
|
|
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) {
|
|
|
pr_err("%s: allocate console buffer failed\n", __func__);
|
|
|
return status;
|
|
@@ -1202,7 +1058,7 @@ static int gs_console_setup(struct console *co, char *options)
|
|
|
co, "gs_console");
|
|
|
if (IS_ERR(info->console_thread)) {
|
|
|
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);
|
|
|
}
|
|
|
wake_up_process(info->console_thread);
|
|
@@ -1217,7 +1073,7 @@ static void gs_console_write(struct console *co,
|
|
|
unsigned long 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);
|
|
|
|
|
|
wake_up_process(info->console_thread);
|
|
@@ -1256,7 +1112,7 @@ static void gserial_console_exit(void)
|
|
|
unregister_console(&gserial_cons);
|
|
|
if (!IS_ERR_OR_NULL(info->console_thread))
|
|
|
kthread_stop(info->console_thread);
|
|
|
- gs_buf_free(&info->con_buf);
|
|
|
+ kfifo_free(&info->con_buf);
|
|
|
}
|
|
|
|
|
|
#else
|
|
@@ -1529,7 +1385,7 @@ void gserial_disconnect(struct gserial *gser)
|
|
|
/* finally, free any unused/unusable I/O buffers */
|
|
|
spin_lock_irqsave(&port->port_lock, flags);
|
|
|
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_queue, NULL);
|
|
|
gs_free_requests(gser->in, &port->write_pool, NULL);
|