Subversion Repositories HelenOS

Rev

Rev 3863 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3743 rimsky 1
/*
2
 * Copyright (c) 2008 Pavel Rimsky
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
 
29
/** @addtogroup sparc64
30
 * @{
31
 */
32
/**
33
 * @file
34
 * @brief   Niagara input/output driver based on hypervisor calls.
35
 */
36
 
37
#include <arch/drivers/niagara.h>
38
#include <console/chardev.h>
39
#include <console/console.h>
4073 rimsky 40
#include <ddi/ddi.h>
41
#include <ddi/device.h>
42
#include <arch/asm.h>
3817 rimsky 43
#include <arch/drivers/kbd.h>
3743 rimsky 44
#include <arch/sun4v/hypercall.h>
4073 rimsky 45
#include <sysinfo/sysinfo.h>
46
#include <ipc/irq.h>
3743 rimsky 47
 
4073 rimsky 48
/**
49
 * The driver is polling based, but in order to notify the userspace
50
 * of a key being pressed, we need to supply the interface with some
51
 * interrupt number. The interrupt number can be arbitrary as it it
52
 * will never be used for identifying HW interrupts, but only in
53
 * notifying the userspace.
54
 */
55
#define FICTIONAL_INR       1
56
 
3743 rimsky 57
/* functions referenced from definitions of I/O operations structures */
58
static void niagara_putchar(chardev_t *, const char);
3817 rimsky 59
static void niagara_noop(chardev_t *);
60
static char niagara_read(chardev_t *);
3743 rimsky 61
 
62
/** character device operations */
63
static chardev_operations_t niagara_ops = {
3817 rimsky 64
    .write = niagara_putchar,
65
    .suspend = niagara_noop,
66
    .resume = niagara_noop,
67
    .read = niagara_read
3743 rimsky 68
};
69
 
4073 rimsky 70
/*
71
 * The driver uses hypercalls to print characters to the console. Since the
72
 * hypercall cannot be performed from the userspace, we do this:
73
 * The kernel "little brother" driver (which will be present no matter what the
74
 * DDI architecture is - as we need the kernel part for the kconsole)
75
 * defines a shared buffer. Kernel walks through the buffer (in the same thread
76
 * which is used for polling the keyboard) and prints any pending characters
77
 * to the console (using hypercalls). The userspace fb server maps this shared
78
 * buffer to its address space and output operation it does is performed using
79
 * the mapped buffer. The shared buffer definition follows.
80
 */
81
#define OUTPUT_BUFFER_SIZE  ((PAGE_SIZE) - 2 * 8)
82
static volatile struct {
83
    uint64_t read_ptr;
84
    uint64_t write_ptr;
85
    char data[OUTPUT_BUFFER_SIZE];
86
}
87
    __attribute__ ((packed))
88
    __attribute__ ((aligned(PAGE_SIZE)))
89
    output_buffer;
90
 
3743 rimsky 91
/** Niagara character device */
92
chardev_t niagara_io;
93
 
4073 rimsky 94
/**
95
 * Niagara IRQ structure. So far used only for notifying the userspace of the
96
 * key being pressed, not for kernel being informed about keyboard interrupts.
97
 */
98
static irq_t niagara_irq;
99
 
3817 rimsky 100
/** defined in drivers/kbd.c */
101
extern kbd_type_t kbd_type;
102
 
4073 rimsky 103
/**
104
 * The character read will be stored here until the (notified) uspace
105
 * driver picks it up.
106
 */
107
static char read_char;
108
 
109
/**
110
 * The driver works in polled mode, so no interrupt should be handled by it.
111
 */
112
static irq_ownership_t niagara_claim(void)
113
{
114
    return IRQ_DECLINE;
115
}
116
 
117
/**
118
 * The driver works in polled mode, so no interrupt should be handled by it.
119
 */
120
static void niagara_irq_handler(irq_t *irq, void *arg, ...)
121
{
122
    panic("Not yet implemented, SGCN works in polled mode.\n");
123
}
124
 
3743 rimsky 125
/** Writes a single character to the standard output. */
3863 rimsky 126
static inline void do_putchar(const char c) {
127
    /* repeat until the buffer is non-full */
128
    while (__hypercall_fast1(CONS_PUTCHAR, c) == EWOULDBLOCK)
129
        ;
130
}
131
 
132
/** Writes a single character to the standard output. */
3743 rimsky 133
static void niagara_putchar(struct chardev * cd, const char c)
134
{
3863 rimsky 135
    do_putchar(c);
3743 rimsky 136
    if (c == '\n')
3863 rimsky 137
        do_putchar('\r');
3743 rimsky 138
}
139
 
140
/**
141
 * Grabs the input for kernel.
142
 */
143
void niagara_grab(void)
144
{
4073 rimsky 145
    ipl_t ipl = interrupts_disable();
146
    spinlock_lock(&niagara_irq.lock);
147
    niagara_irq.notif_cfg.notify = false;
148
    spinlock_unlock(&niagara_irq.lock);
149
    interrupts_restore(ipl);
3743 rimsky 150
}
151
 
152
/**
153
 * Releases the input so that userspace can use it.
154
 */
