Subversion Repositories HelenOS

Rev

Rev 3961 | Rev 4070 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3961 Rev 4011
1
/*
1
/*
2
 * Copyright (c) 2008 Pavel Rimsky
2
 * Copyright (c) 2008 Pavel Rimsky
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup sparc64
29
/** @addtogroup sparc64
30
 * @{
30
 * @{
31
 */
31
 */
32
/**
32
/**
33
 * @file
33
 * @file
34
 * @brief   SGCN driver.
34
 * @brief   SGCN driver.
35
 */
35
 */
36
 
36
 
37
#include <arch/drivers/sgcn.h>
37
#include <arch/drivers/sgcn.h>
38
#include <arch/drivers/kbd.h>
38
#include <arch/drivers/kbd.h>
39
#include <genarch/ofw/ofw_tree.h>
39
#include <genarch/ofw/ofw_tree.h>
40
#include <debug.h>
40
#include <debug.h>
41
#include <func.h>
41
#include <string.h>
42
#include <print.h>
42
#include <print.h>
43
#include <mm/page.h>
43
#include <mm/page.h>
44
#include <ipc/irq.h>
44
#include <ipc/irq.h>
45
#include <ddi/ddi.h>
45
#include <ddi/ddi.h>
46
#include <ddi/device.h>
46
#include <ddi/device.h>
47
#include <console/chardev.h>
47
#include <console/chardev.h>
48
#include <console/console.h>
48
#include <console/console.h>
49
#include <ddi/device.h>
49
#include <ddi/device.h>
50
#include <sysinfo/sysinfo.h>
50
#include <sysinfo/sysinfo.h>
51
#include <synch/spinlock.h>
51
#include <synch/spinlock.h>
52
 
52
 
53
/*
53
/*
54
 * Physical address at which the SBBC starts. This value has been obtained
54
 * Physical address at which the SBBC starts. This value has been obtained
55
 * by inspecting (using Simics) memory accesses made by OBP. It is valid
55
 * by inspecting (using Simics) memory accesses made by OBP. It is valid
56
 * for the Simics-simulated Serengeti machine. The author of this code is
56
 * for the Simics-simulated Serengeti machine. The author of this code is
57
 * not sure whether this value is valid generally.
57
 * not sure whether this value is valid generally.
58
 */
58
 */
59
#define SBBC_START      0x63000000000
59
#define SBBC_START      0x63000000000
60
 
60
 
61
/* offset of SRAM within the SBBC memory */
61
/* offset of SRAM within the SBBC memory */
62
#define SBBC_SRAM_OFFSET    0x900000
62
#define SBBC_SRAM_OFFSET    0x900000
63
 
63
 
64
/* size (in bytes) of the physical memory area which will be mapped */
64
/* size (in bytes) of the physical memory area which will be mapped */
65
#define MAPPED_AREA_SIZE    (128 * 1024)
65
#define MAPPED_AREA_SIZE    (128 * 1024)
66
 
66
 
67
/* magic string contained at the beginning of SRAM */
67
/* magic string contained at the beginning of SRAM */
68
#define SRAM_TOC_MAGIC      "TOCSRAM"
68
#define SRAM_TOC_MAGIC      "TOCSRAM"
69
 
69
 
70
/*
70
/*
71
 * Key into the SRAM table of contents which identifies the entry
71
 * Key into the SRAM table of contents which identifies the entry
72
 * describing the OBP console buffer. It is worth mentioning
72
 * describing the OBP console buffer. It is worth mentioning
73
 * that the OBP console buffer is not the only console buffer
73
 * that the OBP console buffer is not the only console buffer
74
 * which can be used. It is, however, used because when the kernel
74
 * which can be used. It is, however, used because when the kernel
75
 * is running, the OBP buffer is not used by OBP any more but OBP
75
 * is running, the OBP buffer is not used by OBP any more but OBP
76
 * has already made neccessary arangements so that the output will
76
 * has already made neccessary arangements so that the output will
77
 * be read from the OBP buffer and input will go to the OBP buffer.
77
 * be read from the OBP buffer and input will go to the OBP buffer.
78
 * Therefore HelenOS needs to make no such arrangements any more.
78
 * Therefore HelenOS needs to make no such arrangements any more.
79
 */
79
 */
