aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r--drivers/char/tty_io.c104
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
254static void tty_buffer_init(struct tty_struct *tty) 254static 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
313int tty_buffer_request_room(struct tty_struct *tty, size_t size) 319int 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);
396int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) 414int 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);
416int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) 436int 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);
2764out: 2792out:
2765 tty_ldisc_deref(disc); 2793 tty_ldisc_deref(disc);
2766} 2794}
@@ -2852,6 +2880,14 @@ EXPORT_SYMBOL(tty_get_baud_rate);
2852 2880
2853void tty_flip_buffer_push(struct tty_struct *tty) 2881void 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