diff options
Diffstat (limited to 'drivers/usb/gadget/function/u_serial.c')
-rw-r--r-- | drivers/usb/gadget/function/u_serial.c | 192 |
1 files changed, 24 insertions, 168 deletions
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 4d653d2960d4..29436f75bbe0 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -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); |