Ignore:
Timestamp:
2009-03-12T23:26:32Z (16 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
648c9d9
Parents:
3b122e9
Message:

arm32: update for the new scheme of device drivers and keyboard/serial modules
streamline arm32 port (as GXemul is still the only machine supported), more cleanup is needed

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/arm32/src/drivers/gxemul.c

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