Subversion Repositories HelenOS

Rev

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

Rev 3514 Rev 3549
Line 33... Line 33...
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 <genarch/ofw/ofw_tree.h>
39
#include <genarch/ofw/ofw_tree.h>
39
#include <debug.h>
40
#include <debug.h>
40
#include <func.h>
41
#include <func.h>
41
#include <print.h>
42
#include <print.h>
42
#include <mm/page.h>
43
#include <mm/page.h>
-
 
44
#include <ipc/irq.h>
-
 
45
#include <ddi/ddi.h>
-
 
46
#include <ddi/device.h>
43
#include <console/chardev.h>
47
#include <console/chardev.h>
44
#include <console/console.h>
48
#include <console/console.h>
-
 
49
#include <ddi/device.h>
-
 
50
#include <sysinfo/sysinfo.h>
45
#include <synch/spinlock.h>
51
#include <synch/spinlock.h>
46
 
52
 
47
/*
53
/*
48
 * 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
49
 * 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
Line 53... Line 59...
53
#define SBBC_START      0x63000000000
59
#define SBBC_START      0x63000000000
54
 
60
 
55
/* offset of SRAM within the SBBC memory */
61
/* offset of SRAM within the SBBC memory */
56
#define SBBC_SRAM_OFFSET    0x900000
62
#define SBBC_SRAM_OFFSET    0x900000
57
 
63
 
-
 
64
/* size (in bytes) of the physical memory area which will be mapped */
-
 
65
#define MAPPED_AREA_SIZE    (128 * 1024)
-
 
66
 
58
/* magic string contained at the beginning of SRAM */
67
/* magic string contained at the beginning of SRAM */
59
#define SRAM_TOC_MAGIC      "TOCSRAM"
68
#define SRAM_TOC_MAGIC      "TOCSRAM"
60
 
69
 
61
/*
70
/*
62
 * Key into the SRAM table of contents which identifies the entry
71
 * Key into the SRAM table of contents which identifies the entry
Line 71... Line 80...
71
#define CONSOLE_KEY     "OBPCONS"
80
#define CONSOLE_KEY     "OBPCONS"
72
 
81
 
73
/* magic string contained at the beginning of the console buffer */
82
/* magic string contained at the beginning of the console buffer */
74
#define SGCN_BUFFER_MAGIC   "CON"
83
#define SGCN_BUFFER_MAGIC   "CON"
75
 
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
 
76
 
94
 
77
/*
95
/*
78
 * 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
79
 * offset from the SRAM beginning.
97
 * offset from the SRAM beginning.
80
 */
98
 */
Line 88... Line 106...
88
 * offset from the console buffer beginning.
106
 * offset from the console buffer beginning.
89
 */
107
 */
90
#define SGCN_BUFFER(type, offset) \
108
#define SGCN_BUFFER(type, offset) \
91
                ((type *) (sgcn_buffer_begin + (offset)))
109
                ((type *) (sgcn_buffer_begin + (offset)))
92
 
110
 
93
/* Returns a pointer to the console buffer header. */
111
/** Returns a pointer to the console buffer header. */
94
#define SGCN_BUFFER_HEADER  (SGCN_BUFFER(sgcn_buffer_header_t, 0))
112
#define SGCN_BUFFER_HEADER  (SGCN_BUFFER(sgcn_buffer_header_t, 0))
95
 
113
 
-
 
114
/** defined in drivers/kbd.c */
-
 
115
extern kbd_type_t kbd_type;
96
 
116
 
97
/* 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 */
98
static uintptr_t sram_begin;
118
static uintptr_t sram_begin;
99
 
119
 
100
/*
120
/**
101
 * starting address of the SGCN buffer, will be set by the
121
 * starting address of the SGCN buffer, will be set by the
102
 * init_sgcn_buffer_begin function
122
 * init_sgcn_buffer_begin function
103
 */
123
 */
