Subversion Repositories HelenOS

Rev

Rev 4345 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4345 Rev 4346
Line 32... Line 32...
32
/**
32
/**
33
 * @file
33
 * @file
34
 * @brief   SGCN driver.
34
 * @brief   SGCN driver.
35
 */
35
 */
36
 
36
 
-
 
37
#include <arch.h>
37
#include <arch/drivers/sgcn.h>
38
#include <arch/drivers/sgcn.h>
38
#include <arch/drivers/kbd.h>
39
#include <arch/drivers/kbd.h>
39
#include <genarch/ofw/ofw_tree.h>
40
#include <genarch/ofw/ofw_tree.h>
40
#include <debug.h>
41
#include <debug.h>
41
#include <string.h>
42
#include <string.h>
42
#include <print.h>
43
#include <print.h>
43
#include <mm/page.h>
44
#include <mm/page.h>
44
#include <ipc/irq.h>
45
#include <proc/thread.h>
45
#include <ddi/ddi.h>
-
 
46
#include <ddi/device.h>
-
 
47
#include <console/chardev.h>
46
#include <console/chardev.h>
48
#include <console/console.h>
47
#include <console/console.h>
49
#include <ddi/device.h>
-
 
50
#include <sysinfo/sysinfo.h>
48
#include <sysinfo/sysinfo.h>
51
#include <synch/spinlock.h>
49
#include <synch/spinlock.h>
52
 
50
 
-
 
51
#define POLL_INTERVAL       10000
-
 
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.
Line 71... Line 71...
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 necessary arrangements 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
/**
-
 
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
-
 
88
 * interrupt number. The interrupt number can be arbitrary as it it
-
 
89
 * will never be used for identifying HW interrupts, but only in
-
 
90
 * notifying the userspace.
-
 
91
 */
-
 
92
#define FICTIONAL_INR       1
-
 
93
 
-
 
94
 
-
 
95
/*
85
/*
96
 * Returns a pointer to the object of a given type which is placed at the given
86
 * Returns a pointer to the object of a given type which is placed at the given
97
 * offset from the SRAM beginning.
87
 * offset from the SRAM beginning.
98
 */
88
 */
99
#define SRAM(type, offset)  ((type *) (sram_begin + (offset)))
89
#define SRAM(type, offset)  ((type *) (sram_begin + (offset)))
Line 104... Line 94...
104
/*
94
/*
105
 * Returns a pointer to the object of a given type which is placed at the given
95
 * Returns a pointer to the object of a given type which is placed at the given
106
 * offset from the console buffer beginning.
96
 * offset from the console buffer beginning.
107
 */
97
 */
108
#define SGCN_BUFFER(type, offset) \
98
#define SGCN_BUFFER(type, offset) \
109
                ((type *) (sgcn_buffer_begin + (offset)))
99
    ((type *) (sgcn_buffer_begin + (offset)))
110
 
100
 
111
/** Returns a pointer to the console buffer header. */
101
/** Returns a pointer to the console buffer header. */
112
#define SGCN_BUFFER_HEADER  (SGCN_BUFFER(sgcn_buffer_header_t, 0))
102
#define SGCN_BUFFER_HEADER  (SGCN_BUFFER(sgcn_buffer_header_t, 0))
113
 
103
 
114
/** defined in drivers/kbd.c */
104
/** defined in drivers/kbd.c */
Line 121... Line 111...
121
 * starting address of the SGCN buffer, will be set by the
111
 * starting address of the SGCN buffer, will be set by the
122
 * init_sgcn_buffer_begin function
112
 * init_sgcn_buffer_begin function
123
 */
113
 */
124
static uintptr_t sgcn_buffer_begin;
114
static uintptr_t sgcn_buffer_begin;
125
 
115
 
126
/**
-
 
127
 * SGCN IRQ structure. So far used only for notifying the userspace of the
116
/* true iff the kernel driver should ignore pressed keys */
128
 * key being pressed, not for kernel being informed about keyboard interrupts.
-
 
129
 */
-
 
130
static irq_t sgcn_irq;
117
static bool kbd_disabled;
131
 
-
 
