Fix 32-bit overflow in parallels image support
[qemu-kvm/fedora.git] / hw / mcf_uart.c
blob8300fe832400d07e2eab92fcbc761b480f4c1f39
1 /*
2 * ColdFire UART emulation.
4 * Copyright (c) 2007 CodeSourcery.
6 * This code is licenced under the GPL
7 */
8 #include "hw.h"
9 #include "mcf.h"
10 #include "qemu-char.h"
12 typedef struct {
13 uint8_t mr[2];
14 uint8_t sr;
15 uint8_t isr;
16 uint8_t imr;
17 uint8_t bg1;
18 uint8_t bg2;
19 uint8_t fifo[4];
20 uint8_t tb;
21 int current_mr;
22 int fifo_len;
23 int tx_enabled;
24 int rx_enabled;
25 qemu_irq irq;
26 CharDriverState *chr;
27 } mcf_uart_state;
29 /* UART Status Register bits. */
30 #define MCF_UART_RxRDY 0x01
31 #define MCF_UART_FFULL 0x02
32 #define MCF_UART_TxRDY 0x04
33 #define MCF_UART_TxEMP 0x08
34 #define MCF_UART_OE 0x10
35 #define MCF_UART_PE 0x20
36 #define MCF_UART_FE 0x40
37 #define MCF_UART_RB 0x80
39 /* Interrupt flags. */
40 #define MCF_UART_TxINT 0x01
41 #define MCF_UART_RxINT 0x02
42 #define MCF_UART_DBINT 0x04
43 #define MCF_UART_COSINT 0x80
45 /* UMR1 flags. */
46 #define MCF_UART_BC0 0x01
47 #define MCF_UART_BC1 0x02
48 #define MCF_UART_PT 0x04
49 #define MCF_UART_PM0 0x08
50 #define MCF_UART_PM1 0x10
51 #define MCF_UART_ERR 0x20
52 #define MCF_UART_RxIRQ 0x40
53 #define MCF_UART_RxRTS 0x80
55 static void mcf_uart_update(mcf_uart_state *s)
57 s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
58 if (s->sr & MCF_UART_TxRDY)
59 s->isr |= MCF_UART_TxINT;
60 if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
61 ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
62 s->isr |= MCF_UART_RxINT;
64 qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
67 uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr)
69 mcf_uart_state *s = (mcf_uart_state *)opaque;
70 switch (addr & 0x3f) {
71 case 0x00:
72 return s->mr[s->current_mr];
73 case 0x04:
74 return s->sr;
75 case 0x0c:
77 uint8_t val;
78 int i;
80 if (s->fifo_len == 0)
81 return 0;
83 val = s->fifo[0];
84 s->fifo_len--;
85 for (i = 0; i < s->fifo_len; i++)
86 s->fifo[i] = s->fifo[i + 1];
87 s->sr &= ~MCF_UART_FFULL;
88 if (s->fifo_len == 0)
89 s->sr &= ~MCF_UART_RxRDY;
90 mcf_uart_update(s);
91 qemu_chr_accept_input(s->chr);
92 return val;
94 case 0x10:
95 /* TODO: Implement IPCR. */
96 return 0;
97 case 0x14:
98 return s->isr;
99 case 0x18:
100 return s->bg1;
101 case 0x1c:
102 return s->bg2;
103 default:
104 return 0;
108 /* Update TxRDY flag and set data if present and enabled. */
109 static void mcf_uart_do_tx(mcf_uart_state *s)
111 if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
112 if (s->chr)
113 qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1);
114 s->sr |= MCF_UART_TxEMP;
116 if (s->tx_enabled) {
117 s->sr |= MCF_UART_TxRDY;
118 } else {
119 s->sr &= ~MCF_UART_TxRDY;
123 static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
125 /* Misc command. */
126 switch ((cmd >> 4) & 3) {
127 case 0: /* No-op. */
128 break;
129 case 1: /* Reset mode register pointer. */
130 s->current_mr = 0;
131 break;
132 case 2: /* Reset receiver. */
133 s->rx_enabled = 0;
134 s->fifo_len = 0;
135 s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
136 break;
137 case 3: /* Reset transmitter. */
138 s->tx_enabled = 0;
139 s->sr |= MCF_UART_TxEMP;
140 s->sr &= ~MCF_UART_TxRDY;
141 break;
142 case 4: /* Reset error status. */
143 break;
144 case 5: /* Reset break-change interrupt. */
145 s->isr &= ~MCF_UART_DBINT;
146 break;
147 case 6: /* Start break. */
148 case 7: /* Stop break. */
149 break;
152 /* Transmitter command. */
153 switch ((cmd >> 2) & 3) {
154 case 0: /* No-op. */
155 break;
156 case 1: /* Enable. */
157 s->tx_enabled = 1;
158 mcf_uart_do_tx(s);
159 break;
160 case 2: /* Disable. */
161 s->tx_enabled = 0;
162 mcf_uart_do_tx(s);
163 break;
164 case 3: /* Reserved. */
165 fprintf(stderr, "mcf_uart: Bad TX command\n");
166 break;
169 /* Receiver command. */
170 switch (cmd & 3) {
171 case 0: /* No-op. */
172 break;
173 case 1: /* Enable. */
174 s->rx_enabled = 1;
175 break;
176 case 2:
177 s->rx_enabled = 0;
178 break;
179 case 3: /* Reserved. */
180 fprintf(stderr, "mcf_uart: Bad RX command\n");
181 break;
185 void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val)
187 mcf_uart_state *s = (mcf_uart_state *)opaque;
188 switch (addr & 0x3f) {
189 case 0x00:
190 s->mr[s->current_mr] = val;
191 s->current_mr = 1;
192 break;
193 case 0x04:
194 /* CSR is ignored. */
195 break;
196 case 0x08: /* Command Register. */
197 mcf_do_command(s, val);
198 break;
199 case 0x0c: /* Transmit Buffer. */
200 s->sr &= ~MCF_UART_TxEMP;
201 s->tb = val;
202 mcf_uart_do_tx(s);
203 break;
204 case 0x10:
205 /* ACR is ignored. */
206 break;
207 case 0x14:
208 s->imr = val;
209 break;
210 default:
211 break;
213 mcf_uart_update(s);
216 static void mcf_uart_reset(mcf_uart_state *s)
218 s->fifo_len = 0;
219 s->mr[0] = 0;
220 s->mr[1] = 0;
221 s->sr = MCF_UART_TxEMP;
222 s->tx_enabled = 0;
223 s->rx_enabled = 0;
224 s->isr = 0;
225 s->imr = 0;
228 static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
230 /* Break events overwrite the last byte if the fifo is full. */
231 if (s->fifo_len == 4)
232 s->fifo_len--;
234 s->fifo[s->fifo_len] = data;
235 s->fifo_len++;
236 s->sr |= MCF_UART_RxRDY;
237 if (s->fifo_len == 4)
238 s->sr |= MCF_UART_FFULL;
240 mcf_uart_update(s);
243 static void mcf_uart_event(void *opaque, int event)
245 mcf_uart_state *s = (mcf_uart_state *)opaque;
247 switch (event) {
248 case CHR_EVENT_BREAK:
249 s->isr |= MCF_UART_DBINT;
250 mcf_uart_push_byte(s, 0);
251 break;
252 default:
253 break;
257 static int mcf_uart_can_receive(void *opaque)
259 mcf_uart_state *s = (mcf_uart_state *)opaque;
261 return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
264 static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
266 mcf_uart_state *s = (mcf_uart_state *)opaque;
268 mcf_uart_push_byte(s, buf[0]);
271 void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
273 mcf_uart_state *s;
275 s = qemu_mallocz(sizeof(mcf_uart_state));
276 s->chr = chr;
277 s->irq = irq;
278 if (chr) {
279 qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
280 mcf_uart_event, s);
282 mcf_uart_reset(s);
283 return s;
287 static CPUReadMemoryFunc *mcf_uart_readfn[] = {
288 mcf_uart_read,
289 mcf_uart_read,
290 mcf_uart_read
293 static CPUWriteMemoryFunc *mcf_uart_writefn[] = {
294 mcf_uart_write,
295 mcf_uart_write,
296 mcf_uart_write
299 void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
300 CharDriverState *chr)
302 mcf_uart_state *s;
303 int iomemtype;
305 s = mcf_uart_init(irq, chr);
306 iomemtype = cpu_register_io_memory(mcf_uart_readfn,
307 mcf_uart_writefn, s);
308 cpu_register_physical_memory(base, 0x40, iomemtype);