qemu

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

led.c (4448B)


      1 /*
      2  * QEMU single LED device
      3  *
      4  * Copyright (C) 2020 Philippe Mathieu-Daudé <f4bug@amsat.org>
      5  *
      6  * SPDX-License-Identifier: GPL-2.0-or-later
      7  */
      8 #include "qemu/osdep.h"
      9 #include "qapi/error.h"
     10 #include "migration/vmstate.h"
     11 #include "hw/qdev-properties.h"
     12 #include "hw/misc/led.h"
     13 #include "trace.h"
     14 
     15 #define LED_INTENSITY_PERCENT_MAX   100
     16 
     17 static const char * const led_color_name[] = {
     18     [LED_COLOR_VIOLET]  = "violet",
     19     [LED_COLOR_BLUE]    = "blue",
     20     [LED_COLOR_CYAN]    = "cyan",
     21     [LED_COLOR_GREEN]   = "green",
     22     [LED_COLOR_YELLOW]  = "yellow",
     23     [LED_COLOR_AMBER]   = "amber",
     24     [LED_COLOR_ORANGE]  = "orange",
     25     [LED_COLOR_RED]     = "red",
     26 };
     27 
     28 static bool led_color_name_is_valid(const char *color_name)
     29 {
     30     for (size_t i = 0; i < ARRAY_SIZE(led_color_name); i++) {
     31         if (strcmp(color_name, led_color_name[i]) == 0) {
     32             return true;
     33         }
     34     }
     35     return false;
     36 }
     37 
     38 void led_set_intensity(LEDState *s, unsigned intensity_percent)
     39 {
     40     if (intensity_percent > LED_INTENSITY_PERCENT_MAX) {
     41         intensity_percent = LED_INTENSITY_PERCENT_MAX;
     42     }
     43     trace_led_set_intensity(s->description, s->color, intensity_percent);
     44     if (intensity_percent != s->intensity_percent) {
     45         trace_led_change_intensity(s->description, s->color,
     46                                    s->intensity_percent, intensity_percent);
     47     }
     48     s->intensity_percent = intensity_percent;
     49 }
     50 
     51 unsigned led_get_intensity(LEDState *s)
     52 {
     53     return s->intensity_percent;
     54 }
     55 
     56 void led_set_state(LEDState *s, bool is_emitting)
     57 {
     58     led_set_intensity(s, is_emitting ? LED_INTENSITY_PERCENT_MAX : 0);
     59 }
     60 
     61 static void led_set_state_gpio_handler(void *opaque, int line, int new_state)
     62 {
     63     LEDState *s = LED(opaque);
     64 
     65     assert(line == 0);
     66     led_set_state(s, !!new_state != s->gpio_active_high);
     67 }
     68 
     69 static void led_reset(DeviceState *dev)
     70 {
     71     LEDState *s = LED(dev);
     72 
     73     led_set_state(s, s->gpio_active_high);
     74 }
     75 
     76 static const VMStateDescription vmstate_led = {
     77     .name = TYPE_LED,
     78     .version_id = 1,
     79     .minimum_version_id = 1,
     80     .fields = (VMStateField[]) {
     81         VMSTATE_UINT8(intensity_percent, LEDState),
     82         VMSTATE_END_OF_LIST()
     83     }
     84 };
     85 
     86 static void led_realize(DeviceState *dev, Error **errp)
     87 {
     88     LEDState *s = LED(dev);
     89 
     90     if (s->color == NULL) {
     91         error_setg(errp, "property 'color' not specified");
     92         return;
     93     } else if (!led_color_name_is_valid(s->color)) {
     94         error_setg(errp, "property 'color' invalid or not supported");
     95         return;
     96     }
     97     if (s->description == NULL) {
     98         s->description = g_strdup("n/a");
     99     }
    100 
    101     qdev_init_gpio_in(DEVICE(s), led_set_state_gpio_handler, 1);
    102 }
    103 
    104 static Property led_properties[] = {
    105     DEFINE_PROP_STRING("color", LEDState, color),
    106     DEFINE_PROP_STRING("description", LEDState, description),
    107     DEFINE_PROP_BOOL("gpio-active-high", LEDState, gpio_active_high, true),
    108     DEFINE_PROP_END_OF_LIST(),
    109 };
    110 
    111 static void led_class_init(ObjectClass *klass, void *data)
    112 {
    113     DeviceClass *dc = DEVICE_CLASS(klass);
    114 
    115     dc->desc = "LED";
    116     dc->vmsd = &vmstate_led;
    117     dc->reset = led_reset;
    118     dc->realize = led_realize;
    119     set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
    120     device_class_set_props(dc, led_properties);
    121 }
    122 
    123 static const TypeInfo led_info = {
    124     .name = TYPE_LED,
    125     .parent = TYPE_DEVICE,
    126     .instance_size = sizeof(LEDState),
    127     .class_init = led_class_init
    128 };
    129 
    130 static void led_register_types(void)
    131 {
    132     type_register_static(&led_info);
    133 }
    134 
    135 type_init(led_register_types)
    136 
    137 LEDState *led_create_simple(Object *parentobj,
    138                             GpioPolarity gpio_polarity,
    139                             LEDColor color,
    140                             const char *description)
    141 {
    142     g_autofree char *name = NULL;
    143     DeviceState *dev;
    144 
    145     dev = qdev_new(TYPE_LED);
    146     qdev_prop_set_bit(dev, "gpio-active-high",
    147                       gpio_polarity == GPIO_POLARITY_ACTIVE_HIGH);
    148     qdev_prop_set_string(dev, "color", led_color_name[color]);
    149     if (!description) {
    150         static unsigned undescribed_led_id;
    151         name = g_strdup_printf("undescribed-led-#%u", undescribed_led_id++);
    152     } else {
    153         qdev_prop_set_string(dev, "description", description);
    154         name = g_ascii_strdown(description, -1);
    155         name = g_strdelimit(name, " #", '-');
    156     }
    157     object_property_add_child(parentobj, name, OBJECT(dev));
    158     qdev_realize_and_unref(dev, NULL, &error_fatal);
    159 
    160     return LED(dev);
    161 }