132
// TODO think of a way how to synchronize accesses to SGCN buffer between the kernel and the userspace
-
 
133
 
118
 
134
/*
119
/*
135
 * Ensures that writing to the buffer and consequent update of the write pointer
120
 * Ensures that writing to the buffer and consequent update of the write pointer
136
 * are together one atomic operation.
121
 * are together one atomic operation.
137
 */
122
 */
Line 143... Line 128...
143
 */
128
 */
144
SPINLOCK_INITIALIZE(sgcn_input_lock);
129
SPINLOCK_INITIALIZE(sgcn_input_lock);
145
 
130
 
146
 
131
 
147
/* functions referenced from definitions of I/O operations structures */
132
/* functions referenced from definitions of I/O operations structures */
148
static void sgcn_noop(chardev_t *);
-
 
149
static void sgcn_putchar(chardev_t *, const char, bool);
133
static void sgcn_putchar(outdev_t *, const char, bool);
150
static char sgcn_key_read(chardev_t *);
-
 
151
 
134
 
152
/** character device operations */
135
/** SGCN output device operations */
153
static chardev_operations_t sgcn_ops = {
136
static outdev_operations_t sgcnout_ops = {
154
    .suspend = sgcn_noop,
-
 
155
    .resume = sgcn_noop,
-
 
156
    .read = sgcn_key_read,
-
 
157
    .write = sgcn_putchar
137
    .write = sgcn_putchar
158
};
138
};
159
 
139
 
160
/** SGCN character device */
140
/** SGCN input device operations */
161
chardev_t sgcn_io;
141
static indev_operations_t sgcnin_ops = {
-
 
142
    .poll = NULL
-
 
143
};
-
 
144
 
-
 
145
static indev_t sgcnin;      /**< SGCN input device. */
-
 
146
static outdev_t sgcnout;    /**< SGCN output device. */
162
 
147
 
163
/**
148
/**
164
 * Set some sysinfo values (SRAM address and SRAM size).
149
 * Set some sysinfo values (SRAM address and SRAM size).
165
 */
150
 */
166
static void register_sram(uintptr_t sram_begin_physical)
151
static void register_sram(uintptr_t sram_begin_physical)
167
{
152
{
168
    sysinfo_set_item_val("sram.area.size", NULL, MAPPED_AREA_SIZE);
153
    sysinfo_set_item_val("sram.area.size", NULL, MAPPED_AREA_SIZE);
169
    sysinfo_set_item_val("sram.address.physical", NULL,
154
    sysinfo_set_item_val("sram.address.physical", NULL,
170
        sram_begin_physical);
155
        sram_begin_physical);
171
}
156
}
172
 
157
 
173
/**
158
/**
174
 * Initializes the starting address of SRAM.
159
 * Initializes the starting address of SRAM.
175
 *
160
 *
176
 * The SRAM starts 0x900000 + C bytes behind the SBBC start in the
161
 * 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"
162
 * physical memory, where C is the value read from the "iosram-toc"
178
 * property of the "/chosen" OBP node. The sram_begin variable will
163
 * property of the "/chosen" OBP node. The sram_begin variable will
179
 * be set to the virtual address which maps to the SRAM physical
164
 * be set to the virtual address which maps to the SRAM physical
180
 * address.
165
 * address.
181
 *
-
 
182
 * It also registers the physical area of SRAM and sets some sysinfo
-
 
183
 * values (SRAM address and SRAM size).
-
 
184
 */
166
 */
185
static void init_sram_begin(void)
167
static void init_sram_begin(void)
186
{
168
{
187
    ofw_tree_node_t *chosen;
169
    ofw_tree_node_t *chosen;
188
    ofw_tree_property_t *iosram_toc;
170
    ofw_tree_property_t *iosram_toc;
Line 197... Line 179...
197
        panic("Cannot find property 'iosram-toc'.");
179
        panic("Cannot find property 'iosram-toc'.");
198
    if (!iosram_toc->value)
180
    if (!iosram_toc->value)
199
        panic("Cannot find SRAM TOC.");
181
        panic("Cannot find SRAM TOC.");
200
 
182
 
201
    sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
183
    sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
202
        + *((uint32_t *) iosram_toc->value);
184
        + *((uint32_t *) iosram_toc->value);
203
    sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
185
    sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
204
   
186
   
205
    register_sram(sram_begin_physical);
187
    register_sram(sram_begin_physical);
206
}
188
}
207
 
