Statistics
| Branch: | Revision:

root / hw / pl050.c @ 09b26c5e

History | View | Annotate | Download (3.1 kB)

1
/* 
2
 * Arm PrimeCell PL050 Kyeboard / 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
    void *pic;
19
    int pending;
20
    int irq;
21
    int is_mouse;
22
} pl050_state;
23

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

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

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

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

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

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

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

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

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