104
static uintptr_t sgcn_buffer_begin;
124
static uintptr_t sgcn_buffer_begin;
105
 
125
 
-
 
126
/**
-
 
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.
-
 
129
 */
-
 
130
static irq_t sgcn_irq;
-
 
131
 
-
 
132
// TODO think of a way how to synchronize accesses to SGCN buffer between the kernel and the userspace
106
 
133
 
107
/*
134
/*
108
 * 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
109
 * are together one atomic operation.
136
 * are together one atomic operation.
110
 */
137
 */
111
SPINLOCK_INITIALIZE(sgcn_output_lock);
138
SPINLOCK_INITIALIZE(sgcn_output_lock);
112
 
139
 
113
/*
140
/*
114
 * Ensures that reading from the buffer and consequent update of the read
141
 * Prevents the input buffer read/write pointers from getting to inconsistent
115
 * pointer are together one atomic operation.
142
 * state.
116
 */
143
 */
117
SPINLOCK_INITIALIZE(sgcn_input_lock);
144
SPINLOCK_INITIALIZE(sgcn_input_lock);
118
 
145
 
119
 
146
 
120
/* functions referenced from definitions of I/O operations structures */
147
/* functions referenced from definitions of I/O operations structures */
121
static void sgcn_noop(chardev_t *);
148
static void sgcn_noop(chardev_t *);
122
static void sgcn_putchar(chardev_t *, const char);
149
static void sgcn_putchar(chardev_t *, const char);
123
static char sgcn_key_read(chardev_t *);
150
static char sgcn_key_read(chardev_t *);
124
 
151
 
125
/** character device output operations */
152
/** character device operations */
126
static chardev_operations_t sgcn_output_ops = {
153
static chardev_operations_t sgcn_ops = {
127
    .suspend = sgcn_noop,
154
    .suspend = sgcn_noop,
128
    .resume = sgcn_noop,
155
    .resume = sgcn_noop,
129
    .write = sgcn_putchar,
156
    .read = sgcn_key_read,
130
    .read = NULL
157
    .write = sgcn_putchar
131
};
158
};
132
 
159
 
133
/** character device input operations */
-
 
134
static chardev_operations_t sgcn_input_ops = {
-
 
135
    .suspend = sgcn_noop,
-
 
136
    .resume = sgcn_noop,
-
 
137
    .read = sgcn_key_read
-
 
138
};
-
 
139
 
-
 
140
 
-
 
141
/** SGCN character output device */
-
 
142
chardev_t sgcn_stdout;
-
 
143
 
-
 
144
/** SGCN character input device */
160
/** SGCN character device */
145
chardev_t sgcn_input;
161
chardev_t sgcn_io;
146
 
162
 
-
 
163
/**
-
 
164
 * Registers the physical area of the SRAM so that the userspace SGCN
-
 
165
 * driver can map it. Moreover, it sets some sysinfo values (SRAM address
-
 
166
 * and SRAM size).
-
 
167
 */
-
 
168
static void register_sram_parea(uintptr_t sram_begin_physical)
-
 
169
{
-
 
170
    static parea_t sram_parea;
-
 
171
    sram_parea.pbase = sram_begin_physical;
-
 
172
    sram_parea.vbase = (uintptr_t) sram_begin;
-
 
173
    sram_parea.frames = MAPPED_AREA_SIZE / FRAME_SIZE;
-
 
174
    sram_parea.cacheable = false;
-
 
175
    ddi_parea_register(&sram_parea);
-
 
176
   
-
 
177
    sysinfo_set_item_val("sram.area.size", NULL, MAPPED_AREA_SIZE);
-
 
178
    sysinfo_set_item_val("sram.address.physical", NULL, sram_begin_physical);
-
 
179
}
147
 
180
 