189
 
Line 216... Line 198...
216
 * This function also writes the offset of the SGCN buffer within SRAM
198
 * This function also writes the offset of the SGCN buffer within SRAM
217
 * under the sram.buffer.offset sysinfo key.
199
 * under the sram.buffer.offset sysinfo key.
218
 */
200
 */
219
static void sgcn_buffer_begin_init(void)
201
static void sgcn_buffer_begin_init(void)
220
{
202
{
-
 
203
    static bool initialized;
-
 
204
   
-
 
205
    if (initialized)
-
 
206
        return;
-
 
207
 
221
    init_sram_begin();
208
    init_sram_begin();
222
       
209
       
223
    ASSERT(strcmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
210
    ASSERT(strcmp(SRAM_TOC->magic, SRAM_TOC_MAGIC) == 0);
224
   
211
   
225
    /* lookup TOC entry with the correct key */
212
    /* lookup TOC entry with the correct key */
Line 231... Line 218...
231
    ASSERT(i < MAX_TOC_ENTRIES);
218
    ASSERT(i < MAX_TOC_ENTRIES);
232
   
219
   
233
    sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
220
    sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
234
   
221
   
235
    sysinfo_set_item_val("sram.buffer.offset", NULL,
222
    sysinfo_set_item_val("sram.buffer.offset", NULL,
236
        SRAM_TOC->keys[i].offset);
223
        SRAM_TOC->keys[i].offset);
237
}
224
   
238
 
-
 
239
/**
-
 
240
 * Default suspend/resume operation for the input device.
-
 
241
 */
-
 
242
static void sgcn_noop(chardev_t *d)
225
    initialized = true;
243
{
-
 
244
}
226
}
245
 
227
 
246
/**
228
/**
247
 * Writes a single character to the SGCN (circular) output buffer
229
 * Writes a single character to the SGCN (circular) output buffer
248
 * and updates the output write pointer so that SGCN gets to know
230
 * and updates the output write pointer so that SGCN gets to know
Line 254... Line 236...
254
    uint32_t end = SGCN_BUFFER_HEADER->out_end;
236
    uint32_t end = SGCN_BUFFER_HEADER->out_end;
255
    uint32_t size = end - begin;
237
    uint32_t size = end - begin;
256
   
238
   
257
    /* we need pointers to volatile variables */
239
    /* we need pointers to volatile variables */
258
    volatile char *buf_ptr = (volatile char *)
240
    volatile char *buf_ptr = (volatile char *)
259
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
241
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->out_wrptr);
260
    volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
242
    volatile uint32_t *out_wrptr_ptr = &(SGCN_BUFFER_HEADER->out_wrptr);
261
    volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
243
    volatile uint32_t *out_rdptr_ptr = &(SGCN_BUFFER_HEADER->out_rdptr);
262
 
244
 
263
    /*
245
    /*
264
     * Write the character and increment the write pointer modulo the
246
     * Write the character and increment the write pointer modulo the
Line 284... Line 266...
284
/**
266
/**
285
 * SGCN output operation. Prints a single character to the SGCN. If the line
267
 * 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
268
 * feed character is written ('\n'), the carriage return character ('\r') is
287
 * written straight away.
269
 * written straight away.
288
 */
270
 */
289
static void sgcn_putchar(struct chardev * cd, const char c, bool silent)
271
static void sgcn_putchar(outdev_t *od, const char c, bool silent)
290
{
272
{
291
    if (!silent) {
273
    if (!silent) {
292
        spinlock_lock(&sgcn_output_lock);
274
        spinlock_lock(&sgcn_output_lock);
293
       
275
       
294
        sgcn_do_putchar(c);
276
        sgcn_do_putchar(c);
Line 298... Line 280...
298
        spinlock_unlock(&sgcn_output_lock);
280
        spinlock_unlock(&sgcn_output_lock);
299
    }
281
    }
300
}
282
}
301
 
