handle the case where several PCI irqs share the same PIC irq
[qemu] / hw / m48t59.c
index dd303d2..5ab5816 100644 (file)
@@ -24,9 +24,9 @@
 #include "vl.h"
 #include "m48t59.h"
 
-//#define NVRAM_DEBUG
+//#define DEBUG_NVRAM
 
-#if defined(NVRAM_DEBUG)
+#if defined(DEBUG_NVRAM)
 #define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
 #else
 #define NVRAM_PRINTF(fmt, args...) do { } while (0)
@@ -35,6 +35,8 @@
 struct m48t59_t {
     /* Hardware parameters */
     int      IRQ;
+    int mem_index;
+    uint32_t mem_base;
     uint32_t io_base;
     uint16_t size;
     /* RTC management */
@@ -45,6 +47,7 @@ struct m48t59_t {
     struct QEMUTimer *alrm_timer;
     struct QEMUTimer *wd_timer;
     /* NVRAM storage */
+    uint8_t  lock;
     uint16_t addr;
     uint8_t *buffer;
 };
@@ -67,7 +70,11 @@ static void get_time (m48t59_t *NVRAM, struct tm *tm)
     time_t t;
 
     t = time(NULL) + NVRAM->time_offset;
-    localtime_r(&t, tm);
+#ifdef _WIN32
+    memcpy(tm,localtime(&t),sizeof(*tm));
+#else
+    localtime_r (&t, tm) ;
+#endif
 }
 
 static void set_time (m48t59_t *NVRAM, struct tm *tm)
@@ -129,7 +136,11 @@ static void alarm_cb (void *opaque)
 
 static void get_alarm (m48t59_t *NVRAM, struct tm *tm)
 {
-    localtime_r(&NVRAM->alarm, tm);
+#ifdef _WIN32
+    memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm));
+#else
+    localtime_r (&NVRAM->alarm, tm);
+#endif
 }
 
 static void set_alarm (m48t59_t *NVRAM, struct tm *tm)
@@ -152,7 +163,8 @@ static void watchdog_cb (void *opaque)
     if (NVRAM->buffer[0x1FF7] & 0x80) {
        NVRAM->buffer[0x1FF7] = 0x00;
        NVRAM->buffer[0x1FFC] &= ~0x40;
-       //      reset_CPU();
+        /* May it be a hw CPU Reset instead ? */
+        qemu_system_reset_request();
     } else {
        pic_set_irq(NVRAM->IRQ, 1);
        pic_set_irq(NVRAM->IRQ, 0);
@@ -315,6 +327,11 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t val)
        }
         break;
     default:
+        /* Check lock registers state */
+        if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
+            break;
+        if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
+            break;
         if (NVRAM->addr < 0x1FF0 ||
            (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
             NVRAM->buffer[NVRAM->addr] = val & 0xFF;
@@ -394,6 +411,11 @@ uint32_t m48t59_read (m48t59_t *NVRAM)
         retval = toBCD(tm.tm_year);
         break;
     default:
+        /* Check lock registers state */
+        if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
+            break;
+        if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
+            break;
         if (NVRAM->addr < 0x1FF0 ||
            (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
        do_read:
@@ -412,12 +434,18 @@ void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr)
     NVRAM->addr = addr;
 }
 
+void m48t59_toggle_lock (m48t59_t *NVRAM, int lock)
+{
+    NVRAM->lock ^= 1 << lock;
+}
+
 /* IO access to NVRAM */
 static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
 {
     m48t59_t *NVRAM = opaque;
 
     addr -= NVRAM->io_base;
+    NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val);
     switch (addr) {
     case 0:
         NVRAM->addr &= ~0x00FF;
@@ -439,15 +467,111 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
 static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
 {
     m48t59_t *NVRAM = opaque;
+    uint32_t retval;
+
+    addr -= NVRAM->io_base;
+    switch (addr) {
+    case 3:
+        retval = m48t59_read(NVRAM);
+        break;
+    default:
+        retval = -1;
+        break;
+    }
+    NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
+
+    return retval;
+}
+
+static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    m48t59_t *NVRAM = opaque;
+    
+    addr -= NVRAM->mem_base;
+    if (addr < 0x1FF0)
+        NVRAM->buffer[addr] = value;
+}
+
+static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    m48t59_t *NVRAM = opaque;
+    
+    addr -= NVRAM->mem_base;
+    if (addr < 0x1FF0) {
+        NVRAM->buffer[addr] = value >> 8;
+        NVRAM->buffer[addr + 1] = value;
+    }
+}
+
+static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    m48t59_t *NVRAM = opaque;
+    
+    addr -= NVRAM->mem_base;
+    if (addr < 0x1FF0) {
+        NVRAM->buffer[addr] = value >> 24;
+        NVRAM->buffer[addr + 1] = value >> 16;
+        NVRAM->buffer[addr + 2] = value >> 8;
+        NVRAM->buffer[addr + 3] = value;
+    }
+}
+
+static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
+{
+    m48t59_t *NVRAM = opaque;
+    uint32_t retval = 0;
+    
+    addr -= NVRAM->mem_base;
+    if (addr < 0x1FF0)
+        retval = NVRAM->buffer[addr];
+
+    return retval;
+}
+
+static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
+{
+    m48t59_t *NVRAM = opaque;
+    uint32_t retval = 0;
+    
+    addr -= NVRAM->mem_base;
+    if (addr < 0x1FF0) {
+        retval = NVRAM->buffer[addr] << 8;
+        retval |= NVRAM->buffer[addr + 1];
+    }
 
-    if (addr == NVRAM->io_base + 3)
-        return m48t59_read(NVRAM);
+    return retval;
+}
 
-    return 0xFF;
+static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
+{
+    m48t59_t *NVRAM = opaque;
+    uint32_t retval = 0;
+    
+    addr -= NVRAM->mem_base;
+    if (addr < 0x1FF0) {
+        retval = NVRAM->buffer[addr] << 24;
+        retval |= NVRAM->buffer[addr + 1] << 16;
+        retval |= NVRAM->buffer[addr + 2] << 8;
+        retval |= NVRAM->buffer[addr + 3];
+    }
+
+    return retval;
 }
 
+static CPUWriteMemoryFunc *nvram_write[] = {
+    &nvram_writeb,
+    &nvram_writew,
+    &nvram_writel,
+};
+
+static CPUReadMemoryFunc *nvram_read[] = {
+    &nvram_readb,
+    &nvram_readw,
+    &nvram_readl,
+};
 /* Initialisation routine */
-m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size)
+m48t59_t *m48t59_init (int IRQ, uint32_t mem_base,
+                       uint32_t io_base, uint16_t size)
 {
     m48t59_t *s;
 
@@ -461,11 +585,18 @@ m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size)
     }
     s->IRQ = IRQ;
     s->size = size;
+    s->mem_base = mem_base;
     s->io_base = io_base;
     s->addr = 0;
     register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
     register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
+    if (mem_base != 0) {
+        s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
+        cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
+    }
     s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
     s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
+    s->lock = 0;
+
     return s;
 }