80
#define CONSOLE_KEY     "OBPCONS"
80
#define CONSOLE_KEY     "OBPCONS"
81
 
81
 
82
/* magic string contained at the beginning of the console buffer */
82
/* magic string contained at the beginning of the console buffer */
83
#define SGCN_BUFFER_MAGIC   "CON"
83
#define SGCN_BUFFER_MAGIC   "CON"
84
 
84
 
85
/**
85
/**
86
 * The driver is polling based, but in order to notify the userspace
86
 * The driver is polling based, but in order to notify the userspace
87
 * of a key being pressed, we need to supply the interface with some
87
 * of a key being pressed, we need to supply the interface with some
88
 * interrupt number. The interrupt number can be arbitrary as it it
88
 * interrupt number. The interrupt number can be arbitrary as it it
89
 * will never be used for identifying HW interrupts, but only in
89
 * will never be used for identifying HW interrupts, but only in
90
 * notifying the userspace.
90
 * notifying the userspace.
91
 */
91
 */
92
#define FICTIONAL_INR       1
92
#define FICTIONAL_INR       1
93
 
93
 
94
 
94
 
95
/*
95
/*
96
 * Returns a pointer to the object of a given type which is placed at the given
96
 * Returns a pointer to the object of a given type which is placed at the given
97
 * offset from the SRAM beginning.
97
 * offset from the SRAM beginning.
98
 */
98
 */
99
#define SRAM(type, offset)  ((type *) (sram_begin + (offset)))
99
#define SRAM(type, offset)  ((type *) (sram_begin + (offset)))
100
 
100
 
101
/* Returns a pointer to the SRAM table of contents. */
101
/* Returns a pointer to the SRAM table of contents. */
102
#define SRAM_TOC        (SRAM(iosram_toc_t, 0))
102
#define SRAM_TOC        (SRAM(iosram_toc_t, 0))
103
 
103
 
104
/*
104
/*
105
 * Returns a pointer to the object of a given type which is placed at the given
105
 * Returns a pointer to the object of a given type which is placed at the given
106
 * offset from the console buffer beginning.
106
 * offset from the console buffer beginning.
107
 */
107
 */
108
#define SGCN_BUFFER(type, offset) \
108
#define SGCN_BUFFER(type, offset) \
109
                ((type *) (sgcn_buffer_begin + (offset)))
109
                ((type *) (sgcn_buffer_begin + (offset)))
110
 
110
 
111
/** Returns a pointer to the console buffer header. */
111
/** Returns a pointer to the console buffer header. */
112
#define SGCN_BUFFER_HEADER  (SGCN_BUFFER(sgcn_buffer_header_t, 0))
112
#define SGCN_BUFFER_HEADER  (SGCN_BUFFER(sgcn_buffer_header_t, 0))
113
 
113
 
114
/** defined in drivers/kbd.c */
114
/** defined in drivers/kbd.c */
115
extern kbd_type_t kbd_type;
115
extern kbd_type_t kbd_type;
116
 
116
 
117
/** starting address of SRAM, will be set by the init_sram_begin function */
117
/** starting address of SRAM, will be set by the init_sram_begin function */
118
static uintptr_t sram_begin;
118
static uintptr_t sram_begin;
119
 
119
 
120
/**
120
/**
121
 * starting address of the SGCN buffer, will be set by the
121
 * starting address of the SGCN buffer, will be set by the
122
 * init_sgcn_buffer_begin function
122
 * init_sgcn_buffer_begin function
123
 */
123
 */
124
static uintptr_t sgcn_buffer_begin;
124
static uintptr_t sgcn_buffer_begin;
125
 
125
 
126
/**
126
/**
127
 * SGCN IRQ structure. So far used only for notifying the userspace of the
127
 * SGCN IRQ structure. So far used only for notifying the userspace of the
128
 * key being pressed, not for kernel being informed about keyboard interrupts.
128
 * key being pressed, not for kernel being informed about keyboard interrupts.
129
 */
129
 */
130
static irq_t sgcn_irq;
130
static irq_t sgcn_irq;
131
 
131
 
132
// TODO think of a way how to synchronize accesses to SGCN buffer between the kernel and the userspace
132
// TODO think of a way how to synchronize accesses to SGCN buffer between the kernel and the userspace
133
 
133
 