283
 
302
/**
284
/**
303
 * Called when actively reading the character. Not implemented yet.
-
 
304
 */
-
 
305
static char sgcn_key_read(chardev_t *d)
-
 
306
{
-
 
307
    return (char) 0;
-
 
308
}
-
 
309
 
-
 
310
/**
-
 
311
 * The driver works in polled mode, so no interrupt should be handled by it.
-
 
312
 */
-
 
313
static irq_ownership_t sgcn_claim(irq_t *irq)
-
 
314
{
-
 
315
    return IRQ_DECLINE;
-
 
316
}
-
 
317
 
-
 
318
/**
-
 
319
 * The driver works in polled mode, so no interrupt should be handled by it.
-
 
320
 */
-
 
321
static void sgcn_irq_handler(irq_t *irq)
-
 
322
{
-
 
323
    panic("Not yet implemented, SGCN works in polled mode.");
-
 
324
}
-
 
325
 
-
 
326
/**
-
 
327
 * Grabs the input for kernel.
285
 * Grabs the input for kernel.
328
 */
286
 */
329
void sgcn_grab(void)
287
void sgcn_grab(void)
330
{
288
{
331
    ipl_t ipl = interrupts_disable();
-
 
332
   
-
 
333
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
-
 
334
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
-
 
335
   
-
 
336
    /* skip all the user typed before the grab and hasn't been processed */
-
 
337
    spinlock_lock(&sgcn_input_lock);
-
 
338
    *in_rdptr_ptr = *in_wrptr_ptr;
289
    kbd_disabled = true;
339
    spinlock_unlock(&sgcn_input_lock);
-
 
340
 
-
 
341
    spinlock_lock(&sgcn_irq.lock);
-
 
342
    sgcn_irq.notif_cfg.notify = false;
-
 
343
    spinlock_unlock(&sgcn_irq.lock);
-
 
344
   
-
 
345
    interrupts_restore(ipl);
-
 
346
}
290
}
347
 
291
 
348
/**
292
/**
349
 * Releases the input so that userspace can use it.
293
 * Releases the input so that userspace can use it.
350
 */
294
 */
351
void sgcn_release(void)
295
void sgcn_release(void)
352
{
296
{
353
    ipl_t ipl = interrupts_disable();
-
 
354
    spinlock_lock(&sgcn_irq.lock);
-
 
355
    if (sgcn_irq.notif_cfg.answerbox)
-
 
356
        sgcn_irq.notif_cfg.notify = true;
297
    kbd_disabled = true;
357
    spinlock_unlock(&sgcn_irq.lock);
-
 
358
    interrupts_restore(ipl);
-
 
359
}
298
}
360
 
299
 
361
/**
300
/**
362
 * Function regularly called by the keyboard polling thread. Finds out whether
301
 * 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
302
 * 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.
303
 * and sends them to the upper layers of HelenOS.
365
 */
304
 */
366
void sgcn_poll(void)
305
static void sgcn_poll()
367
{
306
{
368
    uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
307
    uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
369
    uint32_t end = SGCN_BUFFER_HEADER->in_end;
308
    uint32_t end = SGCN_BUFFER_HEADER->in_end;
370
    uint32_t size = end - begin;
309
    uint32_t size = end - begin;
-
 
310
 
-
 
311
    if (kbd_disabled)
-
 
312
        return;
371
   
313
 
372
    spinlock_lock(&sgcn_input_lock);
314
    spinlock_lock(&sgcn_input_lock);
373
   
315
   
374
    ipl_t ipl = interrupts_disable();
-
 
375
    spinlock_lock(&sgcn_irq.lock);
-
 
376
   
-
 
377
    /* we need pointers to volatile variables */
316
    /* we need pointers to volatile variables */
378
    volatile char *buf_ptr = (volatile char *)
317
    volatile char *buf_ptr = (volatile char *)
379
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
318
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
380
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
319
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
381
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
320
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
382
   
321
   
383
    if (*in_rdptr_ptr != *in_wrptr_ptr) {
-
 
384
        /* XXX: send notification to userspace */
-
 
385
    }
-
 
386
   
-
 
387
    spinlock_unlock(&sgcn_irq.lock);
-
 
388
    interrupts_restore(ipl);   
-
 
389
 
-
 
390
    while (*in_rdptr_ptr != *in_wrptr_ptr) {
322
    while (*in_rdptr_ptr != *in_wrptr_ptr) {
391
       
323
       
392
        buf_ptr = (volatile char *)
324
        buf_ptr = (volatile char *)
393
            SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
325
            SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
394
        char c = *buf_ptr;
326
        char c = *buf_ptr;
395
        *in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
327
        *in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
396
           
328
           
397
        if (c == '\r') {
-
 
398
            c = '\n';
-
 
399
        }
-
 
400
        chardev_push_character(&sgcn_io, c);   
329
        indev_push_character(&sgcnin, c);  
401
    }  
330
    }  
402
   
331
 
403
    spinlock_unlock(&sgcn_input_lock);
332
    spinlock_unlock(&sgcn_input_lock);
404
}
333
}
405
 
