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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
#include <linux/version.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/major.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/hypervisor.h>
#include <asm-xen/evtchn.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/err.h>
#include "xencons_ring.h"
#include <asm-xen/xen-public/io/console.h>
static int xencons_irq;
static xencons_receiver_func *xencons_receiver;
static inline struct xencons_interface *xencons_interface(void)
{
return mfn_to_virt(xen_start_info->console_mfn);
}
int xencons_ring_send(const char *data, unsigned len)
{
int sent = 0;
struct xencons_interface *intf = xencons_interface();
XENCONS_RING_IDX cons, prod;
cons = intf->out_cons;
prod = intf->out_prod;
mb();
BUG_ON((prod - cons) > sizeof(intf->out));
while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
wmb();
intf->out_prod = prod;
/* Use evtchn: this is called early, before irq is set up. */
notify_remote_via_evtchn(xen_start_info->console_evtchn);
return sent;
}
static irqreturn_t handle_input(int irq, void *unused, struct pt_regs *regs)
{
struct xencons_interface *intf = xencons_interface();
XENCONS_RING_IDX cons, prod;
cons = intf->in_cons;
prod = intf->in_prod;
mb();
BUG_ON((prod - cons) > sizeof(intf->in));
while (cons != prod) {
if (xencons_receiver != NULL)
xencons_receiver(
intf->in + MASK_XENCONS_IDX(cons++, intf->in),
1, regs);
}
wmb();
intf->in_cons = cons;
return IRQ_HANDLED;
}
void xencons_ring_register_receiver(xencons_receiver_func *f)
{
xencons_receiver = f;
}
int xencons_ring_init(void)
{
int err;
if (xencons_irq)
unbind_from_irqhandler(xencons_irq, NULL);
xencons_irq = 0;
if (!xen_start_info->console_evtchn)
return 0;
err = bind_evtchn_to_irqhandler(
xen_start_info->console_evtchn,
handle_input, 0, "xencons", NULL);
if (err <= 0) {
xprintk("XEN console request irq failed %i\n", err);
return err;
}
xencons_irq = err;
return 0;
}
void xencons_resume(void)
{
(void)xencons_ring_init();
}
/*
* Local variables:
* c-file-style: "linux"
* indent-tabs-mode: t
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/
|