diff options
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r-- | drivers/char/tty_io.c | 104 |
1 files changed, 70 insertions, 34 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index eb8b5be4e249..e9bba94fc898 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,9 @@ 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; | ||
271 | p->commit = 0; | ||
272 | p->read = 0; | ||
269 | p->char_buf_ptr = (char *)(p->data); | 273 | p->char_buf_ptr = (char *)(p->data); |
270 | p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; | 274 | p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; |
271 | /* printk("Flip create %p\n", p); */ | 275 | /* printk("Flip create %p\n", p); */ |
@@ -296,6 +300,8 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) | |||
296 | *tbh = t->next; | 300 | *tbh = t->next; |
297 | t->next = NULL; | 301 | t->next = NULL; |
298 | t->used = 0; | 302 | t->used = 0; |
303 | t->commit = 0; | ||
304 | t->read = 0; | ||
299 | /* DEBUG ONLY */ | 305 | /* DEBUG ONLY */ |
300 | memset(t->data, '*', size); | 306 | memset(t->data, '*', size); |
301 | /* printk("Flip recycle %p\n", t); */ | 307 | /* printk("Flip recycle %p\n", t); */ |
@@ -312,25 +318,37 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) | |||
312 | 318 | ||
313 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) | 319 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) |
314 | { | 320 | { |
315 | struct tty_buffer *b = tty->buf.tail, *n; | 321 | struct tty_buffer *b, *n; |
316 | int left = 0; | 322 | int left; |
323 | unsigned long flags; | ||
324 | |||
325 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
317 | 326 | ||
318 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to | 327 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to |
319 | remove this conditional if its worth it. This would be invisible | 328 | remove this conditional if its worth it. This would be invisible |
320 | to the callers */ | 329 | to the callers */ |
321 | if(b != NULL) | 330 | if ((b = tty->buf.tail) != NULL) { |
322 | left = b->size - b->used; | 331 | left = b->size - b->used; |
323 | if(left >= size) | 332 | b->active = 1; |
324 | return size; | 333 | } else |
325 | /* This is the slow path - looking for new buffers to use */ | 334 | left = 0; |
326 | n = tty_buffer_find(tty, size); | 335 | |
327 | if(n == NULL) | 336 | if (left < size) { |
328 | return left; | 337 | /* This is the slow path - looking for new buffers to use */ |
329 | if(b != NULL) | 338 | if ((n = tty_buffer_find(tty, size)) != NULL) { |
330 | b->next = n; | 339 | if (b != NULL) { |
331 | else | 340 | b->next = n; |
332 | tty->buf.head = n; | 341 | b->active = 0; |
333 | tty->buf.tail = n; | 342 | b->commit = b->used; |
343 | } else | ||
344 | tty->buf.head = n; | ||
345 | tty->buf.tail = n; | ||
346 | n->active = 1; | ||
347 | } else | ||
348 | size = left; | ||
349 | } | ||
350 | |||
351 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
334 | return size; | 352 | return size; |
335 | } | 353 | } |
336 | 354 | ||
@@ -396,10 +414,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) | 414 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) |
397 | { | 415 | { |
398 | int space = tty_buffer_request_room(tty, size); | 416 | int space = tty_buffer_request_room(tty, size); |
399 | struct tty_buffer *tb = tty->buf.tail; | 417 | if (likely(space)) { |
400 | *chars = tb->char_buf_ptr + tb->used; | 418 | struct tty_buffer *tb = tty->buf.tail; |
401 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); | 419 | *chars = tb->char_buf_ptr + tb->used; |
402 | tb->used += space; | 420 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); |
421 | tb->used += space; | ||
422 | } | ||
403 | return space; | 423 | return space; |
404 | } | 424 | } |
405 | 425 | ||
@@ -416,10 +436,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) | 436 | int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) |
417 | { | 437 | { |
418 | int space = tty_buffer_request_room(tty, size); | 438 | int space = tty_buffer_request_room(tty, size); |
419 | struct tty_buffer *tb = tty->buf.tail; | 439 | if (likely(space)) { |
420 | *chars = tb->char_buf_ptr + tb->used; | 440 | struct tty_buffer *tb = tty->buf.tail; |
421 | *flags = tb->flag_buf_ptr + tb->used; | 441 | *chars = tb->char_buf_ptr + tb->used; |
422 | tb->used += space; | 442 | *flags = tb->flag_buf_ptr + tb->used; |
443 | tb->used += space; | ||
444 | } | ||
423 | return space; | 445 | return space; |
424 | } | 446 | } |
425 | 447 | ||
@@ -1819,7 +1841,6 @@ static void release_dev(struct file * filp) | |||
1819 | tty_closing = tty->count <= 1; | 1841 | tty_closing = tty->count <= 1; |
1820 | o_tty_closing = o_tty && | 1842 | o_tty_closing = o_tty && |
1821 | (o_tty->count <= (pty_master ? 1 : 0)); | 1843 | (o_tty->count <= (pty_master ? 1 : 0)); |
1822 | up(&tty_sem); | ||
1823 | do_sleep = 0; | 1844 | do_sleep = 0; |
1824 | 1845 | ||
1825 | if (tty_closing) { | 1846 | if (tty_closing) { |
@@ -1847,6 +1868,7 @@ static void release_dev(struct file * filp) | |||
1847 | 1868 | ||
1848 | printk(KERN_WARNING "release_dev: %s: read/write wait queue " | 1869 | printk(KERN_WARNING "release_dev: %s: read/write wait queue " |
1849 | "active!\n", tty_name(tty, buf)); | 1870 | "active!\n", tty_name(tty, buf)); |
1871 | up(&tty_sem); | ||
1850 | schedule(); | 1872 | schedule(); |
1851 | } | 1873 | } |
1852 | 1874 | ||
@@ -1855,8 +1877,6 @@ static void release_dev(struct file * filp) | |||
1855 | * both sides, and we've completed the last operation that could | 1877 | * both sides, and we've completed the last operation that could |
1856 | * block, so it's safe to proceed with closing. | 1878 | * block, so it's safe to proceed with closing. |
1857 | */ | 1879 | */ |
1858 | |||
1859 | down(&tty_sem); | ||
1860 | if (pty_master) { | 1880 | if (pty_master) { |
1861 | if (--o_tty->count < 0) { | 1881 | if (--o_tty->count < 0) { |
1862 | printk(KERN_WARNING "release_dev: bad pty slave count " | 1882 | printk(KERN_WARNING "release_dev: bad pty slave count " |
@@ -1870,7 +1890,6 @@ static void release_dev(struct file * filp) | |||
1870 | tty->count, tty_name(tty, buf)); | 1890 | tty->count, tty_name(tty, buf)); |
1871 | tty->count = 0; | 1891 | tty->count = 0; |
1872 | } | 1892 | } |
1873 | up(&tty_sem); | ||
1874 | 1893 | ||
1875 | /* | 1894 | /* |
1876 | * We've decremented tty->count, so we need to remove this file | 1895 | * We've decremented tty->count, so we need to remove this file |
@@ -1915,6 +1934,8 @@ static void release_dev(struct file * filp) | |||
1915 | read_unlock(&tasklist_lock); | 1934 | read_unlock(&tasklist_lock); |
1916 | } | 1935 | } |
1917 | 1936 | ||
1937 | up(&tty_sem); | ||
1938 | |||
1918 | /* check whether both sides are closing ... */ | 1939 | /* check whether both sides are closing ... */ |
1919 | if (!tty_closing || (o_tty && !o_tty_closing)) | 1940 | if (!tty_closing || (o_tty && !o_tty_closing)) |
1920 | return; | 1941 | return; |
@@ -2735,6 +2756,9 @@ static void flush_to_ldisc(void *private_) | |||
2735 | unsigned long flags; | 2756 | unsigned long flags; |
2736 | struct tty_ldisc *disc; | 2757 | struct tty_ldisc *disc; |
2737 | struct tty_buffer *tbuf; | 2758 | struct tty_buffer *tbuf; |
2759 | int count; | ||
2760 | char *char_buf; | ||
2761 | unsigned char *flag_buf; | ||
2738 | 2762 | ||
2739 | disc = tty_ldisc_ref(tty); | 2763 | disc = tty_ldisc_ref(tty); |
2740 | if (disc == NULL) /* !TTY_LDISC */ | 2764 | if (disc == NULL) /* !TTY_LDISC */ |
@@ -2747,20 +2771,24 @@ static void flush_to_ldisc(void *private_) | |||
2747 | schedule_delayed_work(&tty->buf.work, 1); | 2771 | schedule_delayed_work(&tty->buf.work, 1); |
2748 | goto out; | 2772 | goto out; |
2749 | } | 2773 | } |
2750 | spin_lock_irqsave(&tty->read_lock, flags); | 2774 | spin_lock_irqsave(&tty->buf.lock, flags); |
2751 | while((tbuf = tty->buf.head) != NULL) { | 2775 | while((tbuf = tty->buf.head) != NULL) { |
2776 | while ((count = tbuf->commit - tbuf->read) != 0) { | ||
2777 | char_buf = tbuf->char_buf_ptr + tbuf->read; | ||
2778 | flag_buf = tbuf->flag_buf_ptr + tbuf->read; | ||
2779 | tbuf->read += count; | ||
2780 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
2781 | disc->receive_buf(tty, char_buf, flag_buf, count); | ||
2782 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
2783 | } | ||
2784 | if (tbuf->active) | ||
2785 | break; | ||
2752 | tty->buf.head = tbuf->next; | 2786 | tty->buf.head = tbuf->next; |
2753 | if (tty->buf.head == NULL) | 2787 | if (tty->buf.head == NULL) |
2754 | tty->buf.tail = NULL; | 2788 | tty->buf.tail = NULL; |
2755 | spin_unlock_irqrestore(&tty->read_lock, flags); | ||
2756 | /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */ | ||
2757 | disc->receive_buf(tty, tbuf->char_buf_ptr, | ||
2758 | tbuf->flag_buf_ptr, | ||
2759 | tbuf->used); | ||
2760 | spin_lock_irqsave(&tty->read_lock, flags); | ||
2761 | tty_buffer_free(tty, tbuf); | 2789 | tty_buffer_free(tty, tbuf); |
2762 | } | 2790 | } |
2763 | spin_unlock_irqrestore(&tty->read_lock, flags); | 2791 | spin_unlock_irqrestore(&tty->buf.lock, flags); |
2764 | out: | 2792 | out: |
2765 | tty_ldisc_deref(disc); | 2793 | tty_ldisc_deref(disc); |
2766 | } | 2794 | } |
@@ -2852,6 +2880,14 @@ EXPORT_SYMBOL(tty_get_baud_rate); | |||
2852 | 2880 | ||
2853 | void tty_flip_buffer_push(struct tty_struct *tty) | 2881 | void tty_flip_buffer_push(struct tty_struct *tty) |
2854 | { | 2882 | { |
2883 | unsigned long flags; | ||
2884 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
2885 | if (tty->buf.tail != NULL) { | ||
2886 | tty->buf.tail->active = 0; | ||
2887 | tty->buf.tail->commit = tty->buf.tail->used; | ||
2888 | } | ||
2889 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
2890 | |||
2855 | if (tty->low_latency) | 2891 | if (tty->low_latency) |
2856 | flush_to_ldisc((void *) tty); | 2892 | flush_to_ldisc((void *) tty); |
2857 | else | 2893 | else |