134
/*
134
/*
135
 * Ensures that writing to the buffer and consequent update of the write pointer
135
 * Ensures that writing to the buffer and consequent update of the write pointer
136
 * are together one atomic operation.
136
 * are together one atomic operation.
137
 */
137
 */
138
SPINLOCK_INITIALIZE(sgcn_output_lock);
138
SPINLOCK_INITIALIZE(sgcn_output_lock);
139
 
139
 
140
/*
140
/*
141
 * Prevents the input buffer read/write pointers from getting to inconsistent
141
 * Prevents the input buffer read/write pointers from getting to inconsistent
142
 * state.
142
 * state.
143
 */
143
 */
144
SPINLOCK_INITIALIZE(sgcn_input_lock);
144
SPINLOCK_INITIALIZE(sgcn_input_lock);
145
 
145
 
146
 
146
 
147
/* functions referenced from definitions of I/O operations structures */
147
/* functions referenced from definitions of I/O operations structures */
148
static void sgcn_noop(chardev_t *);
148
static void sgcn_noop(chardev_t *);
149
static void sgcn_putchar(chardev_t *, const char, bool);
149
static void sgcn_putchar(chardev_t *, const char, bool);
150
static char sgcn_key_read(chardev_t *);
150
static char sgcn_key_read(chardev_t *);
151
 
151
 
152
/** character device operations */
152
/** character device operations */
153
static chardev_operations_t sgcn_ops = {
153
static chardev_operations_t sgcn_ops = {
154
    .suspend = sgcn_noop,
154
    .suspend = sgcn_noop,
155
    .resume = sgcn_noop,
155
    .resume = sgcn_noop,
156
    .read = sgcn_key_read,
156
    .read = sgcn_key_read,
157
    .write = sgcn_putchar
157
    .write = sgcn_putchar
158
};
158
};
159
 
159
 
160
/** SGCN character device */
160
/** SGCN character device */
161
chardev_t sgcn_io;
161
chardev_t sgcn_io;
162
 
162
 
163
/**
163
/**
164
 * Set some sysinfo values (SRAM address and SRAM size).
164
 * Set some sysinfo values (SRAM address and SRAM size).
165
 */
165
 */
166
static void register_sram(uintptr_t sram_begin_physical)
166
static void register_sram(uintptr_t sram_begin_physical)
167
{
167
{
168
    sysinfo_set_item_val("sram.area.size", NULL, MAPPED_AREA_SIZE);
168
    sysinfo_set_item_val("sram.area.size", NULL, MAPPED_AREA_SIZE);
169
    sysinfo_set_item_val("sram.address.physical", NULL,
169
    sysinfo_set_item_val("sram.address.physical", NULL,
170
        sram_begin_physical);
170
        sram_begin_physical);
171
}
171
}
172
 
172
 
173
/**
173
/**
174
 * Initializes the starting address of SRAM.
174
 * Initializes the starting address of SRAM.
175
 *
175
 *
176
 * The SRAM starts 0x900000 + C bytes behind the SBBC start in the
176
 * The SRAM starts 0x900000 + C bytes behind the SBBC start in the
177
 * physical memory, where C is the value read from the "iosram-toc"
177
 * physical memory, where C is the value read from the "iosram-toc"
178
 * property of the "/chosen" OBP node. The sram_begin variable will
178
 * property of the "/chosen" OBP node. The sram_begin variable will
179
 * be set to the virtual address which maps to the SRAM physical
179
 * be set to the virtual address which maps to the SRAM physical
180
 * address.
180
 * address.
181
 *
181
 *
182
 * It also registers the physical area of SRAM and sets some sysinfo
182
 * It also registers the physical area of SRAM and sets some sysinfo
183
 * values (SRAM address and SRAM size).
183
 * values (SRAM address and SRAM size).
184
 */
184
 */
