Statistics
| Branch: | Revision:

root / hw / pl050.c @ 92d88ecb

History | View | Annotate | Download (3 kB)

1
/* 
2
 * Arm PrimeCell PL050 Keyboard / Mouse Interface
3
 *
4
 * Copyright (c) 2006 CodeSourcery.
5
 * Written by Paul Brook
6
 *
7
 * This code is licenced under the GPL.
8
 */
9

    
10
#include "vl.h"
11

    
12
typedef struct {
13
    void *dev;
14
    uint32_t base;
15
    uint32_t cr;
16
    uint32_t clk;
17
    uint32_t last;
18
    int pending;
19
    qemu_irq irq;
20
    int is_mouse;
21
} pl050_state;
22

    
23
static const unsigned char pl050_id[] =
24
{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
25

    
26
static void pl050_update(void *opaque, int level)
27
{
28
    pl050_state *s = (pl050_state *)opaque;
29
    int raise;
30

    
31
    s->pending = level;
32
    raise = (s->pending && (s->cr & 0x10) != 0)
33
            || (s->cr & 0x08) != 0;
34
    qemu_set_irq(s->irq, raise);
35
}
36

    
37
static uint32_t pl050_read(void *opaque, target_phys_addr_t offset)
38
{
39
    pl050_state *s = (pl050_state *)opaque;
40
    offset -= s->base;
41
    if (offset >= 0xfe0 && offset < 0x1000)
42
        return pl050_id[(offset - 0xfe0) >> 2];
43

    
44
    switch (offset >> 2) {
45
    case 0: /* KMICR */
46
        return s->cr;
47
    case 1: /* KMISTAT */
48
        /* KMIC and KMID bits not implemented.  */
49
        if (s->pending) {
50
            return 0x10;
51
        } else {
52
            return 0;
53
        }
54
    case 2: /* KMIDATA */
55
        if (s->pending)
56
            s->last = ps2_read_data(s->dev);
57
        return s->last;
58
    case 3: /* KMICLKDIV */
59
        return s->clk;
60
    case 4: /* KMIIR */
61
        return s->pending | 2;
62
    default:
63
        cpu_abort (cpu_single_env, "pl050_read: Bad offset %x\n", offset);
64
        return 0;
65
    }
66
}
67

    
68
static void pl050_write(void *opaque, target_phys_addr_t offset,
69
                          uint32_t value)
70
{
71
    pl050_state *s = (pl050_state *)opaque;
72
    offset -= s->base;
73
    switch (offset >> 2) {
74
    case 0: /* KMICR */
75
        s->cr = value;
76
        pl050_update(s, s->pending);
77
        /* ??? Need to implement the enable/disable bit.  */
78
        break;
79
    case 2: /* KMIDATA */
80
        /* ??? This should toggle the TX interrupt line.  */
81
        /* ??? This means kbd/mouse can block each other.  */
82
        if (s->is_mouse) {
83
            ps2_write_mouse(s->dev, value);
84
        } else {
85
            ps2_write_keyboard(s->dev, value);
86
        }
87
        break;
88
    case 3: /* KMICLKDIV */
89
        s->clk = value;
90
        return;
91
    default:
92
        cpu_abort (cpu_single_env, "pl050_write: Bad offset %x\n", offset);
93
    }
94
}
95
static CPUReadMemoryFunc *pl050_readfn[] = {
96
   pl050_read,
97
   pl050_read,
98
   pl050_read
99
};
100

    
101
static CPUWriteMemoryFunc *pl050_writefn[] = {
102
   pl050_write,
103
   pl050_write,
104
   pl050_write
105
};
106

    
107
void pl050_init(uint32_t base, qemu_irq irq, int is_mouse)
108
{
109
    int iomemtype;
110
    pl050_state *s;
111

    
112
    s = (pl050_state *)qemu_mallocz(sizeof(pl050_state));
113
    iomemtype = cpu_register_io_memory(0, pl050_readfn,
114
                                       pl050_writefn, s);
115
    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
116
    s->base = base;
117
    s->irq = irq;
118
    s->is_mouse = is_mouse;
119
    if (is_mouse)
120
        s->dev = ps2_mouse_init(pl050_update, s);
121
    else
122
        s->dev = ps2_kbd_init(pl050_update, s);
123
    /* ??? Save/restore.  */
124
}
125