]> git.proxmox.com Git - qemu.git/blob - hw/pxa2xx_pcmcia.c
Fix off-by-one memory region sizes.
[qemu.git] / hw / pxa2xx_pcmcia.c
1 /*
2 * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
3 *
4 * Copyright (c) 2006 Openedhand Ltd.
5 * Written by Andrzej Zaborowski <balrog@zabor.org>
6 *
7 * This code is licensed under the GPLv2.
8 */
9
10 #include "vl.h"
11
12 struct pxa2xx_pcmcia_s {
13 struct pcmcia_socket_s slot;
14 struct pcmcia_card_s *card;
15 target_phys_addr_t common_base;
16 target_phys_addr_t attr_base;
17 target_phys_addr_t io_base;
18
19 qemu_irq irq;
20 qemu_irq cd_irq;
21 };
22
23 static uint32_t pxa2xx_pcmcia_common_read(void *opaque,
24 target_phys_addr_t offset)
25 {
26 struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
27
28 if (s->slot.attached) {
29 offset -= s->common_base;
30 return s->card->common_read(s->card->state, offset);
31 }
32
33 return 0;
34 }
35
36 static void pxa2xx_pcmcia_common_write(void *opaque,
37 target_phys_addr_t offset, uint32_t value)
38 {
39 struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
40
41 if (s->slot.attached) {
42 offset -= s->common_base;
43 s->card->common_write(s->card->state, offset, value);
44 }
45 }
46
47 static uint32_t pxa2xx_pcmcia_attr_read(void *opaque,
48 target_phys_addr_t offset)
49 {
50 struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
51
52 if (s->slot.attached) {
53 offset -= s->attr_base;
54 return s->card->attr_read(s->card->state, offset);
55 }
56
57 return 0;
58 }
59
60 static void pxa2xx_pcmcia_attr_write(void *opaque,
61 target_phys_addr_t offset, uint32_t value)
62 {
63 struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
64
65 if (s->slot.attached) {
66 offset -= s->attr_base;
67 s->card->attr_write(s->card->state, offset, value);
68 }
69 }
70
71 static uint32_t pxa2xx_pcmcia_io_read(void *opaque,
72 target_phys_addr_t offset)
73 {
74 struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
75
76 if (s->slot.attached) {
77 offset -= s->io_base;
78 return s->card->io_read(s->card->state, offset);
79 }
80
81 return 0;
82 }
83
84 static void pxa2xx_pcmcia_io_write(void *opaque,
85 target_phys_addr_t offset, uint32_t value)
86 {
87 struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
88
89 if (s->slot.attached) {
90 offset -= s->io_base;
91 s->card->io_write(s->card->state, offset, value);
92 }
93 }
94
95 static CPUReadMemoryFunc *pxa2xx_pcmcia_common_readfn[] = {
96 pxa2xx_pcmcia_common_read,
97 pxa2xx_pcmcia_common_read,
98 pxa2xx_pcmcia_common_read,
99 };
100
101 static CPUWriteMemoryFunc *pxa2xx_pcmcia_common_writefn[] = {
102 pxa2xx_pcmcia_common_write,
103 pxa2xx_pcmcia_common_write,
104 pxa2xx_pcmcia_common_write,
105 };
106
107 static CPUReadMemoryFunc *pxa2xx_pcmcia_attr_readfn[] = {
108 pxa2xx_pcmcia_attr_read,
109 pxa2xx_pcmcia_attr_read,
110 pxa2xx_pcmcia_attr_read,
111 };
112
113 static CPUWriteMemoryFunc *pxa2xx_pcmcia_attr_writefn[] = {
114 pxa2xx_pcmcia_attr_write,
115 pxa2xx_pcmcia_attr_write,
116 pxa2xx_pcmcia_attr_write,
117 };
118
119 static CPUReadMemoryFunc *pxa2xx_pcmcia_io_readfn[] = {
120 pxa2xx_pcmcia_io_read,
121 pxa2xx_pcmcia_io_read,
122 pxa2xx_pcmcia_io_read,
123 };
124
125 static CPUWriteMemoryFunc *pxa2xx_pcmcia_io_writefn[] = {
126 pxa2xx_pcmcia_io_write,
127 pxa2xx_pcmcia_io_write,
128 pxa2xx_pcmcia_io_write,
129 };
130
131 static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
132 {
133 struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
134 if (!s->irq)
135 return;
136
137 qemu_set_irq(s->irq, level);
138 }
139
140 struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base)
141 {
142 int iomemtype;
143 struct pxa2xx_pcmcia_s *s;
144
145 s = (struct pxa2xx_pcmcia_s *)
146 qemu_mallocz(sizeof(struct pxa2xx_pcmcia_s));
147
148 /* Socket I/O Memory Space */
149 s->io_base = base | 0x00000000;
150 iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_io_readfn,
151 pxa2xx_pcmcia_io_writefn, s);
152 cpu_register_physical_memory(s->io_base, 0x04000000, iomemtype);
153
154 /* Then next 64 MB is reserved */
155
156 /* Socket Attribute Memory Space */
157 s->attr_base = base | 0x08000000;
158 iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_attr_readfn,
159 pxa2xx_pcmcia_attr_writefn, s);
160 cpu_register_physical_memory(s->attr_base, 0x04000000, iomemtype);
161
162 /* Socket Common Memory Space */
163 s->common_base = base | 0x0c000000;
164 iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_common_readfn,
165 pxa2xx_pcmcia_common_writefn, s);
166 cpu_register_physical_memory(s->common_base, 0x04000000, iomemtype);
167
168 if (base == 0x30000000)
169 s->slot.slot_string = "PXA PC Card Socket 1";
170 else
171 s->slot.slot_string = "PXA PC Card Socket 0";
172 s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
173 pcmcia_socket_register(&s->slot);
174
175 return s;
176 }
177
178 /* Insert a new card into a slot */
179 int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card)
180 {
181 struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
182 if (s->slot.attached)
183 return -EEXIST;
184
185 if (s->cd_irq) {
186 qemu_irq_raise(s->cd_irq);
187 }
188
189 s->card = card;
190
191 s->slot.attached = 1;
192 s->card->slot = &s->slot;
193 s->card->attach(s->card->state);
194
195 return 0;
196 }
197
198 /* Eject card from the slot */
199 int pxa2xx_pcmcia_dettach(void *opaque)
200 {
201 struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
202 if (!s->slot.attached)
203 return -ENOENT;
204
205 s->card->detach(s->card->state);
206 s->card->slot = 0;
207 s->card = 0;
208
209 s->slot.attached = 0;
210
211 if (s->irq)
212 qemu_irq_lower(s->irq);
213 if (s->cd_irq)
214 qemu_irq_lower(s->cd_irq);
215
216 return 0;
217 }
218
219 /* Who to notify on card events */
220 void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
221 {
222 struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
223 s->irq = irq;
224 s->cd_irq = cd_irq;
225 }