148
/**
181
/**
149
 * Initializes the starting address of SRAM.
182
 * Initializes the starting address of SRAM.
150
 *
183
 *
151
 * The SRAM starts 0x900000 + C bytes behind the SBBC start in the
184
 * The SRAM starts 0x900000 + C bytes behind the SBBC start in the
152
 * physical memory, where C is the value read from the "iosram-toc"
185
 * physical memory, where C is the value read from the "iosram-toc"
153
 * property of the "/chosen" OBP node. The sram_begin variable will
186
 * property of the "/chosen" OBP node. The sram_begin variable will
154
 * be set to the virtual address which maps to the SRAM physical
187
 * be set to the virtual address which maps to the SRAM physical
155
 * address.
188
 * address.
-
 
189
 *
-
 
190
 * It also registers the physical area of SRAM and sets some sysinfo
-
 
191
 * values (SRAM address and SRAM size).
156
 */
192
 */
157
static void init_sram_begin(void)
193
static void init_sram_begin(void)
158
{
194
{
159
    ofw_tree_node_t *chosen;
195
    ofw_tree_node_t *chosen;
160
    ofw_tree_property_t *iosram_toc;
196
    ofw_tree_property_t *iosram_toc;
-
 
197
    uintptr_t sram_begin_physical;
161
 
198
 
162
    chosen = ofw_tree_lookup("/chosen");
199
    chosen = ofw_tree_lookup("/chosen");
163
    if (!chosen)
200
    if (!chosen)
164
        panic("Can't find /chosen.\n");
201
        panic("Can't find /chosen.\n");
165
 
202
 
Line 167... Line 204...
167
    if (!iosram_toc)
204
    if (!iosram_toc)
168
        panic("Can't find property \"iosram-toc\".\n");
205
        panic("Can't find property \"iosram-toc\".\n");
169
    if (!iosram_toc->value)
206
    if (!iosram_toc->value)
170
        panic("Can't find SRAM TOC.\n");
207
        panic("Can't find SRAM TOC.\n");
171
 
208
 
172
    sram_begin = hw_map(
-
 
173
        SBBC_START + SBBC_SRAM_OFFSET
209
    sram_begin_physical = SBBC_START + SBBC_SRAM_OFFSET
174
        + *((uint32_t *) iosram_toc->value),
210
        + *((uint32_t *) iosram_toc->value);
-
 
211
    sram_begin = hw_map(sram_begin_physical, MAPPED_AREA_SIZE);
-
 
212
   
175
        128 * 1024);
213
    register_sram_parea(sram_begin_physical);
176
}
214
}
177
 
215
 
178
/**
216
/**
179
 * Initializes the starting address of the SGCN buffer.
217
 * Initializes the starting address of the SGCN buffer.
180
 *
218
 *
181
 * The offset of the SGCN buffer within SRAM is obtained from the
219
 * The offset of the SGCN buffer within SRAM is obtained from the
182
 * SRAM table of contents. The table of contents contains
220
 * SRAM table of contents. The table of contents contains
183
 * information about several buffers, among which there is an OBP
221
 * information about several buffers, among which there is an OBP
184
 * console buffer - this one will be used as the SGCN buffer.
222
 * console buffer - this one will be used as the SGCN buffer.
-
 
223
 *
-
 
224
 * This function also writes the offset of the SGCN buffer within SRAM
-
 
225
 * under the sram.buffer.offset sysinfo key.
185
 */
226
 */
186
static void sgcn_buffer_begin_init(void)
227
static void sgcn_buffer_begin_init(void)
187
{
228
{
188
    init_sram_begin();
229
    init_sram_begin();
189
       
230
       
Line 196... Line 237...
196
            break;
237
            break;
197
    }
238
    }
198
    ASSERT(i < MAX_TOC_ENTRIES);
239
    ASSERT(i < MAX_TOC_ENTRIES);
199
   
240
   
200
    sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
241
    sgcn_buffer_begin = sram_begin + SRAM_TOC->keys[i].offset;
-
 
242
   
-
 