185
static void init_sram_begin(void)
185
static void init_sram_begin(void)
186
{
186
{
187
    ofw_tree_node_t *chosen;
187
    ofw_tree_node_t *chosen;
188
    ofw_tree_property_t *iosram_toc;
188
    ofw_tree_property_t *iosram_toc;
189
    uintptr_t sram_begin_physical;
189
    uintptr_t sram_begin_physical;
190
 
190
 
191
    chosen = ofw_tree_lookup("/chosen");
191
    chosen = ofw_tree_lookup("/chosen");
192
    if (!chosen)
192
    if (!chosen)
193
        panic("Cannot find '/chosen'.");
193
        panic("Cannot find '/chosen'.");
194
 
194
 
195
    iosram_toc = ofw_tree_getprop(chosen, "iosram-toc");
195
    iosram_toc = ofw_tree_getprop(chosen, "iosram-toc");
196
    if (!iosram_toc)
196
    if (!iosram_toc)
197
        panic("Cannot find property 'iosram-toc'.");
197
        panic("Cannot find property 'iosram-toc'.");
198
    if (!iosram_toc->value)
198
    if (!iosram_toc->value)
199
        panic("Cannot find SRAM TOC.");
199
        panic("Cannot find SRAM TOC.");
200
 
200
 
201
    sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
201
    sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
202
        + *((uint32_t *) iosram_toc->value);
202
        + *((uint32_t *) iosram_toc->value);
203
    sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
203
    sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
204
   
204
   
205
    register_sram(sram_begin_physical);
205
    register_sram(sram_begin_physical);
206
}
206
}
207
 
207
 
208
/**
208
/**
209
 * Initializes the starting address of the SGCN buffer.
209
 * Initializes the starting address of the SGCN buffer.
210
 *
210
 *
211
 * The offset of the SGCN buffer within SRAM is obtained from the
211
 * The offset of the SGCN buffer within SRAM is obtained from the
212
 * SRAM table of contents. The table of contents contains
212
 * SRAM table of contents. The table of contents contains
213
 * information about several buffers, among which there is an OBP
213
 * information about several buffers, among which there is an OBP
214
 * console buffer - this one will be used as the SGCN buffer.
214
 * console buffer - this one will be used as the SGCN buffer.
215
 *
215
 *
216
 * This function also writes the offset of the SGCN buffer within SRAM
216
 * This function also writes the offset of the SGCN buffer within SRAM
217
 * under the sram.buffer.offset sysinfo key.
217
 * under the sram.buffer.offset sysinfo key.
218
 */
218
 */