334
 
406
/**
335
/**
407
 * A public function which initializes I/O from/to Serengeti console
-
 
408
 * and sets it as a default input/output.
336
 * Polling thread function.
409
 */
337
 */
-
 
338
static void kkbdpoll(void *arg) {
-
 
339
    while (1) {
-
 
340
        if (!silent) {
-
 
341
            sgcn_poll();
-
 
342
        }
-
 
343
        thread_usleep(POLL_INTERVAL);
-
 
344
    }
-
 
345
}
-
 
346
 
-
 
347
/**
-
 
348
 * A public function which initializes input from the Serengeti console.
-
 
349
 */
410
void sgcn_init(void)
350
indev_t *sgcnin_init(void)
411
{
351
{
412
    sgcn_buffer_begin_init();
352
    sgcn_buffer_begin_init();
413
 
353
 
414
    kbd_type = KBD_SGCN;
354
    kbd_type = KBD_SGCN;
415
 
355
 
416
    devno_t devno = device_assign_devno();
-
 
417
    irq_initialize(&sgcn_irq);
-
 
418
    sgcn_irq.devno = devno;
-
 
419
    sgcn_irq.inr = FICTIONAL_INR;
-
 
420
    sgcn_irq.claim = sgcn_claim;
-
 
421
    sgcn_irq.handler = sgcn_irq_handler;
-
 
422
    irq_register(&sgcn_irq);
-
 
423
   
-
 
424
    sysinfo_set_item_val("kbd", NULL, true);
356
    sysinfo_set_item_val("kbd", NULL, true);
425
    sysinfo_set_item_val("kbd.type", NULL, KBD_SGCN);
357
    sysinfo_set_item_val("kbd.type", NULL, KBD_SGCN);
-
 
358
 
426
    sysinfo_set_item_val("kbd.devno", NULL, devno);
359
    thread_t *t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll", true);
-
 
360
    if (!t)
427
    sysinfo_set_item_val("kbd.inr", NULL, FICTIONAL_INR);
361
        panic("Cannot create kkbdpoll.");
428
    sysinfo_set_item_val("fb.kind", NULL, 4);
362
    thread_ready(t);
429
   
363
   
430
    chardev_initialize("sgcn_io", &sgcn_io, &sgcn_ops);
364
    indev_initialize("sgcnin", &sgcnin, &sgcnin_ops);
-
 
365
 
431
    stdin = &sgcn_io;
366
    return &sgcnin;
-
 
367
}
-
 
368
 
-
 
369
/**
-
 
370
 * A public function which initializes output to the Serengeti console.
-
 
371
 */
-
 
372
void sgcnout_init(void)
-
 
373
{
-
 
374
    sgcn_buffer_begin_init();
-
 
375
 
-
 
376
    sysinfo_set_item_val("fb.kind", NULL, 4);
-
 
377
 
-
 
378
    outdev_initialize("sgcnout", &sgcnout, &sgcnout_ops);  
432
    stdout = &sgcn_io;
379
    stdout = &sgcnout;
433
}
380
}
434
 
381
 
435
/** @}
382
/** @}
436
 */
383
 */