243
    sysinfo_set_item_val("sram.buffer.offset", NULL,
-
 
244
        SRAM_TOC->keys[i].offset);
201
}
245
}
202
 
246
 
203
/**
247
/**
204
 * Default suspend/resume operation for the input device.
248
 * Default suspend/resume operation for the input device.
205
 */
249
 */
Line 269... Line 313...
269
{
313
{
270
    return (char) 0;
314
    return (char) 0;
271
}
315
}
272
 
316
 
273
/**
317
/**
-
 
318
 * The driver works in polled mode, so no interrupt should be handled by it.
-
 
319
 */
-
 
320
static irq_ownership_t sgcn_claim(void)
-
 
321
{
-
 
322
    return IRQ_DECLINE;
-
 
323
}
-
 
324
 
-
 
325
/**
-
 
326
 * The driver works in polled mode, so no interrupt should be handled by it.
-
 
327
 */
-
 
328
static void sgcn_irq_handler(irq_t *irq, void *arg, ...)
-
 
329
{
-
 
330
    panic("Not yet implemented, SGCN works in polled mode.\n");
-
 
331
}
-
 
332
 
-
 
333
/**
-
 
334
 * Grabs the input for kernel.
-
 
335
 */
-
 
336
void sgcn_grab(void)
-
 
337
{
-
 
338
    ipl_t ipl = interrupts_disable();
-
 
339
   
-
 
340
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
-
 
341
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
-
 
342
   
-
 
343
    /* skip all the user typed before the grab and hasn't been processed */
-
 
344
    spinlock_lock(&sgcn_input_lock);
-
 
345
    *in_rdptr_ptr = *in_wrptr_ptr;
-
 
346
    spinlock_unlock(&sgcn_input_lock);
-
 
347
 
-
 
348
    spinlock_lock(&sgcn_irq.lock);
-
 
349
    sgcn_irq.notif_cfg.notify = false;
-
 
350
    spinlock_unlock(&sgcn_irq.lock);
-
 
351
   
-
 
352
    interrupts_restore(ipl);
-
 
353
}
-
 
354
 
-
 
355
/**
-
 
356
 * Releases the input so that userspace can use it.
-
 
357
 */
-
 
358
void sgcn_release(void)
-
 
359
{
-
 
360
    ipl_t ipl = interrupts_disable();
-
 
361
    spinlock_lock(&sgcn_irq.lock);
-
 
362
    if (sgcn_irq.notif_cfg.answerbox)
-
 
363
        sgcn_irq.notif_cfg.notify = true;
-
 
364
    spinlock_unlock(&sgcn_irq.lock);
-
 
365
    interrupts_restore(ipl);
-
 
366
}
-
 
367
 
-
 
368
/**
274
 * Function regularly called by the keyboard polling thread. Finds out whether
369
 * Function regularly called by the keyboard polling thread. Finds out whether
275
 * there are some unread characters in the input queue. If so, it picks them up
370
 * there are some unread characters in the input queue. If so, it picks them up
276
 * and sends them to the upper layers of HelenOS.
371
 * and sends them to the upper layers of HelenOS.
277
 */
372
 */