219
static void sgcn_buffer_begin_init(void)
219
static void sgcn_buffer_begin_init(void)
220
{
220
{
221
    init_sram_begin();
221
    init_sram_begin();
222
       
222
       
223
    ASSERT(strcmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
223
    ASSERT(strcmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
224
   
224
   
225
    /* lookup TOC entry with the correct key */
225
    /* lookup TOC entry with the correct key */
226
    uint32_t i;
226
    uint32_t i;
227
    for (i = 0; i < MAX_TOC_ENTRIES; i++) {
227
    for (i = 0; i < MAX_TOC_ENTRIES; i++) {
228
        if (strcmp(SRAM_TOC->keys[i].key, CONSOLE_KEY) == 0)
228
        if (strcmp(SRAM_TOC->keys[i].key, CONSOLE_KEY) == 0)
229
            break;
229
            break;
230
    }
230
    }
231
    ASSERT(i < MAX_TOC_ENTRIES);
231
    ASSERT(i < MAX_TOC_ENTRIES);
232
   
232
   
233
    sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
233
    sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
234
   
234
   
235
    sysinfo_set_item_val("sram.buffer.offset", NULL,
235
    sysinfo_set_item_val("sram.buffer.offset", NULL,
236
        SRAM_TOC->keys[i].offset);
236
        SRAM_TOC->keys[i].offset);
237
}
237
}
238
 
238
 
239
/**
239
/**
240
 * Default suspend/resume operation for the input device.
240
 * Default suspend/resume operation for the input device.
241
 */
241
 */
242
static void sgcn_noop(chardev_t *d)
242
static void sgcn_noop(chardev_t *d)
243
{
243
{
244
}
244
}
245
 
245
 
246
/**
246
/**
247
 * Writes a single character to the SGCN (circular) output buffer
247
 * Writes a single character to the SGCN (circular) output buffer
248
 * and updates the output write pointer so that SGCN gets to know
248
 * and updates the output write pointer so that SGCN gets to know
249
 * that the character has been written.
249
 * that the character has been written.
250
 */
250
 */
251
static void sgcn_do_putchar(const char c)
251
static void sgcn_do_putchar(const char c)
252
{
252
{
253
    uint32_t begin = SGCN_BUFFER_HEADER->out_begin;
253
    uint32_t begin = SGCN_BUFFER_HEADER->out_begin;
254
    uint32_t end = SGCN_BUFFER_HEADER->out_end;
254
    uint32_t end = SGCN_BUFFER_HEADER->out_end;
255
    uint32_t size = end - begin;
255
    uint32_t size = end - begin;
256
   
256
   
257
    /* we need pointers to volatile variables */
257
    /* we need pointers to volatile variables */
258
    volatile char *buf_ptr = (volatile char *)
258
    volatile char *buf_ptr = (volatile char *)
259
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
259
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
260
    volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
260
    volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
261
    volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
261
    volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
262
 
262
 
263
    /*
263
    /*
264
     * Write the character and increment the write pointer modulo the
264
     * Write the character and increment the write pointer modulo the
265
     * output buffer size. Note that if we are to rewrite a character
265
     * output buffer size. Note that if we are to rewrite a character
266
     * which has not been read by the SGCN controller yet (i.e. the output
266
     * which has not been read by the SGCN controller yet (i.e. the output
267
     * buffer is full), we need to wait until the controller reads some more
267
     * buffer is full), we need to wait until the controller reads some more
268
     * characters. We wait actively, which means that all threads waiting
268
     * characters. We wait actively, which means that all threads waiting
269
     * for the lock are blocked. However, this situation is
269
     * for the lock are blocked. However, this situation is
270
     *   1) rare - the output buffer is big, so filling the whole
270
     *   1) rare - the output buffer is big, so filling the whole
271
     *             output buffer is improbable
271
     *             output buffer is improbable
272
     *   2) short-lasting - it will take the controller only a fraction
272
     *   2) short-lasting - it will take the controller only a fraction
273
     *             of millisecond to pick the unread characters up
273
     *             of millisecond to pick the unread characters up
274
     *   3) not serious - the blocked threads are those that print something
274
     *   3) not serious - the blocked threads are those that print something
275
     *             to user console, which is not a time-critical operation
275
     *             to user console, which is not a time-critical operation
276
     */
276
     */
277
    uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
277
    uint32_t new_wrptr = (((*out_wrptr_ptr) - begin + 1) % size) + begin;
278
    while (*out_rdptr_ptr == new_wrptr)
278
    while (*out_rdptr_ptr == new_wrptr)
279
        ;
279
        ;
280
    *buf_ptr = c;
280
    *buf_ptr = c;
281
    *out_wrptr_ptr = new_wrptr;
281
    *out_wrptr_ptr = new_wrptr;
282
}
282
}
283
 
283
 
284
/**
284
/**
285
 * SGCN output operation. Prints a single character to the SGCN. If the line
285
 * SGCN output operation. Prints a single character to the SGCN. If the line
286
 * feed character is written ('\n'), the carriage return character ('\r') is
286
 * feed character is written ('\n'), the carriage return character ('\r') is
287
 * written straight away.
287
 * written straight away.
288
 */
288
 */
289
static void sgcn_putchar(struct chardev * cd, const char c, bool silent)
289
static void sgcn_putchar(struct chardev * cd, const char c, bool silent)
290
{
290
{
291
    if (!silent) {
291
    if (!silent) {
292
        spinlock_lock(&sgcn_output_lock);
292
        spinlock_lock(&sgcn_output_lock);
293
       
293
       
294
        sgcn_do_putchar(c);
294
        sgcn_do_putchar(c);
295
        if (c == '\n')
295
        if (c == '\n')
296
            sgcn_do_putchar('\r');
296
            sgcn_do_putchar('\r');
297
       
297
       
298
        spinlock_unlock(&sgcn_output_lock);
298
        spinlock_unlock(&sgcn_output_lock);
299
    }
299
    }
300
}
300
}
301
 
301
 
302
/**
302
/**
303
 * Called when actively reading the character. Not implemented yet.
303
 * Called when actively reading the character. Not implemented yet.
304
 */
304
 */
305
static char sgcn_key_read(chardev_t *d)
305
static char sgcn_key_read(chardev_t *d)
306
{
306
{
307
    return (char) 0;
307
    return (char) 0;
308
}
308
}
309
 
309
 
310
/**
310
/**
311
 * The driver works in polled mode, so no interrupt should be handled by it.
311
 * The driver works in polled mode, so no interrupt should be handled by it.
312
 */
312
 */
313
static irq_ownership_t sgcn_claim(irq_t *irq)
313
static irq_ownership_t sgcn_claim(irq_t *irq)
314
{
314
{
315
    return IRQ_DECLINE;
315
    return IRQ_DECLINE;
316
}
316
}
317
 
317
 
318
/**
318
/**
319
 * The driver works in polled mode, so no interrupt should be handled by it.
319
 * The driver works in polled mode, so no interrupt should be handled by it.
320
 */
320
 */
321
static void sgcn_irq_handler(irq_t *irq)
321
static void sgcn_irq_handler(irq_t *irq)
322
{
322
{
323
    panic("Not yet implemented, SGCN works in polled mode.");
323
    panic("Not yet implemented, SGCN works in polled mode.");
324
}
324
}
325
 
325
 
326
/**
326
/**
327
 * Grabs the input for kernel.
327
 * Grabs the input for kernel.
328
 */
328
 */
329
void sgcn_grab(void)
329
void sgcn_grab(void)
330
{
330
{
331
    ipl_t ipl = interrupts_disable();
331
    ipl_t ipl = interrupts_disable();
332
   
332
   
333
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
333
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
334
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
334
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
335
   
335
   
336
    /* skip all the user typed before the grab and hasn't been processed */
336
    /* skip all the user typed before the grab and hasn't been processed */
337
    spinlock_lock(&sgcn_input_lock);
337
    spinlock_lock(&sgcn_input_lock);
338
    *in_rdptr_ptr = *in_wrptr_ptr;
338
    *in_rdptr_ptr = *in_wrptr_ptr;
339
    spinlock_unlock(&sgcn_input_lock);
339
    spinlock_unlock(&sgcn_input_lock);
340
 
340
 
341
    spinlock_lock(&sgcn_irq.lock);
341
    spinlock_lock(&sgcn_irq.lock);
342
    sgcn_irq.notif_cfg.notify = false;
342
    sgcn_irq.notif_cfg.notify = false;
343
    spinlock_unlock(&sgcn_irq.lock);
343
    spinlock_unlock(&sgcn_irq.lock);
344
   
344
   
345
    interrupts_restore(ipl);
345
    interrupts_restore(ipl);
346
}
346
}
347
 
347
 
348
/**
348
/**
349
 * Releases the input so that userspace can use it.
349
 * Releases the input so that userspace can use it.
350
 */
350
 */
351
void sgcn_release(void)
351
void sgcn_release(void)
352
{
352
{
353
    ipl_t ipl = interrupts_disable();
353
    ipl_t ipl = interrupts_disable();
354
    spinlock_lock(&sgcn_irq.lock);
354
    spinlock_lock(&sgcn_irq.lock);
355
    if (sgcn_irq.notif_cfg.answerbox)
355
    if (sgcn_irq.notif_cfg.answerbox)
356
        sgcn_irq.notif_cfg.notify = true;
356
        sgcn_irq.notif_cfg.notify = true;
357
    spinlock_unlock(&sgcn_irq.lock);
357
    spinlock_unlock(&sgcn_irq.lock);
358
    interrupts_restore(ipl);
358
    interrupts_restore(ipl);
359
}
359
}
360
 
360
 
361
/**
361
/**
362
 * Function regularly called by the keyboard polling thread. Finds out whether
362
 * Function regularly called by the keyboard polling thread. Finds out whether
363
 * there are some unread characters in the input queue. If so, it picks them up
363
 * there are some unread characters in the input queue. If so, it picks them up
364
 * and sends them to the upper layers of HelenOS.
364
 * and sends them to the upper layers of HelenOS.
365
 */
365
 */
366
void sgcn_poll(void)
366
void sgcn_poll(void)
367
{
367
{
368
    uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
368
    uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
369
    uint32_t end = SGCN_BUFFER_HEADER->in_end;
369
    uint32_t end = SGCN_BUFFER_HEADER->in_end;
370
    uint32_t size = end - begin;
370
    uint32_t size = end - begin;
371
   
371
   
372
    spinlock_lock(&sgcn_input_lock);
372
    spinlock_lock(&sgcn_input_lock);
373
   
373
   
374
    ipl_t ipl = interrupts_disable();
374
    ipl_t ipl = interrupts_disable();
375
    spinlock_lock(&sgcn_irq.lock);
375
    spinlock_lock(&sgcn_irq.lock);
376
   
376
   
377
    /* we need pointers to volatile variables */
377
    /* we need pointers to volatile variables */
378
    volatile char *buf_ptr = (volatile char *)
378
    volatile char *buf_ptr = (volatile char *)
379
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
379
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
380
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
380
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
381
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
381
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
382
   
382
   
383
    if (*in_rdptr_ptr != *in_wrptr_ptr) {
383
    if (*in_rdptr_ptr != *in_wrptr_ptr) {
384
        /* XXX: send notification to userspace */
384
        /* XXX: send notification to userspace */
385
    }
385
    }
386
   
386
   
387
    spinlock_unlock(&sgcn_irq.lock);
387
    spinlock_unlock(&sgcn_irq.lock);
388
    interrupts_restore(ipl);   
388
    interrupts_restore(ipl);   
389
 
389
 
390
    while (*in_rdptr_ptr != *in_wrptr_ptr) {
390
    while (*in_rdptr_ptr != *in_wrptr_ptr) {
391
       
391
       
392
        buf_ptr = (volatile char *)
392
        buf_ptr = (volatile char *)
393
            SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
393
            SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
394
        char c = *buf_ptr;
394
        char c = *buf_ptr;
395
        *in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
395
        *in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
396
           
396
           
397
        if (c == '\r') {
397
        if (c == '\r') {
398
            c = '\n';
398
            c = '\n';
399
        }
399
        }
400
        chardev_push_character(&sgcn_io, c);   
400
        chardev_push_character(&sgcn_io, c);   
401
    }  
401
    }  
402
   
402
   
403
    spinlock_unlock(&sgcn_input_lock);
403
    spinlock_unlock(&sgcn_input_lock);
404
}
404
}
405
 
405
 
406
/**
406
/**
407
 * A public function which initializes I/O from/to Serengeti console
407
 * A public function which initializes I/O from/to Serengeti console
408
 * and sets it as a default input/output.
408
 * and sets it as a default input/output.
409
 */
409
 */
410
void sgcn_init(void)
410
void sgcn_init(void)
411
{
411
{
412
    sgcn_buffer_begin_init();
412
    sgcn_buffer_begin_init();
413
 
413
 
414
    kbd_type = KBD_SGCN;
414
    kbd_type = KBD_SGCN;
415
 
415
 
416
    devno_t devno = device_assign_devno();
416
    devno_t devno = device_assign_devno();
417
    irq_initialize(&sgcn_irq);
417
    irq_initialize(&sgcn_irq);
418
    sgcn_irq.devno = devno;
418
    sgcn_irq.devno = devno;
419
    sgcn_irq.inr = FICTIONAL_INR;
419
    sgcn_irq.inr = FICTIONAL_INR;
420
    sgcn_irq.claim = sgcn_claim;
420
    sgcn_irq.claim = sgcn_claim;
421
    sgcn_irq.handler = sgcn_irq_handler;
421
    sgcn_irq.handler = sgcn_irq_handler;
422
    irq_register(&sgcn_irq);
422
    irq_register(&sgcn_irq);
423
   
423
   
424
    sysinfo_set_item_val("kbd", NULL, true);
424
    sysinfo_set_item_val("kbd", NULL, true);
425
    sysinfo_set_item_val("kbd.type", NULL, KBD_SGCN);
425
    sysinfo_set_item_val("kbd.type", NULL, KBD_SGCN);
426
    sysinfo_set_item_val("kbd.devno", NULL, devno);
426
    sysinfo_set_item_val("kbd.devno", NULL, devno);
427
    sysinfo_set_item_val("kbd.inr", NULL, FICTIONAL_INR);
427
    sysinfo_set_item_val("kbd.inr", NULL, FICTIONAL_INR);
428
    sysinfo_set_item_val("fb.kind", NULL, 4);
428
    sysinfo_set_item_val("fb.kind", NULL, 4);
429
   
429
   
430
    chardev_initialize("sgcn_io", &sgcn_io, &sgcn_ops);
430
    chardev_initialize("sgcn_io", &sgcn_io, &sgcn_ops);
431
    stdin = &sgcn_io;
431
    stdin = &sgcn_io;
432
    stdout = &sgcn_io;
432
    stdout = &sgcn_io;
433
}
433
}
434
 
434
 
435
/** @}
435
/** @}
436
 */
436
 */
437
 
437