xref: /openbmc/qemu/hw/display/jazz_led.c (revision b7163687)
1 /*
2  * QEMU JAZZ LED emulator.
3  *
4  * Copyright (c) 2007-2012 Herve 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 "qemu-common.h"
26 #include "ui/console.h"
27 #include "ui/pixel_ops.h"
28 #include "trace.h"
29 #include "hw/sysbus.h"
30 
31 typedef enum {
32     REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
33 } screen_state_t;
34 
35 typedef struct LedState {
36     SysBusDevice busdev;
37     MemoryRegion iomem;
38     uint8_t segments;
39     QemuConsole *con;
40     screen_state_t state;
41 } LedState;
42 
43 static uint64_t jazz_led_read(void *opaque, hwaddr addr,
44                               unsigned int size)
45 {
46     LedState *s = opaque;
47     uint8_t val;
48 
49     val = s->segments;
50     trace_jazz_led_read(addr, val);
51 
52     return val;
53 }
54 
55 static void jazz_led_write(void *opaque, hwaddr addr,
56                            uint64_t val, unsigned int size)
57 {
58     LedState *s = opaque;
59     uint8_t new_val = val & 0xff;
60 
61     trace_jazz_led_write(addr, new_val);
62 
63     s->segments = new_val;
64     s->state |= REDRAW_SEGMENTS;
65 }
66 
67 static const MemoryRegionOps led_ops = {
68     .read = jazz_led_read,
69     .write = jazz_led_write,
70     .endianness = DEVICE_NATIVE_ENDIAN,
71     .impl.min_access_size = 1,
72     .impl.max_access_size = 1,
73 };
74 
75 /***********************************************************/
76 /* jazz_led display */
77 
78 static void draw_horizontal_line(DisplaySurface *ds,
79                                  int posy, int posx1, int posx2,
80                                  uint32_t color)
81 {
82     uint8_t *d;
83     int x, bpp;
84 
85     bpp = (surface_bits_per_pixel(ds) + 7) >> 3;
86     d = surface_data(ds) + surface_stride(ds) * posy + bpp * posx1;
87     switch(bpp) {
88         case 1:
89             for (x = posx1; x <= posx2; x++) {
90                 *((uint8_t *)d) = color;
91                 d++;
92             }
93             break;
94         case 2:
95             for (x = posx1; x <= posx2; x++) {
96                 *((uint16_t *)d) = color;
97                 d += 2;
98             }
99             break;
100         case 4:
101             for (x = posx1; x <= posx2; x++) {
102                 *((uint32_t *)d) = color;
103                 d += 4;
104             }
105             break;
106     }
107 }
108 
109 static void draw_vertical_line(DisplaySurface *ds,
110                                int posx, int posy1, int posy2,
111                                uint32_t color)
112 {
113     uint8_t *d;
114     int y, bpp;
115 
116     bpp = (surface_bits_per_pixel(ds) + 7) >> 3;
117     d = surface_data(ds) + surface_stride(ds) * posy1 + bpp * posx;
118     switch(bpp) {
119         case 1:
120             for (y = posy1; y <= posy2; y++) {
121                 *((uint8_t *)d) = color;
122                 d += surface_stride(ds);
123             }
124             break;
125         case 2:
126             for (y = posy1; y <= posy2; y++) {
127                 *((uint16_t *)d) = color;
128                 d += surface_stride(ds);
129             }
130             break;
131         case 4:
132             for (y = posy1; y <= posy2; y++) {
133                 *((uint32_t *)d) = color;
134                 d += surface_stride(ds);
135             }
136             break;
137     }
138 }
139 
140 static void jazz_led_update_display(void *opaque)
141 {
142     LedState *s = opaque;
143     DisplaySurface *surface = qemu_console_surface(s->con);
144     uint8_t *d1;
145     uint32_t color_segment, color_led;
146     int y, bpp;
147 
148     if (s->state & REDRAW_BACKGROUND) {
149         /* clear screen */
150         bpp = (surface_bits_per_pixel(surface) + 7) >> 3;
151         d1 = surface_data(surface);
152         for (y = 0; y < surface_height(surface); y++) {
153             memset(d1, 0x00, surface_width(surface) * bpp);
154             d1 += surface_stride(surface);
155         }
156     }
157 
158     if (s->state & REDRAW_SEGMENTS) {
159         /* set colors according to bpp */
160         switch (surface_bits_per_pixel(surface)) {
161             case 8:
162                 color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa);
163                 color_led = rgb_to_pixel8(0x00, 0xff, 0x00);
164                 break;
165             case 15:
166                 color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa);
167                 color_led = rgb_to_pixel15(0x00, 0xff, 0x00);
168                 break;
169             case 16:
170                 color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa);
171                 color_led = rgb_to_pixel16(0x00, 0xff, 0x00);
172             case 24:
173                 color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa);
174                 color_led = rgb_to_pixel24(0x00, 0xff, 0x00);
175                 break;
176             case 32:
177                 color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa);
178                 color_led = rgb_to_pixel32(0x00, 0xff, 0x00);
179                 break;
180             default:
181                 return;
182         }
183 
184         /* display segments */
185         draw_horizontal_line(surface, 40, 10, 40,
186                              (s->segments & 0x02) ? color_segment : 0);
187         draw_vertical_line(surface, 10, 10, 40,
188                            (s->segments & 0x04) ? color_segment : 0);
189         draw_vertical_line(surface, 10, 40, 70,
190                            (s->segments & 0x08) ? color_segment : 0);
191         draw_horizontal_line(surface, 70, 10, 40,
192                              (s->segments & 0x10) ? color_segment : 0);
193         draw_vertical_line(surface, 40, 40, 70,
194                            (s->segments & 0x20) ? color_segment : 0);
195         draw_vertical_line(surface, 40, 10, 40,
196                            (s->segments & 0x40) ? color_segment : 0);
197         draw_horizontal_line(surface, 10, 10, 40,
198                              (s->segments & 0x80) ? color_segment : 0);
199 
200         /* display led */
201         if (!(s->segments & 0x01))
202             color_led = 0; /* black */
203         draw_horizontal_line(surface, 68, 50, 50, color_led);
204         draw_horizontal_line(surface, 69, 49, 51, color_led);
205         draw_horizontal_line(surface, 70, 48, 52, color_led);
206         draw_horizontal_line(surface, 71, 49, 51, color_led);
207         draw_horizontal_line(surface, 72, 50, 50, color_led);
208     }
209 
210     s->state = REDRAW_NONE;
211     dpy_gfx_update(s->con, 0, 0,
212                    surface_width(surface), surface_height(surface));
213 }
214 
215 static void jazz_led_invalidate_display(void *opaque)
216 {
217     LedState *s = opaque;
218     s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND;
219 }
220 
221 static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
222 {
223     LedState *s = opaque;
224     char buf[2];
225 
226     dpy_text_cursor(s->con, -1, -1);
227     qemu_console_resize(s->con, 2, 1);
228 
229     /* TODO: draw the segments */
230     snprintf(buf, 2, "%02hhx\n", s->segments);
231     console_write_ch(chardata++, 0x00200100 | buf[0]);
232     console_write_ch(chardata++, 0x00200100 | buf[1]);
233 
234     dpy_text_update(s->con, 0, 0, 2, 1);
235 }
236 
237 static int jazz_led_post_load(void *opaque, int version_id)
238 {
239     /* force refresh */
240     jazz_led_invalidate_display(opaque);
241 
242     return 0;
243 }
244 
245 static const VMStateDescription vmstate_jazz_led = {
246     .name = "jazz-led",
247     .version_id = 0,
248     .minimum_version_id = 0,
249     .minimum_version_id_old = 0,
250     .post_load = jazz_led_post_load,
251     .fields = (VMStateField[]) {
252         VMSTATE_UINT8(segments, LedState),
253         VMSTATE_END_OF_LIST()
254     }
255 };
256 
257 static const GraphicHwOps jazz_led_ops = {
258     .invalidate  = jazz_led_invalidate_display,
259     .gfx_update  = jazz_led_update_display,
260     .text_update = jazz_led_text_update,
261 };
262 
263 static int jazz_led_init(SysBusDevice *dev)
264 {
265     LedState *s = FROM_SYSBUS(LedState, dev);
266 
267     memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1);
268     sysbus_init_mmio(dev, &s->iomem);
269 
270     s->con = graphic_console_init(DEVICE(dev), &jazz_led_ops, s);
271 
272     return 0;
273 }
274 
275 static void jazz_led_reset(DeviceState *d)
276 {
277     LedState *s = DO_UPCAST(LedState, busdev.qdev, d);
278 
279     s->segments = 0;
280     s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
281     qemu_console_resize(s->con, 60, 80);
282 }
283 
284 static void jazz_led_class_init(ObjectClass *klass, void *data)
285 {
286     DeviceClass *dc = DEVICE_CLASS(klass);
287     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
288 
289     k->init = jazz_led_init;
290     dc->desc = "Jazz LED display",
291     dc->vmsd = &vmstate_jazz_led;
292     dc->reset = jazz_led_reset;
293 }
294 
295 static const TypeInfo jazz_led_info = {
296     .name          = "jazz-led",
297     .parent        = TYPE_SYS_BUS_DEVICE,
298     .instance_size = sizeof(LedState),
299     .class_init    = jazz_led_class_init,
300 };
301 
302 static void jazz_led_register(void)
303 {
304     type_register_static(&jazz_led_info);
305 }
306 
307 type_init(jazz_led_register);
308