1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/console.h>
26#include <linux/cpumask.h>
27#include <linux/init.h>
28#include <linux/kbd_kern.h>
29#include <linux/kernel.h>
30#include <linux/kthread.h>
31#include <linux/list.h>
32#include <linux/module.h>
33#include <linux/major.h>
34#include <linux/sysrq.h>
35#include <linux/tty.h>
36#include <linux/tty_flip.h>
37#include <linux/sched.h>
38#include <linux/spinlock.h>
39#include <linux/delay.h>
40#include <linux/freezer.h>
41#include <linux/slab.h>
42#include <linux/serial_core.h>
43
44#include <asm/uaccess.h>
45
46#include "hvc_console.h"
47
48#define HVC_MAJOR 229
49#define HVC_MINOR 0
50
51
52
53
54
55#define HVC_CLOSE_WAIT (HZ/100)
56
57
58
59
60
61
62#define N_OUTBUF 16
63#define N_INBUF 16
64
65#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
66
67static struct tty_driver *hvc_driver;
68static struct task_struct *hvc_task;
69
70
71static int hvc_kicked;
72
73static int hvc_init(void);
74
75#ifdef CONFIG_MAGIC_SYSRQ
76static int sysrq_pressed;
77#endif
78
79
80static LIST_HEAD(hvc_structs);
81
82
83
84
85
86static DEFINE_SPINLOCK(hvc_structs_lock);
87
88
89
90
91
92
93static int last_hvc = -1;
94
95
96
97
98
99
100static struct hvc_struct *hvc_get_by_index(int index)
101{
102 struct hvc_struct *hp;
103 unsigned long flags;
104
105 spin_lock(&hvc_structs_lock);
106
107 list_for_each_entry(hp, &hvc_structs, next) {
108 spin_lock_irqsave(&hp->lock, flags);
109 if (hp->index == index) {
110 tty_port_get(&hp->port);
111 spin_unlock_irqrestore(&hp->lock, flags);
112 spin_unlock(&hvc_structs_lock);
113 return hp;
114 }
115 spin_unlock_irqrestore(&hp->lock, flags);
116 }
117 hp = NULL;
118
119 spin_unlock(&hvc_structs_lock);
120 return hp;
121}
122
123
124
125
126
127
128
129
130static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
131static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
132 {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1};
133
134
135
136
137
138
139static void hvc_console_print(struct console *co, const char *b,
140 unsigned count)
141{
142 char c[N_OUTBUF] __ALIGNED__;
143 unsigned i = 0, n = 0;
144 int r, donecr = 0, index = co->index;
145
146
147 if (index >= MAX_NR_HVC_CONSOLES)
148 return;
149
150
151 if (vtermnos[index] == -1)
152 return;
153
154 while (count > 0 || i > 0) {
155 if (count > 0 && i < sizeof(c)) {
156 if (b[n] == '\n' && !donecr) {
157 c[i++] = '\r';
158 donecr = 1;
159 } else {
160 c[i++] = b[n++];
161 donecr = 0;
162 --count;
163 }
164 } else {
165 r = cons_ops[index]->put_chars(vtermnos[index], c, i);
166 if (r <= 0) {
167
168
169 if (r != -EAGAIN)
170 i = 0;
171 } else if (r > 0) {
172 i -= r;
173 if (i > 0)
174 memmove(c, c+r, i);
175 }
176 }
177 }
178}
179
180static struct tty_driver *hvc_console_device(struct console *c, int *index)
181{
182 if (vtermnos[c->index] == -1)
183 return NULL;
184
185 *index = c->index;
186 return hvc_driver;
187}
188
189static int __init hvc_console_setup(struct console *co, char *options)
190{
191 if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
192 return -ENODEV;
193
194 if (vtermnos[co->index] == -1)
195 return -ENODEV;
196
197 return 0;
198}
199
200static struct console hvc_console = {
201 .name = "hvc",
202 .write = hvc_console_print,
203 .device = hvc_console_device,
204 .setup = hvc_console_setup,
205 .flags = CON_PRINTBUFFER,
206 .index = -1,
207};
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224static int __init hvc_console_init(void)
225{
226 register_console(&hvc_console);
227 return 0;
228}
229console_initcall(hvc_console_init);
230
231
232static void hvc_port_destruct(struct tty_port *port)
233{
234 struct hvc_struct *hp = container_of(port, struct hvc_struct, port);
235 unsigned long flags;
236
237 spin_lock(&hvc_structs_lock);
238
239 spin_lock_irqsave(&hp->lock, flags);
240 list_del(&(hp->next));
241 spin_unlock_irqrestore(&hp->lock, flags);
242
243 spin_unlock(&hvc_structs_lock);
244
245 kfree(hp);
246}
247
248static void hvc_check_console(int index)
249{
250
251 if (hvc_console.flags & CON_ENABLED)
252 return;
253
254
255
256
257
258 if (index == hvc_console.index)
259 register_console(&hvc_console);
260}
261
262
263
264
265
266
267
268int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
269{
270 struct hvc_struct *hp;
271
272 if (index < 0 || index >= MAX_NR_HVC_CONSOLES)
273 return -1;
274
275 if (vtermnos[index] != -1)
276 return -1;
277
278
279 hp = hvc_get_by_index(index);
280 if (hp) {
281 tty_port_put(&hp->port);
282 return -1;
283 }
284
285 vtermnos[index] = vtermno;
286 cons_ops[index] = ops;
287
288
289 if (last_hvc < index)
290 last_hvc = index;
291
292
293 hvc_check_console(index);
294
295 return 0;
296}
297EXPORT_SYMBOL_GPL(hvc_instantiate);
298
299
300void hvc_kick(void)
301{
302 hvc_kicked = 1;
303 wake_up_process(hvc_task);
304}
305EXPORT_SYMBOL_GPL(hvc_kick);
306
307static void hvc_unthrottle(struct tty_struct *tty)
308{
309 hvc_kick();
310}
311
312static int hvc_install(struct tty_driver *driver, struct tty_struct *tty)
313{
314 struct hvc_struct *hp;
315 int rc;
316
317
318 if (!(hp = hvc_get_by_index(tty->index)))
319 return -ENODEV;
320
321 tty->driver_data = hp;
322
323 rc = tty_port_install(&hp->port, driver, tty);
324 if (rc)
325 tty_port_put(&hp->port);
326 return rc;
327}
328
329
330
331
332
333static int hvc_open(struct tty_struct *tty, struct file * filp)
334{
335 struct hvc_struct *hp = tty->driver_data;
336 unsigned long flags;
337 int rc = 0;
338
339 spin_lock_irqsave(&hp->port.lock, flags);
340
341 if (hp->port.count++ > 0) {
342 spin_unlock_irqrestore(&hp->port.lock, flags);
343 hvc_kick();
344 return 0;
345 }
346 spin_unlock_irqrestore(&hp->port.lock, flags);
347
348 tty_port_tty_set(&hp->port, tty);
349
350 if (hp->ops->notifier_add)
351 rc = hp->ops->notifier_add(hp, hp->data);
352
353
354
355
356
357
358
359 if (rc) {
360 tty_port_tty_set(&hp->port, NULL);
361 tty->driver_data = NULL;
362 tty_port_put(&hp->port);
363 printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
364 } else
365
366 if (C_BAUD(tty))
367 if (hp->ops->dtr_rts)
368 hp->ops->dtr_rts(hp, 1);
369
370
371 hvc_kick();
372
373 return rc;
374}
375
376static void hvc_close(struct tty_struct *tty, struct file * filp)
377{
378 struct hvc_struct *hp;
379 unsigned long flags;
380
381 if (tty_hung_up_p(filp))
382 return;
383
384
385
386
387
388
389 if (!tty->driver_data)
390 return;
391
392 hp = tty->driver_data;
393
394 spin_lock_irqsave(&hp->port.lock, flags);
395
396 if (--hp->port.count == 0) {
397 spin_unlock_irqrestore(&hp->port.lock, flags);
398
399 tty_port_tty_set(&hp->port, NULL);
400
401 if (C_HUPCL(tty))
402 if (hp->ops->dtr_rts)
403 hp->ops->dtr_rts(hp, 0);
404
405 if (hp->ops->notifier_del)
406 hp->ops->notifier_del(hp, hp->data);
407
408
409 cancel_work_sync(&hp->tty_resize);
410
411
412
413
414
415
416 tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
417 } else {
418 if (hp->port.count < 0)
419 printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
420 hp->vtermno, hp->port.count);
421 spin_unlock_irqrestore(&hp->port.lock, flags);
422 }
423}
424
425static void hvc_cleanup(struct tty_struct *tty)
426{
427 struct hvc_struct *hp = tty->driver_data;
428
429 tty_port_put(&hp->port);
430}
431
432static void hvc_hangup(struct tty_struct *tty)
433{
434 struct hvc_struct *hp = tty->driver_data;
435 unsigned long flags;
436
437 if (!hp)
438 return;
439
440
441 cancel_work_sync(&hp->tty_resize);
442
443 spin_lock_irqsave(&hp->port.lock, flags);
444
445
446
447
448
449
450 if (hp->port.count <= 0) {
451 spin_unlock_irqrestore(&hp->port.lock, flags);
452 return;
453 }
454
455 hp->port.count = 0;
456 spin_unlock_irqrestore(&hp->port.lock, flags);
457 tty_port_tty_set(&hp->port, NULL);
458
459 hp->n_outbuf = 0;
460
461 if (hp->ops->notifier_hangup)
462 hp->ops->notifier_hangup(hp, hp->data);
463}
464
465
466
467
468
469static int hvc_push(struct hvc_struct *hp)
470{
471 int n;
472
473 n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
474 if (n <= 0) {
475 if (n == 0 || n == -EAGAIN) {
476 hp->do_wakeup = 1;
477 return 0;
478 }
479
480
481 hp->n_outbuf = 0;
482 } else
483 hp->n_outbuf -= n;
484 if (hp->n_outbuf > 0)
485 memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf);
486 else
487 hp->do_wakeup = 1;
488
489 return n;
490}
491
492static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
493{
494 struct hvc_struct *hp = tty->driver_data;
495 unsigned long flags;
496 int rsize, written = 0;
497
498
499 if (!hp)
500 return -EPIPE;
501
502
503 if (hp->port.count <= 0)
504 return -EIO;
505
506 spin_lock_irqsave(&hp->lock, flags);
507
508
509 if (hp->n_outbuf > 0)
510 hvc_push(hp);
511
512 while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) {
513 if (rsize > count)
514 rsize = count;
515 memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
516 count -= rsize;
517 buf += rsize;
518 hp->n_outbuf += rsize;
519 written += rsize;
520 hvc_push(hp);
521 }
522 spin_unlock_irqrestore(&hp->lock, flags);
523
524
525
526
527 if (hp->n_outbuf)
528 hvc_kick();
529
530 return written;
531}
532
533
534
535
536
537
538
539
540
541
542static void hvc_set_winsz(struct work_struct *work)
543{
544 struct hvc_struct *hp;
545 unsigned long hvc_flags;
546 struct tty_struct *tty;
547 struct winsize ws;
548
549 hp = container_of(work, struct hvc_struct, tty_resize);
550
551 tty = tty_port_tty_get(&hp->port);
552 if (!tty)
553 return;
554
555 spin_lock_irqsave(&hp->lock, hvc_flags);
556 ws = hp->ws;
557 spin_unlock_irqrestore(&hp->lock, hvc_flags);
558
559 tty_do_resize(tty, &ws);
560 tty_kref_put(tty);
561}
562
563
564
565
566
567
568static int hvc_write_room(struct tty_struct *tty)
569{
570 struct hvc_struct *hp = tty->driver_data;
571
572 if (!hp)
573 return 0;
574
575 return hp->outbuf_size - hp->n_outbuf;
576}
577
578static int hvc_chars_in_buffer(struct tty_struct *tty)
579{
580 struct hvc_struct *hp = tty->driver_data;
581
582 if (!hp)
583 return 0;
584 return hp->n_outbuf;
585}
586
587
588
589
590
591
592
593
594
595#define MIN_TIMEOUT (10)
596#define MAX_TIMEOUT (2000)
597static u32 timeout = MIN_TIMEOUT;
598
599#define HVC_POLL_READ 0x00000001
600#define HVC_POLL_WRITE 0x00000002
601
602int hvc_poll(struct hvc_struct *hp)
603{
604 struct tty_struct *tty;
605 int i, n, poll_mask = 0;
606 char buf[N_INBUF] __ALIGNED__;
607 unsigned long flags;
608 int read_total = 0;
609 int written_total = 0;
610
611 spin_lock_irqsave(&hp->lock, flags);
612
613
614 if (hp->n_outbuf > 0)
615 written_total = hvc_push(hp);
616
617
618 if (hp->n_outbuf > 0) {
619 poll_mask |= HVC_POLL_WRITE;
620
621 timeout = (written_total) ? 0 : MIN_TIMEOUT;
622 }
623
624
625 tty = tty_port_tty_get(&hp->port);
626 if (tty == NULL)
627 goto bail;
628
629
630 if (test_bit(TTY_THROTTLED, &tty->flags))
631 goto throttled;
632
633
634
635
636 if (!hp->irq_requested)
637 poll_mask |= HVC_POLL_READ;
638
639
640 for (;;) {
641 int count = tty_buffer_request_room(&hp->port, N_INBUF);
642
643
644 if (count == 0) {
645 poll_mask |= HVC_POLL_READ;
646 break;
647 }
648
649 n = hp->ops->get_chars(hp->vtermno, buf, count);
650 if (n <= 0) {
651
652 if (n == -EPIPE) {
653 spin_unlock_irqrestore(&hp->lock, flags);
654 tty_hangup(tty);
655 spin_lock_irqsave(&hp->lock, flags);
656 } else if ( n == -EAGAIN ) {
657
658
659
660
661
662 poll_mask |= HVC_POLL_READ;
663 }
664 break;
665 }
666 for (i = 0; i < n; ++i) {
667#ifdef CONFIG_MAGIC_SYSRQ
668 if (hp->index == hvc_console.index) {
669
670
671 if (buf[i] == '\x0f') {
672
673
674 sysrq_pressed = !sysrq_pressed;
675 if (sysrq_pressed)
676 continue;
677 } else if (sysrq_pressed) {
678 handle_sysrq(buf[i]);
679 sysrq_pressed = 0;
680 continue;
681 }
682 }
683#endif
684 tty_insert_flip_char(&hp->port, buf[i], 0);
685 }
686
687 read_total += n;
688 }
689 throttled:
690
691 if (hp->do_wakeup) {
692 hp->do_wakeup = 0;
693 tty_wakeup(tty);
694 }
695 bail:
696 spin_unlock_irqrestore(&hp->lock, flags);
697
698 if (read_total) {
699
700
701 timeout = MIN_TIMEOUT;
702
703 tty_flip_buffer_push(&hp->port);
704 }
705 tty_kref_put(tty);
706
707 return poll_mask;
708}
709EXPORT_SYMBOL_GPL(hvc_poll);
710
711
712
713
714
715
716
717
718
719
720
721void __hvc_resize(struct hvc_struct *hp, struct winsize ws)
722{
723 hp->ws = ws;
724 schedule_work(&hp->tty_resize);
725}
726EXPORT_SYMBOL_GPL(__hvc_resize);
727
728
729
730
731
732
733static int khvcd(void *unused)
734{
735 int poll_mask;
736 struct hvc_struct *hp;
737
738 set_freezable();
739 do {
740 poll_mask = 0;
741 hvc_kicked = 0;
742 try_to_freeze();
743 wmb();
744 if (!cpus_are_in_xmon()) {
745 spin_lock(&hvc_structs_lock);
746 list_for_each_entry(hp, &hvc_structs, next) {
747 poll_mask |= hvc_poll(hp);
748 }
749 spin_unlock(&hvc_structs_lock);
750 } else
751 poll_mask |= HVC_POLL_READ;
752 if (hvc_kicked)
753 continue;
754 set_current_state(TASK_INTERRUPTIBLE);
755 if (!hvc_kicked) {
756 if (poll_mask == 0)
757 schedule();
758 else {
759 if (timeout < MAX_TIMEOUT)
760 timeout += (timeout >> 6) + 1;
761
762 msleep_interruptible(timeout);
763 }
764 }
765 __set_current_state(TASK_RUNNING);
766 } while (!kthread_should_stop());
767
768 return 0;
769}
770
771static int hvc_tiocmget(struct tty_struct *tty)
772{
773 struct hvc_struct *hp = tty->driver_data;
774
775 if (!hp || !hp->ops->tiocmget)
776 return -EINVAL;
777 return hp->ops->tiocmget(hp);
778}
779
780static int hvc_tiocmset(struct tty_struct *tty,
781 unsigned int set, unsigned int clear)
782{
783 struct hvc_struct *hp = tty->driver_data;
784
785 if (!hp || !hp->ops->tiocmset)
786 return -EINVAL;
787 return hp->ops->tiocmset(hp, set, clear);
788}
789
790#ifdef CONFIG_CONSOLE_POLL
791int hvc_poll_init(struct tty_driver *driver, int line, char *options)
792{
793 return 0;
794}
795
796static int hvc_poll_get_char(struct tty_driver *driver, int line)
797{
798 struct tty_struct *tty = driver->ttys[0];
799 struct hvc_struct *hp = tty->driver_data;
800 int n;
801 char ch;
802
803 n = hp->ops->get_chars(hp->vtermno, &ch, 1);
804
805 if (n == 0)
806 return NO_POLL_CHAR;
807
808 return ch;
809}
810
811static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch)
812{
813 struct tty_struct *tty = driver->ttys[0];
814 struct hvc_struct *hp = tty->driver_data;
815 int n;
816
817 do {
818 n = hp->ops->put_chars(hp->vtermno, &ch, 1);
819 } while (n <= 0);
820}
821#endif
822
823static const struct tty_operations hvc_ops = {
824 .install = hvc_install,
825 .open = hvc_open,
826 .close = hvc_close,
827 .cleanup = hvc_cleanup,
828 .write = hvc_write,
829 .hangup = hvc_hangup,
830 .unthrottle = hvc_unthrottle,
831 .write_room = hvc_write_room,
832 .chars_in_buffer = hvc_chars_in_buffer,
833 .tiocmget = hvc_tiocmget,
834 .tiocmset = hvc_tiocmset,
835#ifdef CONFIG_CONSOLE_POLL
836 .poll_init = hvc_poll_init,
837 .poll_get_char = hvc_poll_get_char,
838 .poll_put_char = hvc_poll_put_char,
839#endif
840};
841
842static const struct tty_port_operations hvc_port_ops = {
843 .destruct = hvc_port_destruct,
844};
845
846struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
847 const struct hv_ops *ops,
848 int outbuf_size)
849{
850 struct hvc_struct *hp;
851 int i;
852
853
854 if (!hvc_driver) {
855 int err = hvc_init();
856 if (err)
857 return ERR_PTR(err);
858 }
859
860 hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
861 GFP_KERNEL);
862 if (!hp)
863 return ERR_PTR(-ENOMEM);
864
865 hp->vtermno = vtermno;
866 hp->data = data;
867 hp->ops = ops;
868 hp->outbuf_size = outbuf_size;
869 hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
870
871 tty_port_init(&hp->port);
872 hp->port.ops = &hvc_port_ops;
873
874 INIT_WORK(&hp->tty_resize, hvc_set_winsz);
875 spin_lock_init(&hp->lock);
876 spin_lock(&hvc_structs_lock);
877
878
879
880
881
882 for (i=0; i < MAX_NR_HVC_CONSOLES; i++)
883 if (vtermnos[i] == hp->vtermno &&
884 cons_ops[i] == hp->ops)
885 break;
886
887
888 if (i >= MAX_NR_HVC_CONSOLES)
889 i = ++last_hvc;
890
891 hp->index = i;
892 cons_ops[i] = ops;
893 vtermnos[i] = vtermno;
894
895 list_add_tail(&(hp->next), &hvc_structs);
896 spin_unlock(&hvc_structs_lock);
897
898
899 hvc_check_console(i);
900
901 return hp;
902}
903EXPORT_SYMBOL_GPL(hvc_alloc);
904
905int hvc_remove(struct hvc_struct *hp)
906{
907 unsigned long flags;
908 struct tty_struct *tty;
909
910 tty = tty_port_tty_get(&hp->port);
911
912 spin_lock_irqsave(&hp->lock, flags);
913 if (hp->index < MAX_NR_HVC_CONSOLES) {
914 console_lock();
915 vtermnos[hp->index] = -1;
916 cons_ops[hp->index] = NULL;
917 console_unlock();
918 }
919
920
921
922 spin_unlock_irqrestore(&hp->lock, flags);
923
924
925
926
927
928
929
930 tty_port_put(&hp->port);
931
932
933
934
935 if (tty) {
936 tty_vhangup(tty);
937 tty_kref_put(tty);
938 }
939 return 0;
940}
941EXPORT_SYMBOL_GPL(hvc_remove);
942
943
944static int hvc_init(void)
945{
946 struct tty_driver *drv;
947 int err;
948
949
950 drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);
951 if (!drv) {
952 err = -ENOMEM;
953 goto out;
954 }
955
956 drv->driver_name = "hvc";
957 drv->name = "hvc";
958 drv->major = HVC_MAJOR;
959 drv->minor_start = HVC_MINOR;
960 drv->type = TTY_DRIVER_TYPE_SYSTEM;
961 drv->init_termios = tty_std_termios;
962 drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
963 tty_set_operations(drv, &hvc_ops);
964
965
966
967 hvc_task = kthread_run(khvcd, NULL, "khvcd");
968 if (IS_ERR(hvc_task)) {
969 printk(KERN_ERR "Couldn't create kthread for console.\n");
970 err = PTR_ERR(hvc_task);
971 goto put_tty;
972 }
973
974 err = tty_register_driver(drv);
975 if (err) {
976 printk(KERN_ERR "Couldn't register hvc console driver\n");
977 goto stop_thread;
978 }
979
980
981
982
983
984 smp_mb();
985 hvc_driver = drv;
986 return 0;
987
988stop_thread:
989 kthread_stop(hvc_task);
990 hvc_task = NULL;
991put_tty:
992 put_tty_driver(drv);
993out:
994 return err;
995}
996
997
998
999
1000static void __exit hvc_exit(void)
1001{
1002 if (hvc_driver) {
1003 kthread_stop(hvc_task);
1004
1005 tty_unregister_driver(hvc_driver);
1006
1007 put_tty_driver(hvc_driver);
1008 unregister_console(&hvc_console);
1009 }
1010}
1011module_exit(hvc_exit);
1012