qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

jazz_led.c (9432B)


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