diff options
Diffstat (limited to 'drivers/char/hvc_console.c')
-rw-r--r-- | drivers/char/hvc_console.c | 69 |
1 files changed, 29 insertions, 40 deletions
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index a94c5b0cac52..2b6a56b2bf35 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
@@ -39,8 +39,10 @@ | |||
39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
40 | #include <linux/spinlock.h> | 40 | #include <linux/spinlock.h> |
41 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
42 | |||
42 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
43 | #include <asm/hvconsole.h> | 44 | |
45 | #include "hvc_console.h" | ||
44 | 46 | ||
45 | #define HVC_MAJOR 229 | 47 | #define HVC_MAJOR 229 |
46 | #define HVC_MINOR 0 | 48 | #define HVC_MINOR 0 |
@@ -54,17 +56,14 @@ | |||
54 | #define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ | 56 | #define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ |
55 | 57 | ||
56 | /* | 58 | /* |
57 | * The Linux TTY code does not support dynamic addition of tty derived devices | 59 | * These sizes are most efficient for vio, because they are the |
58 | * so we need to know how many tty devices we might need when space is allocated | 60 | * native transfer size. We could make them selectable in the |
59 | * for the tty device. Since this driver supports hotplug of vty adapters we | 61 | * future to better deal with backends that want other buffer sizes. |
60 | * need to make sure we have enough allocated. | ||
61 | */ | 62 | */ |
62 | #define HVC_ALLOC_TTY_ADAPTERS 8 | ||
63 | |||
64 | #define N_OUTBUF 16 | 63 | #define N_OUTBUF 16 |
65 | #define N_INBUF 16 | 64 | #define N_INBUF 16 |
66 | 65 | ||
67 | #define __ALIGNED__ __attribute__((__aligned__(8))) | 66 | #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) |
68 | 67 | ||
69 | static struct tty_driver *hvc_driver; | 68 | static struct tty_driver *hvc_driver; |
70 | static struct task_struct *hvc_task; | 69 | static struct task_struct *hvc_task; |
@@ -154,7 +153,7 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = | |||
154 | 153 | ||
155 | void hvc_console_print(struct console *co, const char *b, unsigned count) | 154 | void hvc_console_print(struct console *co, const char *b, unsigned count) |
156 | { | 155 | { |
157 | char c[16] __ALIGNED__; | 156 | char c[N_OUTBUF] __ALIGNED__; |
158 | unsigned i = 0, n = 0; | 157 | unsigned i = 0, n = 0; |
159 | int r, donecr = 0, index = co->index; | 158 | int r, donecr = 0, index = co->index; |
160 | 159 | ||
@@ -473,8 +472,10 @@ static void hvc_push(struct hvc_struct *hp) | |||
473 | 472 | ||
474 | n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); | 473 | n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); |
475 | if (n <= 0) { | 474 | if (n <= 0) { |
476 | if (n == 0) | 475 | if (n == 0) { |
476 | hp->do_wakeup = 1; | ||
477 | return; | 477 | return; |
478 | } | ||
478 | /* throw away output on error; this happens when | 479 | /* throw away output on error; this happens when |
479 | there is no session connected to the vterm. */ | 480 | there is no session connected to the vterm. */ |
480 | hp->n_outbuf = 0; | 481 | hp->n_outbuf = 0; |
@@ -486,12 +487,19 @@ static void hvc_push(struct hvc_struct *hp) | |||
486 | hp->do_wakeup = 1; | 487 | hp->do_wakeup = 1; |
487 | } | 488 | } |
488 | 489 | ||
489 | static inline int __hvc_write_kernel(struct hvc_struct *hp, | 490 | static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) |
490 | const unsigned char *buf, int count) | ||
491 | { | 491 | { |
492 | struct hvc_struct *hp = tty->driver_data; | ||
492 | unsigned long flags; | 493 | unsigned long flags; |
493 | int rsize, written = 0; | 494 | int rsize, written = 0; |
494 | 495 | ||
496 | /* This write was probably executed during a tty close. */ | ||
497 | if (!hp) | ||
498 | return -EPIPE; | ||
499 | |||
500 | if (hp->count <= 0) | ||
501 | return -EIO; | ||
502 | |||
495 | spin_lock_irqsave(&hp->lock, flags); | 503 | spin_lock_irqsave(&hp->lock, flags); |
496 | 504 | ||
497 | /* Push pending writes */ | 505 | /* Push pending writes */ |
@@ -510,26 +518,8 @@ static inline int __hvc_write_kernel(struct hvc_struct *hp, | |||
510 | } | 518 | } |
511 | spin_unlock_irqrestore(&hp->lock, flags); | 519 | spin_unlock_irqrestore(&hp->lock, flags); |
512 | 520 | ||
513 | return written; | ||
514 | } | ||
515 | static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) | ||
516 | { | ||
517 | struct hvc_struct *hp = tty->driver_data; | ||
518 | int written; | ||
519 | |||
520 | /* This write was probably executed during a tty close. */ | ||
521 | if (!hp) | ||
522 | return -EPIPE; | ||
523 | |||
524 | if (hp->count <= 0) | ||
525 | return -EIO; | ||
526 | |||
527 | written = __hvc_write_kernel(hp, buf, count); | ||
528 | |||
529 | /* | 521 | /* |
530 | * Racy, but harmless, kick thread if there is still pending data. | 522 | * Racy, but harmless, kick thread if there is still pending data. |
531 | * There really is nothing wrong with kicking the thread, even if there | ||
532 | * is no buffered data. | ||
533 | */ | 523 | */ |
534 | if (hp->n_outbuf) | 524 | if (hp->n_outbuf) |
535 | hvc_kick(); | 525 | hvc_kick(); |
@@ -614,6 +604,13 @@ static int hvc_poll(struct hvc_struct *hp) | |||
614 | spin_unlock_irqrestore(&hp->lock, flags); | 604 | spin_unlock_irqrestore(&hp->lock, flags); |
615 | tty_hangup(tty); | 605 | tty_hangup(tty); |
616 | spin_lock_irqsave(&hp->lock, flags); | 606 | spin_lock_irqsave(&hp->lock, flags); |
607 | } else if ( n == -EAGAIN ) { | ||
608 | /* | ||
609 | * Some back-ends can only ensure a certain min | ||
610 | * num of bytes read, which may be > 'count'. | ||
611 | * Let the tty clear the flip buff to make room. | ||
612 | */ | ||
613 | poll_mask |= HVC_POLL_READ; | ||
617 | } | 614 | } |
618 | break; | 615 | break; |
619 | } | 616 | } |
@@ -635,16 +632,7 @@ static int hvc_poll(struct hvc_struct *hp) | |||
635 | tty_insert_flip_char(tty, buf[i], 0); | 632 | tty_insert_flip_char(tty, buf[i], 0); |
636 | } | 633 | } |
637 | 634 | ||
638 | /* | ||
639 | * Account for the total amount read in one loop, and if above | ||
640 | * 64 bytes, we do a quick schedule loop to let the tty grok | ||
641 | * the data and eventually throttle us. | ||
642 | */ | ||
643 | read_total += n; | 635 | read_total += n; |
644 | if (read_total >= 64) { | ||
645 | poll_mask |= HVC_POLL_QUICK; | ||
646 | break; | ||
647 | } | ||
648 | } | 636 | } |
649 | throttled: | 637 | throttled: |
650 | /* Wakeup write queue if necessary */ | 638 | /* Wakeup write queue if necessary */ |
@@ -767,7 +755,8 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, | |||
767 | * see if this vterm id matches one registered for console. | 755 | * see if this vterm id matches one registered for console. |
768 | */ | 756 | */ |
769 | for (i=0; i < MAX_NR_HVC_CONSOLES; i++) | 757 | for (i=0; i < MAX_NR_HVC_CONSOLES; i++) |
770 | if (vtermnos[i] == hp->vtermno) | 758 | if (vtermnos[i] == hp->vtermno && |
759 | cons_ops[i] == hp->ops) | ||
771 | break; | 760 | break; |
772 | 761 | ||
773 | /* no matching slot, just use a counter */ | 762 | /* no matching slot, just use a counter */ |