278
void sgcn_poll(void)
373
void sgcn_poll(void)
279
{
374
{
280
    spinlock_lock(&sgcn_input_lock);
-
 
281
   
-
 
282
    char c;
-
 
283
    uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
375
    uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
284
    uint32_t end = SGCN_BUFFER_HEADER->in_end;
376
    uint32_t end = SGCN_BUFFER_HEADER->in_end;
285
    uint32_t size = end - begin;
377
    uint32_t size = end - begin;
286
   
378
   
-
 
379
    spinlock_lock(&sgcn_input_lock);
-
 
380
   
-
 
381
    ipl_t ipl = interrupts_disable();
-
 
382
    spinlock_lock(&sgcn_irq.lock);
-
 
383
   
287
    /* we need pointers to volatile variables */
384
    /* we need pointers to volatile variables */
288
    volatile char *buf_ptr = (volatile char *)
385
    volatile char *buf_ptr = (volatile char *)
289
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
386
        SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
290
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
387
    volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
291
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
388
    volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
292
   
389
   
-
 
390
    if (*in_rdptr_ptr != *in_wrptr_ptr) {
-
 
391
        if (sgcn_irq.notif_cfg.notify && sgcn_irq.notif_cfg.answerbox) {
-
 
392
            ipc_irq_send_notif(&sgcn_irq);
-
 
393
            spinlock_unlock(&sgcn_irq.lock);
-
 
394
            interrupts_restore(ipl);
-
 
395
            spinlock_unlock(&sgcn_input_lock);
-
 
396
            return;
-
 
397
        }
-
 
398
    }
-
 
399
   
-
 
400
    spinlock_unlock(&sgcn_irq.lock);
-
 
401
    interrupts_restore(ipl);   
-
 
402
 
293
    while (*in_rdptr_ptr != *in_wrptr_ptr) {
403
    while (*in_rdptr_ptr != *in_wrptr_ptr) {
294
        c = *buf_ptr;
404
       
295
        *in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
-
 
296
        buf_ptr = (volatile char *)
405
        buf_ptr = (volatile char *)
297
            SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
406
            SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
298
        chardev_push_character(&sgcn_input, c);
407
        char c = *buf_ptr;
-
 
408
        *in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
-
 
409
           
299
        if (c == '\r')
410
        if (c == '\r') {
-
 
411
            c = '\n';
-
 
412
        }
300
            chardev_push_character(&sgcn_input, '\n');
413
        chardev_push_character(&sgcn_io, c);   
301
    }
414
    }  
302
   
415
   
303
    spinlock_unlock(&sgcn_input_lock);
416
    spinlock_unlock(&sgcn_input_lock);
304
}
417
}
305
 
418
 
306
/**
419
/**
Line 308... Line 421...
308
 * and sets it as a default input/output.
421
 * and sets it as a default input/output.
309
 */
422
 */
310
void sgcn_init(void)
423
void sgcn_init(void)
311
{
424
{
312
    sgcn_buffer_begin_init();
425
    sgcn_buffer_begin_init();
-
 
426
 
-
 
427
    kbd_type = KBD_SGCN;
-
 
428
 
-
 
429
    devno_t devno = device_assign_devno();
-
 
430
    irq_initialize(&sgcn_irq);
-
 
431
    sgcn_irq.devno = devno;
-
 
432
    sgcn_irq.inr = FICTIONAL_INR;
-
 
433
    sgcn_irq.claim = sgcn_claim;
-
 
434
    sgcn_irq.handler = sgcn_irq_handler;
-
 
435
    irq_register(&sgcn_irq);
313
   
436
   
-
 
437
    sysinfo_set_item_val("kbd", NULL, true);
-
 
438
    sysinfo_set_item_val("kbd.type", NULL, KBD_SGCN);
-
 
439
    sysinfo_set_item_val("kbd.devno", NULL, devno);
314
    chardev_initialize("sgcn_output", &sgcn_stdout, &sgcn_output_ops);
440
    sysinfo_set_item_val("kbd.inr", NULL, FICTIONAL_INR);
315
    stdout = &sgcn_stdout;
441
    sysinfo_set_item_val("fb.kind", NULL, 4);
316
   
442
   
317
    chardev_initialize("sgcn_input", &sgcn_input, &sgcn_input_ops);
443
    chardev_initialize("sgcn_io", &sgcn_io, &sgcn_ops);
318
    stdin = &sgcn_input;
444
    stdin = &sgcn_io;
-
 
445
    stdout = &sgcn_io;
319
}
446
}
320
 
447
 
321
/** @}
448
/** @}
322
 */
-
 
323
449
 */
-
 
450