Implement resolution switching in common console code.
[qemu] / hw / jazz_led.c
1 /*
2  * QEMU JAZZ LED emulator.
3  *
4  * Copyright (c) 2007 HervĂ© Poussineau
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 #include "hw.h"
26 #include "mips.h"
27 #include "console.h"
28 #include "pixel_ops.h"
29
30 //#define DEBUG_LED
31
32 typedef enum {
33     REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
34 } screen_state_t;
35
36 typedef struct LedState {
37     target_phys_addr_t base;
38     uint8_t segments;
39     DisplayState *ds;
40     QEMUConsole *console;
41     screen_state_t state;
42 } LedState;
43
44 static uint32_t led_readb(void *opaque, target_phys_addr_t addr)
45 {
46     LedState *s = opaque;
47     int relative_addr = addr - s->base;
48     uint32_t val;
49
50     switch (relative_addr) {
51         case 0:
52             val = s->segments;
53             break;
54         default:
55 #ifdef DEBUG_LED
56             printf("jazz led: invalid read [0x%x]\n", relative_addr);
57 #endif
58             val = 0;
59     }
60
61     return val;
62 }
63
64 static uint32_t led_readw(void *opaque, target_phys_addr_t addr)
65 {
66     uint32_t v;
67 #ifdef TARGET_WORDS_BIGENDIAN
68     v = led_readb(opaque, addr) << 8;
69     v |= led_readb(opaque, addr + 1);
70 #else
71     v = led_readb(opaque, addr);
72     v |= led_readb(opaque, addr + 1) << 8;
73 #endif
74     return v;
75 }
76
77 static uint32_t led_readl(void *opaque, target_phys_addr_t addr)
78 {
79     uint32_t v;
80 #ifdef TARGET_WORDS_BIGENDIAN
81     v = led_readb(opaque, addr) << 24;
82     v |= led_readb(opaque, addr + 1) << 16;
83     v |= led_readb(opaque, addr + 2) << 8;
84     v |= led_readb(opaque, addr + 3);
85 #else
86     v = led_readb(opaque, addr);
87     v |= led_readb(opaque, addr + 1) << 8;
88     v |= led_readb(opaque, addr + 2) << 16;
89     v |= led_readb(opaque, addr + 3) << 24;
90 #endif
91     return v;
92 }
93
94 static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
95 {
96     LedState *s = opaque;
97     int relative_addr = addr - s->base;
98
99     switch (relative_addr) {
100         case 0:
101             s->segments = val;
102             s->state |= REDRAW_SEGMENTS;
103             break;
104         default:
105 #ifdef DEBUG_LED
106             printf("jazz led: invalid write of 0x%02x at [0x%x]\n", val, relative_addr);
107 #endif
108             break;
109     }
110 }
111
112 static void led_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
113 {
114 #ifdef TARGET_WORDS_BIGENDIAN
115     led_writeb(opaque, addr, (val >> 8) & 0xff);
116     led_writeb(opaque, addr + 1, val & 0xff);
117 #else
118     led_writeb(opaque, addr, val & 0xff);
119     led_writeb(opaque, addr + 1, (val >> 8) & 0xff);
120 #endif
121 }
122
123 static void led_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
124 {
125 #ifdef TARGET_WORDS_BIGENDIAN
126     led_writeb(opaque, addr, (val >> 24) & 0xff);
127     led_writeb(opaque, addr + 1, (val >> 16) & 0xff);
128     led_writeb(opaque, addr + 2, (val >> 8) & 0xff);
129     led_writeb(opaque, addr + 3, val & 0xff);
130 #else
131     led_writeb(opaque, addr, val & 0xff);
132     led_writeb(opaque, addr + 1, (val >> 8) & 0xff);
133     led_writeb(opaque, addr + 2, (val >> 16) & 0xff);
134     led_writeb(opaque, addr + 3, (val >> 24) & 0xff);
135 #endif
136 }
137
138 static CPUReadMemoryFunc *led_read[3] = {
139     led_readb,
140     led_readw,
141     led_readl,
142 };
143
144 static CPUWriteMemoryFunc *led_write[3] = {
145     led_writeb,
146     led_writew,
147     led_writel,
148 };
149
150 /***********************************************************/
151 /* jazz_led display */
152
153 static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx2, uint32_t color)
154 {
155     uint8_t *d;
156     int x, bpp;
157
158     bpp = (ds->depth + 7) >> 3;
159     d = ds->data + ds->linesize * posy + bpp * posx1;
160     switch(bpp) {
161         case 1:
162             for (x = posx1; x <= posx2; x++) {
163                 *((uint8_t *)d) = color;
164                 d++;
165             }
166             break;
167         case 2:
168             for (x = posx1; x <= posx2; x++) {
169                 *((uint16_t *)d) = color;
170                 d += 2;
171             }
172             break;
173         case 4:
174             for (x = posx1; x <= posx2; x++) {
175                 *((uint32_t *)d) = color;
176                 d += 4;
177             }
178             break;
179     }
180 }
181
182 static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, uint32_t color)
183 {
184     uint8_t *d;
185     int y, bpp;
186
187     bpp = (ds->depth + 7) >> 3;
188     d = ds->data + ds->linesize * posy1 + bpp * posx;
189     switch(bpp) {
190         case 1:
191             for (y = posy1; y <= posy2; y++) {
192                 *((uint8_t *)d) = color;
193                 d += ds->linesize;
194             }
195             break;
196         case 2:
197             for (y = posy1; y <= posy2; y++) {
198                 *((uint16_t *)d) = color;
199                 d += ds->linesize;
200             }
201             break;
202         case 4:
203             for (y = posy1; y <= posy2; y++) {
204                 *((uint32_t *)d) = color;
205                 d += ds->linesize;
206             }
207             break;
208     }
209 }
210
211 static void jazz_led_update_display(void *opaque)
212 {
213     LedState *s = opaque;
214     DisplayState *ds = s->ds;
215     uint8_t *d1;
216     uint32_t color_segment, color_led;
217     int y, bpp;
218
219     if (s->state & REDRAW_BACKGROUND) {
220         /* clear screen */
221         bpp = (ds->depth + 7) >> 3;
222         d1 = ds->data;
223         for (y = 0; y < ds->height; y++) {
224             memset(d1, 0x00, ds->width * bpp);
225             d1 += ds->linesize;
226         }
227     }
228
229     if (s->state & REDRAW_SEGMENTS) {
230         /* set colors according to bpp */
231         switch (ds->depth) {
232             case 8:
233                 color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa);
234                 color_led = rgb_to_pixel8(0x00, 0xff, 0x00);
235                 break;
236             case 15:
237                 color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa);
238                 color_led = rgb_to_pixel15(0x00, 0xff, 0x00);
239                 break;
240             case 16:
241                 color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa);
242                 color_led = rgb_to_pixel16(0x00, 0xff, 0x00);
243             case 24:
244                 color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa);
245                 color_led = rgb_to_pixel24(0x00, 0xff, 0x00);
246                 break;
247             case 32:
248                 color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa);
249                 color_led = rgb_to_pixel32(0x00, 0xff, 0x00);
250                 break;
251             default:
252                 return;
253         }
254
255         /* display segments */
256         draw_horizontal_line(ds, 40, 10, 40, (s->segments & 0x02) ? color_segment : 0);
257         draw_vertical_line(ds, 10, 10, 40, (s->segments & 0x04) ? color_segment : 0);
258         draw_vertical_line(ds, 10, 40, 70, (s->segments & 0x08) ? color_segment : 0);
259         draw_horizontal_line(ds, 70, 10, 40, (s->segments & 0x10) ? color_segment : 0);
260         draw_vertical_line(ds, 40, 40, 70, (s->segments & 0x20) ? color_segment : 0);
261         draw_vertical_line(ds, 40, 10, 40, (s->segments & 0x40) ? color_segment : 0);
262         draw_horizontal_line(ds, 10, 10, 40, (s->segments & 0x80) ? color_segment : 0);
263
264         /* display led */
265         if (!(s->segments & 0x01))
266             color_led = 0; /* black */
267         draw_horizontal_line(ds, 68, 50, 50, color_led);
268         draw_horizontal_line(ds, 69, 49, 51, color_led);
269         draw_horizontal_line(ds, 70, 48, 52, color_led);
270         draw_horizontal_line(ds, 71, 49, 51, color_led);
271         draw_horizontal_line(ds, 72, 50, 50, color_led);
272     }
273
274     s->state = REDRAW_NONE;
275     dpy_update(ds, 0, 0, ds->width, ds->height);
276 }
277
278 static void jazz_led_invalidate_display(void *opaque)
279 {
280     LedState *s = opaque;
281     s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND;
282 }
283
284 static void jazz_led_screen_dump(void *opaque, const char *filename)
285 {
286     printf("jazz_led_screen_dump() not implemented\n");
287 }
288
289 static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
290 {
291     LedState *s = opaque;
292     char buf[2];
293
294     dpy_cursor(s->ds, -1, -1);
295     qemu_console_resize(s->console, 2, 1);
296
297     /* TODO: draw the segments */
298     snprintf(buf, 2, "%02hhx\n", s->segments);
299     console_write_ch(chardata++, 0x00200100 | buf[0]);
300     console_write_ch(chardata++, 0x00200100 | buf[1]);
301
302     dpy_update(s->ds, 0, 0, 2, 1);
303 }
304
305 void jazz_led_init(DisplayState *ds, target_phys_addr_t base)
306 {
307     LedState *s;
308     int io;
309
310     s = qemu_mallocz(sizeof(LedState));
311     if (!s)
312         return;
313
314     s->base = base;
315     s->ds = ds;
316     s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
317
318     io = cpu_register_io_memory(0, led_read, led_write, s);
319     cpu_register_physical_memory(s->base, 1, io);
320
321     s->console = graphic_console_init(ds, jazz_led_update_display,
322                                      jazz_led_invalidate_display,
323                                      jazz_led_screen_dump,
324                                      jazz_led_text_update, s);
325     qemu_console_resize(s->console, 60, 80);
326 }