source: mainline/kernel/arch/arm32/src/drivers/gxemul.c@ 9446f39

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9446f39 was 9446f39, checked in by Jakub Jermar <jakub@…>, 17 years ago

Unreak arm32 (as far as breakage introduced by 3947 goes) and
adapt the uspace GXemul kbd IRQ driver to use the new pseudo code.

  • Property mode set to 100644
File size: 9.4 KB
Line 
1/*
2 * Copyright (c) 2007 Michal Kebrt, Petr Stepan
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 arm32gxemul
30 * @{
31 */
32/** @file
33 * @brief GXemul drivers.
34 */
35
36#include <interrupt.h>
37#include <ipc/irq.h>
38#include <console/chardev.h>
39#include <arch/drivers/gxemul.h>
40#include <console/console.h>
41#include <sysinfo/sysinfo.h>
42#include <print.h>
43#include <ddi/device.h>
44#include <mm/page.h>
45#include <arch/machine.h>
46#include <arch/debug/print.h>
47
48/* Addresses of devices. */
49#define GXEMUL_VIDEORAM 0x10000000
50#define GXEMUL_KBD 0x10000000
51#define GXEMUL_HALT_OFFSET 0x10
52#define GXEMUL_RTC 0x15000000
53#define GXEMUL_RTC_FREQ_OFFSET 0x100
54#define GXEMUL_RTC_ACK_OFFSET 0x110
55#define GXEMUL_IRQC 0x16000000
56#define GXEMUL_IRQC_MASK_OFFSET 0x4
57#define GXEMUL_IRQC_UNMASK_OFFSET 0x8
58#define GXEMUL_MP 0x11000000
59#define GXEMUL_MP_MEMSIZE_OFFSET 0x0090
60#define GXEMUL_FB 0x12000000
61
62/* IRQs */
63#define GXEMUL_KBD_IRQ 2
64#define GXEMUL_TIMER_IRQ 4
65
66static gxemul_hw_map_t gxemul_hw_map;
67static chardev_t console;
68static irq_t gxemul_console_irq;
69static irq_t gxemul_timer_irq;
70
71static bool hw_map_init_called = false;
72
73static void gxemul_kbd_enable(chardev_t *dev);
74static void gxemul_kbd_disable(chardev_t *dev);
75static void gxemul_write(chardev_t *dev, const char ch, bool silent);
76static char gxemul_do_read(chardev_t *dev);
77
78static chardev_operations_t gxemul_ops = {
79 .resume = gxemul_kbd_enable,
80 .suspend = gxemul_kbd_disable,
81 .write = gxemul_write,
82 .read = gxemul_do_read,
83};
84
85
86/** Returns the mask of active interrupts. */
87static inline uint32_t gxemul_irqc_get_sources(void)
88{
89 return *((uint32_t *) gxemul_hw_map.irqc);
90}
91
92
93/** Masks interrupt.
94 *
95 * @param irq interrupt number
96 */
97static inline void gxemul_irqc_mask(uint32_t irq)
98{
99 *((uint32_t *) gxemul_hw_map.irqc_mask) = irq;
100}
101
102
103/** Unmasks interrupt.
104 *
105 * @param irq interrupt number
106 */
107static inline void gxemul_irqc_unmask(uint32_t irq)
108{
109 *((uint32_t *) gxemul_hw_map.irqc_unmask) = irq;
110}
111
112
113/** Initializes #gxemul_hw_map. */
114void gxemul_hw_map_init(void)
115{
116 gxemul_hw_map.videoram = hw_map(GXEMUL_VIDEORAM, PAGE_SIZE);
117 gxemul_hw_map.kbd = hw_map(GXEMUL_KBD, PAGE_SIZE);
118 gxemul_hw_map.rtc = hw_map(GXEMUL_RTC, PAGE_SIZE);
119 gxemul_hw_map.irqc = hw_map(GXEMUL_IRQC, PAGE_SIZE);
120
121 gxemul_hw_map.rtc_freq = gxemul_hw_map.rtc + GXEMUL_RTC_FREQ_OFFSET;
122 gxemul_hw_map.rtc_ack = gxemul_hw_map.rtc + GXEMUL_RTC_ACK_OFFSET;
123 gxemul_hw_map.irqc_mask = gxemul_hw_map.irqc + GXEMUL_IRQC_MASK_OFFSET;
124 gxemul_hw_map.irqc_unmask = gxemul_hw_map.irqc +
125 GXEMUL_IRQC_UNMASK_OFFSET;
126
127 hw_map_init_called = true;
128}
129
130
131/** Putchar that works with gxemul.
132 *
133 * @param dev Not used.
134 * @param ch Characted to be printed.
135 */
136static void gxemul_write(chardev_t *dev, const char ch, bool silent)
137{
138 if (!silent)
139 *((char *) gxemul_hw_map.videoram) = ch;
140}
141
142/** Enables gxemul keyboard (interrupt unmasked).
143 *
144 * @param dev Not used.
145 *
146 * Called from getc().
147 */
148static void gxemul_kbd_enable(chardev_t *dev)
149{
150 gxemul_irqc_unmask(GXEMUL_KBD_IRQ);
151}
152
153/** Disables gxemul keyboard (interrupt masked).
154 *
155 * @param dev not used
156 *
157 * Called from getc().
158 */
159static void gxemul_kbd_disable(chardev_t *dev)
160{
161 gxemul_irqc_mask(GXEMUL_KBD_IRQ);
162}
163
164/** Read character using polling, assume interrupts disabled.
165 *
166 * @param dev Not used.
167 */
168static char gxemul_do_read(chardev_t *dev)
169{
170 char ch;
171
172 while (1) {
173 ch = *((volatile char *) gxemul_hw_map.kbd);
174 if (ch) {
175 if (ch == '\r')
176 return '\n';
177 if (ch == 0x7f)
178 return '\b';
179 return ch;
180 }
181 }
182}
183
184/** Process keyboard interrupt.
185 *
186 * @param irq IRQ information.
187 */
188static void gxemul_irq_handler(irq_t *irq)
189{
190 char ch = 0;
191
192 ch = *((char *) gxemul_hw_map.kbd);
193 if (ch == '\r') {
194 ch = '\n';
195 }
196 if (ch == 0x7f) {
197 ch = '\b';
198 }
199 chardev_push_character(&console, ch);
200}
201
202static irq_ownership_t gxemul_claim(irq_t *irq)
203{
204 return IRQ_ACCEPT;
205}
206
207
208/** Acquire console back for kernel. */
209void gxemul_grab_console(void)
210{
211 ipl_t ipl = interrupts_disable();
212 spinlock_lock(&gxemul_console_irq.lock);
213 gxemul_console_irq.notif_cfg.notify = false;
214 spinlock_unlock(&gxemul_console_irq.lock);
215 interrupts_restore(ipl);
216}
217
218/** Return console to userspace. */
219void gxemul_release_console(void)
220{
221 ipl_t ipl = interrupts_disable();
222 spinlock_lock(&gxemul_console_irq.lock);
223 if (gxemul_console_irq.notif_cfg.answerbox) {
224 gxemul_console_irq.notif_cfg.notify = true;
225 }
226 spinlock_unlock(&gxemul_console_irq.lock);
227 interrupts_restore(ipl);
228}
229
230/** Initializes console object representing gxemul console.
231 *
232 * @param devno device number.
233 */
234void gxemul_console_init(devno_t devno)
235{
236 chardev_initialize("gxemul_console", &console, &gxemul_ops);
237 stdin = &console;
238 stdout = &console;
239
240 irq_initialize(&gxemul_console_irq);
241 gxemul_console_irq.devno = devno;
242 gxemul_console_irq.inr = GXEMUL_KBD_IRQ;
243 gxemul_console_irq.claim = gxemul_claim;
244 gxemul_console_irq.handler = gxemul_irq_handler;
245 irq_register(&gxemul_console_irq);
246
247 gxemul_irqc_unmask(GXEMUL_KBD_IRQ);
248
249 sysinfo_set_item_val("kbd", NULL, true);
250 sysinfo_set_item_val("kbd.devno", NULL, devno);
251 sysinfo_set_item_val("kbd.inr", NULL, GXEMUL_KBD_IRQ);
252 sysinfo_set_item_val("kbd.address.virtual", NULL, gxemul_hw_map.kbd);
253}
254
255/** Starts gxemul Real Time Clock device, which asserts regular interrupts.
256 *
257 * @param frequency Interrupts frequency (0 disables RTC).
258 */
259static void gxemul_timer_start(uint32_t frequency)
260{
261 *((uint32_t*) gxemul_hw_map.rtc_freq) = frequency;
262}
263
264static irq_ownership_t gxemul_timer_claim(irq_t *irq)
265{
266 return IRQ_ACCEPT;
267}
268
269/** Timer interrupt handler.
270 *
271 * @param irq Interrupt information.
272 * @param arg Not used.
273 */
274static void gxemul_timer_irq_handler(irq_t *irq)
275{
276 /*
277 * We are holding a lock which prevents preemption.
278 * Release the lock, call clock() and reacquire the lock again.
279 */
280 spinlock_unlock(&irq->lock);
281 clock();
282 spinlock_lock(&irq->lock);
283
284 /* acknowledge tick */
285 *((uint32_t*) gxemul_hw_map.rtc_ack) = 0;
286}
287
288/** Initializes and registers timer interrupt handler. */
289static void gxemul_timer_irq_init(void)
290{
291 irq_initialize(&gxemul_timer_irq);
292 gxemul_timer_irq.devno = device_assign_devno();
293 gxemul_timer_irq.inr = GXEMUL_TIMER_IRQ;
294 gxemul_timer_irq.claim = gxemul_timer_claim;
295 gxemul_timer_irq.handler = gxemul_timer_irq_handler;
296
297 irq_register(&gxemul_timer_irq);
298}
299
300
301/** Starts timer.
302 *
303 * Initiates regular timer interrupts after initializing
304 * corresponding interrupt handler.
305 */
306void gxemul_timer_irq_start(void)
307{
308 gxemul_timer_irq_init();
309 gxemul_timer_start(GXEMUL_TIMER_FREQ);
310}
311
312/** Returns the size of emulated memory.
313 *
314 * @return Size in bytes.
315 */
316size_t gxemul_get_memory_size(void)
317{
318 return *((int *) (GXEMUL_MP + GXEMUL_MP_MEMSIZE_OFFSET));
319}
320
321/** Prints a character.
322 *
323 * @param ch Character to be printed.
324 */
325void gxemul_debug_putc(char ch)
326{
327 char *addr = 0;
328 if (!hw_map_init_called) {
329 addr = (char *) GXEMUL_KBD;
330 } else {
331 addr = (char *) gxemul_hw_map.videoram;
332 }
333
334 *(addr) = ch;
335}
336
337/** Stops gxemul. */
338void gxemul_cpu_halt(void)
339{
340 char * addr = 0;
341 if (!hw_map_init_called) {
342 addr = (char *) GXEMUL_KBD;
343 } else {
344 addr = (char *) gxemul_hw_map.videoram;
345 }
346
347 *(addr + GXEMUL_HALT_OFFSET) = '\0';
348}
349
350/** Gxemul specific interrupt exception handler.
351 *
352 * Determines sources of the interrupt from interrupt controller and
353 * calls high-level handlers for them.
354 *
355 * @param exc_no Interrupt exception number.
356 * @param istate Saved processor state.
357 */
358void gxemul_irq_exception(int exc_no, istate_t *istate)
359{
360 uint32_t sources = gxemul_irqc_get_sources();
361 int i;
362
363 for (i = 0; i < GXEMUL_IRQC_MAX_IRQ; i++) {
364 if (sources & (1 << i)) {
365 irq_t *irq = irq_dispatch_and_lock(i);
366 if (irq) {
367 /* The IRQ handler was found. */
368 irq->handler(irq);
369 spinlock_unlock(&irq->lock);
370 } else {
371 /* Spurious interrupt.*/
372 dprintf("cpu%d: spurious interrupt (inum=%d)\n",
373 CPU->id, i);
374 }
375 }
376 }
377}
378
379/** Returns address of framebuffer device.
380 *
381 * @return Address of framebuffer device.
382 */
383uintptr_t gxemul_get_fb_address(void)
384{
385 return (uintptr_t) GXEMUL_FB;
386}
387
388/** @}
389 */
Note: See TracBrowser for help on using the repository browser.