|
|
|
@ -27,9 +27,9 @@
|
|
|
|
|
* Locking: none
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void tty_buffer_free_all(struct tty_struct *tty)
|
|
|
|
|
void tty_buffer_free_all(struct tty_port *port)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &port->buf;
|
|
|
|
|
struct tty_buffer *thead;
|
|
|
|
|
|
|
|
|
|
while ((thead = buf->head) != NULL) {
|
|
|
|
@ -56,11 +56,11 @@ void tty_buffer_free_all(struct tty_struct *tty)
|
|
|
|
|
* Locking: Caller must hold tty->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
|
|
|
|
|
static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct tty_buffer *p;
|
|
|
|
|
|
|
|
|
|
if (tty->buf.memory_used + size > 65536)
|
|
|
|
|
if (port->buf.memory_used + size > 65536)
|
|
|
|
|
return NULL;
|
|
|
|
|
p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
|
|
|
|
|
if (p == NULL)
|
|
|
|
@ -72,7 +72,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
|
|
|
|
|
p->read = 0;
|
|
|
|
|
p->char_buf_ptr = (char *)(p->data);
|
|
|
|
|
p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
|
|
|
|
|
tty->buf.memory_used += size;
|
|
|
|
|
port->buf.memory_used += size;
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -87,9 +87,9 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
|
|
|
|
|
* Locking: Caller must hold tty->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
|
|
|
|
|
static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &port->buf;
|
|
|
|
|
|
|
|
|
|
/* Dumb strategy for now - should keep some stats */
|
|
|
|
|
buf->memory_used -= b->size;
|
|
|
|
@ -114,14 +114,14 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
|
|
|
|
|
* Locking: Caller must hold tty->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void __tty_buffer_flush(struct tty_struct *tty)
|
|
|
|
|
static void __tty_buffer_flush(struct tty_port *port)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &port->buf;
|
|
|
|
|
struct tty_buffer *thead;
|
|
|
|
|
|
|
|
|
|
while ((thead = buf->head) != NULL) {
|
|
|
|
|
buf->head = thead->next;
|
|
|
|
|
tty_buffer_free(tty, thead);
|
|
|
|
|
tty_buffer_free(port, thead);
|
|
|
|
|
}
|
|
|
|
|
buf->tail = NULL;
|
|
|
|
|
}
|
|
|
|
@ -140,7 +140,7 @@ static void __tty_buffer_flush(struct tty_struct *tty)
|
|
|
|
|
void tty_buffer_flush(struct tty_struct *tty)
|
|
|
|
|
{
|
|
|
|
|
struct tty_port *port = tty->port;
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &port->buf;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&buf->lock, flags);
|
|
|
|
@ -155,7 +155,7 @@ void tty_buffer_flush(struct tty_struct *tty)
|
|
|
|
|
test_bit(TTYP_FLUSHPENDING, &port->iflags) == 0);
|
|
|
|
|
return;
|
|
|
|
|
} else
|
|
|
|
|
__tty_buffer_flush(tty);
|
|
|
|
|
__tty_buffer_flush(port);
|
|
|
|
|
spin_unlock_irqrestore(&buf->lock, flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -171,9 +171,9 @@ void tty_buffer_flush(struct tty_struct *tty)
|
|
|
|
|
* Locking: Caller must hold tty->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
|
|
|
|
|
static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct tty_buffer **tbh = &tty->buf.free;
|
|
|
|
|
struct tty_buffer **tbh = &port->buf.free;
|
|
|
|
|
while ((*tbh) != NULL) {
|
|
|
|
|
struct tty_buffer *t = *tbh;
|
|
|
|
|
if (t->size >= size) {
|
|
|
|
@ -182,14 +182,14 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
|
|
|
|
|
t->used = 0;
|
|
|
|
|
t->commit = 0;
|
|
|
|
|
t->read = 0;
|
|
|
|
|
tty->buf.memory_used += t->size;
|
|
|
|
|
port->buf.memory_used += t->size;
|
|
|
|
|
return t;
|
|
|
|
|
}
|
|
|
|
|
tbh = &((*tbh)->next);
|
|
|
|
|
}
|
|
|
|
|
/* Round the buffer size out */
|
|
|
|
|
size = (size + 0xFF) & ~0xFF;
|
|
|
|
|
return tty_buffer_alloc(tty, size);
|
|
|
|
|
return tty_buffer_alloc(port, size);
|
|
|
|
|
/* Should possibly check if this fails for the largest buffer we
|
|
|
|
|
have queued and recycle that ? */
|
|
|
|
|
}
|
|
|
|
@ -200,11 +200,11 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
|
|
|
|
|
*
|
|
|
|
|
* Make at least size bytes of linear space available for the tty
|
|
|
|
|
* buffer. If we fail return the size we managed to find.
|
|
|
|
|
* Locking: Caller must hold tty->buf.lock
|
|
|
|
|
* Locking: Caller must hold port->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
|
|
|
|
|
static int __tty_buffer_request_room(struct tty_port *port, size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &port->buf;
|
|
|
|
|
struct tty_buffer *b, *n;
|
|
|
|
|
int left;
|
|
|
|
|
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
|
|
|
|
@ -218,7 +218,7 @@ static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
|
|
|
|
|
|
|
|
|
|
if (left < size) {
|
|
|
|
|
/* This is the slow path - looking for new buffers to use */
|
|
|
|
|
if ((n = tty_buffer_find(tty, size)) != NULL) {
|
|
|
|
|
if ((n = tty_buffer_find(port, size)) != NULL) {
|
|
|
|
|
if (b != NULL) {
|
|
|
|
|
b->next = n;
|
|
|
|
|
b->commit = b->used;
|
|
|
|
@ -241,16 +241,17 @@ static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
|
|
|
|
|
* Make at least size bytes of linear space available for the tty
|
|
|
|
|
* buffer. If we fail return the size we managed to find.
|
|
|
|
|
*
|
|
|
|
|
* Locking: Takes tty->buf.lock
|
|
|
|
|
* Locking: Takes port->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct tty_port *port = tty->port;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
int length;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&tty->buf.lock, flags);
|
|
|
|
|
length = __tty_buffer_request_room(tty, size);
|
|
|
|
|
spin_unlock_irqrestore(&tty->buf.lock, flags);
|
|
|
|
|
spin_lock_irqsave(&port->buf.lock, flags);
|
|
|
|
|
length = __tty_buffer_request_room(port, size);
|
|
|
|
|
spin_unlock_irqrestore(&port->buf.lock, flags);
|
|
|
|
|
return length;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
|
|
|
|
@ -265,13 +266,13 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room);
|
|
|
|
|
* Queue a series of bytes to the tty buffering. All the characters
|
|
|
|
|
* passed are marked with the supplied flag. Returns the number added.
|
|
|
|
|
*
|
|
|
|
|
* Locking: Called functions may take tty->buf.lock
|
|
|
|
|
* Locking: Called functions may take port->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
|
|
|
|
|
const unsigned char *chars, char flag, size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &tty->port->buf;
|
|
|
|
|
int copied = 0;
|
|
|
|
|
do {
|
|
|
|
|
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
|
|
|
|
@ -280,7 +281,7 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
|
|
|
|
|
struct tty_buffer *tb;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&buf->lock, flags);
|
|
|
|
|
space = __tty_buffer_request_room(tty, goal);
|
|
|
|
|
space = __tty_buffer_request_room(tty->port, goal);
|
|
|
|
|
tb = buf->tail;
|
|
|
|
|
/* If there is no space then tb may be NULL */
|
|
|
|
|
if (unlikely(space == 0)) {
|
|
|
|
@ -311,13 +312,13 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
|
|
|
|
|
* the flags array indicates the status of the character. Returns the
|
|
|
|
|
* number added.
|
|
|
|
|
*
|
|
|
|
|
* Locking: Called functions may take tty->buf.lock
|
|
|
|
|
* Locking: Called functions may take port->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int tty_insert_flip_string_flags(struct tty_struct *tty,
|
|
|
|
|
const unsigned char *chars, const char *flags, size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &tty->port->buf;
|
|
|
|
|
int copied = 0;
|
|
|
|
|
do {
|
|
|
|
|
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
|
|
|
|
@ -326,7 +327,7 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
|
|
|
|
|
struct tty_buffer *tb;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&buf->lock, __flags);
|
|
|
|
|
space = __tty_buffer_request_room(tty, goal);
|
|
|
|
|
space = __tty_buffer_request_room(tty->port, goal);
|
|
|
|
|
tb = buf->tail;
|
|
|
|
|
/* If there is no space then tb may be NULL */
|
|
|
|
|
if (unlikely(space == 0)) {
|
|
|
|
@ -357,12 +358,12 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags);
|
|
|
|
|
* Note that this function can only be used when the low_latency flag
|
|
|
|
|
* is unset. Otherwise the workqueue won't be flushed.
|
|
|
|
|
*
|
|
|
|
|
* Locking: Takes tty->buf.lock
|
|
|
|
|
* Locking: Takes port->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void tty_schedule_flip(struct tty_struct *tty)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &tty->port->buf;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&buf->lock, flags);
|
|
|
|
@ -385,19 +386,19 @@ EXPORT_SYMBOL(tty_schedule_flip);
|
|
|
|
|
* that need their own block copy routines into the buffer. There is no
|
|
|
|
|
* guarantee the buffer is a DMA target!
|
|
|
|
|
*
|
|
|
|
|
* Locking: May call functions taking tty->buf.lock
|
|
|
|
|
* Locking: May call functions taking port->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
|
|
|
|
|
size_t size)
|
|
|
|
|
size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &tty->port->buf;
|
|
|
|
|
int space;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
struct tty_buffer *tb;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&buf->lock, flags);
|
|
|
|
|
space = __tty_buffer_request_room(tty, size);
|
|
|
|
|
space = __tty_buffer_request_room(tty->port, size);
|
|
|
|
|
|
|
|
|
|
tb = buf->tail;
|
|
|
|
|
if (likely(space)) {
|
|
|
|
@ -423,19 +424,19 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
|
|
|
|
|
* that need their own block copy routines into the buffer. There is no
|
|
|
|
|
* guarantee the buffer is a DMA target!
|
|
|
|
|
*
|
|
|
|
|
* Locking: May call functions taking tty->buf.lock
|
|
|
|
|
* Locking: May call functions taking port->buf.lock
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int tty_prepare_flip_string_flags(struct tty_struct *tty,
|
|
|
|
|
unsigned char **chars, char **flags, size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &tty->port->buf;
|
|
|
|
|
int space;
|
|
|
|
|
unsigned long __flags;
|
|
|
|
|
struct tty_buffer *tb;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&buf->lock, __flags);
|
|
|
|
|
space = __tty_buffer_request_room(tty, size);
|
|
|
|
|
space = __tty_buffer_request_room(tty->port, size);
|
|
|
|
|
|
|
|
|
|
tb = buf->tail;
|
|
|
|
|
if (likely(space)) {
|
|
|
|
@ -464,13 +465,16 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
|
|
|
|
|
|
|
|
|
|
static void flush_to_ldisc(struct work_struct *work)
|
|
|
|
|
{
|
|
|
|
|
struct tty_struct *tty =
|
|
|
|
|
container_of(work, struct tty_struct, buf.work);
|
|
|
|
|
struct tty_port *port = tty->port;
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_port *port = container_of(work, struct tty_port, buf.work);
|
|
|
|
|
struct tty_bufhead *buf = &port->buf;
|
|
|
|
|
struct tty_struct *tty;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
struct tty_ldisc *disc;
|
|
|
|
|
|
|
|
|
|
tty = port->itty;
|
|
|
|
|
if (WARN_RATELIMIT(tty == NULL, "tty is NULL"))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
disc = tty_ldisc_ref(tty);
|
|
|
|
|
if (disc == NULL) /* !TTY_LDISC */
|
|
|
|
|
return;
|
|
|
|
@ -489,7 +493,7 @@ static void flush_to_ldisc(struct work_struct *work)
|
|
|
|
|
if (head->next == NULL)
|
|
|
|
|
break;
|
|
|
|
|
buf->head = head->next;
|
|
|
|
|
tty_buffer_free(tty, head);
|
|
|
|
|
tty_buffer_free(port, head);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Ldisc or user is trying to flush the buffers
|
|
|
|
@ -515,7 +519,7 @@ static void flush_to_ldisc(struct work_struct *work)
|
|
|
|
|
/* We may have a deferred request to flush the input buffer,
|
|
|
|
|
if so pull the chain under the lock and empty the queue */
|
|
|
|
|
if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
|
|
|
|
|
__tty_buffer_flush(tty);
|
|
|
|
|
__tty_buffer_flush(port);
|
|
|
|
|
clear_bit(TTYP_FLUSHPENDING, &port->iflags);
|
|
|
|
|
wake_up(&tty->read_wait);
|
|
|
|
|
}
|
|
|
|
@ -535,7 +539,7 @@ static void flush_to_ldisc(struct work_struct *work)
|
|
|
|
|
void tty_flush_to_ldisc(struct tty_struct *tty)
|
|
|
|
|
{
|
|
|
|
|
if (!tty->low_latency)
|
|
|
|
|
flush_work(&tty->buf.work);
|
|
|
|
|
flush_work(&tty->port->buf.work);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -553,7 +557,7 @@ void tty_flush_to_ldisc(struct tty_struct *tty)
|
|
|
|
|
|
|
|
|
|
void tty_flip_buffer_push(struct tty_struct *tty)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &tty->port->buf;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&buf->lock, flags);
|
|
|
|
@ -578,9 +582,9 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
|
|
|
|
|
* Locking: none
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void tty_buffer_init(struct tty_struct *tty)
|
|
|
|
|
void tty_buffer_init(struct tty_port *port)
|
|
|
|
|
{
|
|
|
|
|
struct tty_bufhead *buf = &tty->buf;
|
|
|
|
|
struct tty_bufhead *buf = &port->buf;
|
|
|
|
|
|
|
|
|
|
spin_lock_init(&buf->lock);
|
|
|
|
|
buf->head = NULL;
|
|
|
|
|