155
void niagara_release(void)
156
{
4073 rimsky 157
    ipl_t ipl = interrupts_disable();
158
    spinlock_lock(&niagara_irq.lock);
159
    if (niagara_irq.notif_cfg.answerbox)
160
        niagara_irq.notif_cfg.notify = true;
161
    spinlock_unlock(&niagara_irq.lock);
162
    interrupts_restore(ipl);
3743 rimsky 163
}
164
 
165
/**
3817 rimsky 166
 * Default suspend/resume operation for the input device.
167
 */
168
static void niagara_noop(chardev_t *d)
169
{
170
}
171
 
172
/**
4073 rimsky 173
 * Called when actively reading the character.
3817 rimsky 174
 */
175
static char niagara_read(chardev_t *d)
176
{
4073 rimsky 177
    uint64_t c;
178
 
179
    if (__hypercall_fast_ret1(0, 0, 0, 0, 0, CONS_GETCHAR, &c) == EOK) {
180
        return (char) c;
181
    }
182
 
183
    return '\0';
3817 rimsky 184
}
185
 
186
/**
4073 rimsky 187
 * Returns the character last read. This function is called from the
188
 * pseudocode - the character returned by this function is passed to
189
 * the userspace keyboard driver.
190
 */
191
char niagara_getc(void) {
192
    return read_char;
193
}
194
 
195
/**
3817 rimsky 196
 * Function regularly called by the keyboard polling thread. Asks the
197
 * hypervisor whether there is any unread character. If so, it picks it up
198
 * and sends it to the upper layers of HelenOS.
199
 */
200
void niagara_poll(void)
201
{
4073 rimsky 202
    while (output_buffer.read_ptr != output_buffer.write_ptr) {
203
        do_putchar(output_buffer.data[output_buffer.read_ptr]);
204
        output_buffer.read_ptr =
205
            ((output_buffer.read_ptr) + 1) % OUTPUT_BUFFER_SIZE;
206
    }
3817 rimsky 207
 
4073 rimsky 208
    uint64_t c;
209
 
3817 rimsky 210
    if (__hypercall_fast_ret1(0, 0, 0, 0, 0, CONS_GETCHAR, &c) == EOK) {
4073 rimsky 211
        ipl_t ipl = interrupts_disable();
212
        spinlock_lock(&niagara_irq.lock);
213
 
214
        if (niagara_irq.notif_cfg.notify &&
215
                niagara_irq.notif_cfg.answerbox) {
216
            /*
217
             * remember the character, uspace will pick it
218
             * up using pseudocode
219
             */
220
            read_char = (char) c;
221
            ipc_irq_send_notif(&niagara_irq);
222
            spinlock_unlock(&niagara_irq.lock);
223
            interrupts_restore(ipl);
224
            return;
225
        } else {
226
            spinlock_unlock(&niagara_irq.lock);
227
            interrupts_restore(ipl);   
228
 
229
            chardev_push_character(&niagara_io, c);
230
            if (c == '\r')
231
                chardev_push_character(&niagara_io, '\n');
232
        }
3817 rimsky 233
    }
234
 
235
}
236
 
237
/**
3743 rimsky 238
 * Initializes the input/output subsystem so that the Niagara standard
239
 * input/output is used.
240
 */
241
void niagara_init(void)
242
{
3817 rimsky 243
    kbd_type = KBD_SUN4V;
244
 
4073 rimsky 245
    devno_t devno = device_assign_devno();
246
    irq_initialize(&niagara_irq);
247
    niagara_irq.devno = devno;
248
    niagara_irq.inr = FICTIONAL_INR;
249
    niagara_irq.claim = niagara_claim;
250
    niagara_irq.handler = niagara_irq_handler;
251
    irq_register(&niagara_irq);
252
 
253
    sysinfo_set_item_val("kbd", NULL, true);
254
    sysinfo_set_item_val("kbd.type", NULL, KBD_SUN4V);
255
    sysinfo_set_item_val("kbd.devno", NULL, devno);
256
    sysinfo_set_item_val("kbd.inr", NULL, FICTIONAL_INR);
257
    sysinfo_set_item_val("fb.kind", NULL, 5);
258
 
259
    /*
260
     * Set sysinfos and pareas so that the userspace counterpart of the
261
     * niagara fb driver can communicate with kernel using a shared buffer.
262
     */
263
    output_buffer.read_ptr = 0;
264
    output_buffer.write_ptr = 0;
265
    sysinfo_set_item_val("niagara.outbuf.address", NULL,
266
        KA2PA(&output_buffer));
267
    sysinfo_set_item_val("niagara.outbuf.size", NULL,
268
        PAGE_SIZE);
269
    sysinfo_set_item_val("niagara.outbuf.datasize", NULL,
270
        OUTPUT_BUFFER_SIZE);
271
    static parea_t outbuf_parea;
272
    outbuf_parea.pbase = (uintptr_t) (KA2PA(&output_buffer));
273
    outbuf_parea.vbase = (uintptr_t) (&output_buffer);
274
    outbuf_parea.frames = 1;
275
    outbuf_parea.cacheable = false;
276
    ddi_parea_register(&outbuf_parea);
277
 
3743 rimsky 278
    chardev_initialize("niagara_io", &niagara_io, &niagara_ops);
279
    stdin = &niagara_io;
280
    stdout = &niagara_io;
281
}
282
 
283
/** @}
284
 */