diff options
Diffstat (limited to 'drivers/char/tty_io.c')
| -rw-r--r-- | drivers/char/tty_io.c | 77 |
1 files changed, 50 insertions, 27 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index eb8b5be4e249..076e07c1da38 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
| @@ -253,6 +253,7 @@ static void tty_buffer_free_all(struct tty_struct *tty) | |||
| 253 | 253 | ||
| 254 | static void tty_buffer_init(struct tty_struct *tty) | 254 | static void tty_buffer_init(struct tty_struct *tty) |
| 255 | { | 255 | { |
| 256 | spin_lock_init(&tty->buf.lock); | ||
| 256 | tty->buf.head = NULL; | 257 | tty->buf.head = NULL; |
| 257 | tty->buf.tail = NULL; | 258 | tty->buf.tail = NULL; |
| 258 | tty->buf.free = NULL; | 259 | tty->buf.free = NULL; |
| @@ -266,6 +267,7 @@ static struct tty_buffer *tty_buffer_alloc(size_t size) | |||
| 266 | p->used = 0; | 267 | p->used = 0; |
| 267 | p->size = size; | 268 | p->size = size; |
| 268 | p->next = NULL; | 269 | p->next = NULL; |
| 270 | p->active = 0; | ||
| 269 | p->char_buf_ptr = (char *)(p->data); | 271 | p->char_buf_ptr = (char *)(p->data); |
| 270 | p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; | 272 | p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; |
| 271 | /* printk("Flip create %p\n", p); */ | 273 | /* printk("Flip create %p\n", p); */ |
| @@ -312,25 +314,36 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) | |||
| 312 | 314 | ||
| 313 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) | 315 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) |
| 314 | { | 316 | { |
| 315 | struct tty_buffer *b = tty->buf.tail, *n; | 317 | struct tty_buffer *b, *n; |
| 316 | int left = 0; | 318 | int left; |
| 319 | unsigned long flags; | ||
| 320 | |||
| 321 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
| 317 | 322 | ||
| 318 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to | 323 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to |
| 319 | remove this conditional if its worth it. This would be invisible | 324 | remove this conditional if its worth it. This would be invisible |
| 320 | to the callers */ | 325 | to the callers */ |
| 321 | if(b != NULL) | 326 | if ((b = tty->buf.tail) != NULL) { |
| 322 | left = b->size - b->used; | 327 | left = b->size - b->used; |
| 323 | if(left >= size) | 328 | b->active = 1; |
| 324 | return size; | 329 | } else |
| 325 | /* This is the slow path - looking for new buffers to use */ | 330 | left = 0; |
| 326 | n = tty_buffer_find(tty, size); | 331 | |
| 327 | if(n == NULL) | 332 | if (left < size) { |
| 328 | return left; | 333 | /* This is the slow path - looking for new buffers to use */ |
| 329 | if(b != NULL) | 334 | if ((n = tty_buffer_find(tty, size)) != NULL) { |
| 330 | b->next = n; | 335 | if (b != NULL) { |
| 331 | else | 336 | b->next = n; |
| 332 | tty->buf.head = n; | 337 | b->active = 0; |
| 333 | tty->buf.tail = n; | 338 | } else |
| 339 | tty->buf.head = n; | ||
| 340 | tty->buf.tail = n; | ||
| 341 | n->active = 1; | ||
| 342 | } else | ||
| 343 | size = left; | ||
| 344 | } | ||
| 345 | |||
| 346 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
| 334 | return size; | 347 | return size; |
| 335 | } | 348 | } |
| 336 | 349 | ||
| @@ -396,10 +409,12 @@ EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags); | |||
| 396 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) | 409 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) |
| 397 | { | 410 | { |
| 398 | int space = tty_buffer_request_room(tty, size); | 411 | int space = tty_buffer_request_room(tty, size); |
| 399 | struct tty_buffer *tb = tty->buf.tail; | 412 | if (likely(space)) { |
| 400 | *chars = tb->char_buf_ptr + tb->used; | 413 | struct tty_buffer *tb = tty->buf.tail; |
| 401 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); | 414 | *chars = tb->char_buf_ptr + tb->used; |
| 402 | tb->used += space; | 415 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); |
| 416 | tb->used += space; | ||
| 417 | } | ||
| 403 | return space; | 418 | return space; |
| 404 | } | 419 | } |
| 405 | 420 | ||
| @@ -416,10 +431,12 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); | |||
| 416 | int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) | 431 | int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) |
| 417 | { | 432 | { |
| 418 | int space = tty_buffer_request_room(tty, size); | 433 | int space = tty_buffer_request_room(tty, size); |
| 419 | struct tty_buffer *tb = tty->buf.tail; | 434 | if (likely(space)) { |
| 420 | *chars = tb->char_buf_ptr + tb->used; | 435 | struct tty_buffer *tb = tty->buf.tail; |
| 421 | *flags = tb->flag_buf_ptr + tb->used; | 436 | *chars = tb->char_buf_ptr + tb->used; |
| 422 | tb->used += space; | 437 | *flags = tb->flag_buf_ptr + tb->used; |
| 438 | tb->used += space; | ||
| 439 | } | ||
| 423 | return space; | 440 | return space; |
| 424 | } | 441 | } |
| 425 | 442 | ||
| @@ -2747,20 +2764,20 @@ static void flush_to_ldisc(void *private_) | |||
| 2747 | schedule_delayed_work(&tty->buf.work, 1); | 2764 | schedule_delayed_work(&tty->buf.work, 1); |
| 2748 | goto out; | 2765 | goto out; |
| 2749 | } | 2766 | } |
| 2750 | spin_lock_irqsave(&tty->read_lock, flags); | 2767 | spin_lock_irqsave(&tty->buf.lock, flags); |
| 2751 | while((tbuf = tty->buf.head) != NULL) { | 2768 | while((tbuf = tty->buf.head) != NULL && !tbuf->active) { |
| 2752 | tty->buf.head = tbuf->next; | 2769 | tty->buf.head = tbuf->next; |
| 2753 | if (tty->buf.head == NULL) | 2770 | if (tty->buf.head == NULL) |
| 2754 | tty->buf.tail = NULL; | 2771 | tty->buf.tail = NULL; |
| 2755 | spin_unlock_irqrestore(&tty->read_lock, flags); | 2772 | spin_unlock_irqrestore(&tty->buf.lock, flags); |
| 2756 | /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */ | 2773 | /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */ |
| 2757 | disc->receive_buf(tty, tbuf->char_buf_ptr, | 2774 | disc->receive_buf(tty, tbuf->char_buf_ptr, |
| 2758 | tbuf->flag_buf_ptr, | 2775 | tbuf->flag_buf_ptr, |
| 2759 | tbuf->used); | 2776 | tbuf->used); |
| 2760 | spin_lock_irqsave(&tty->read_lock, flags); | 2777 | spin_lock_irqsave(&tty->buf.lock, flags); |
| 2761 | tty_buffer_free(tty, tbuf); | 2778 | tty_buffer_free(tty, tbuf); |
| 2762 | } | 2779 | } |
| 2763 | spin_unlock_irqrestore(&tty->read_lock, flags); | 2780 | spin_unlock_irqrestore(&tty->buf.lock, flags); |
| 2764 | out: | 2781 | out: |
| 2765 | tty_ldisc_deref(disc); | 2782 | tty_ldisc_deref(disc); |
| 2766 | } | 2783 | } |
| @@ -2852,6 +2869,12 @@ EXPORT_SYMBOL(tty_get_baud_rate); | |||
| 2852 | 2869 | ||
| 2853 | void tty_flip_buffer_push(struct tty_struct *tty) | 2870 | void tty_flip_buffer_push(struct tty_struct *tty) |
| 2854 | { | 2871 | { |
| 2872 | unsigned long flags; | ||
| 2873 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
| 2874 | if (tty->buf.tail != NULL) | ||
| 2875 | tty->buf.tail->active = 0; | ||
| 2876 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
| 2877 | |||
| 2855 | if (tty->low_latency) | 2878 | if (tty->low_latency) |
| 2856 | flush_to_ldisc((void *) tty); | 2879 | flush_to_ldisc((void *) tty); |
| 2857 | else | 2880 | else |
