From patchwork Tue Jun 16 14:15:54 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liviu Ionescu X-Patchwork-Id: 485023 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 62A8014027C for ; Wed, 17 Jun 2015 00:16:41 +1000 (AEST) Received: from localhost ([::1]:40460 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z4rfL-0001go-7m for incoming@patchwork.ozlabs.org; Tue, 16 Jun 2015 10:16:39 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53597) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z4rem-0000jE-AO for Qemu-devel@nongnu.org; Tue, 16 Jun 2015 10:16:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Z4rej-0008PP-Hf for Qemu-devel@nongnu.org; Tue, 16 Jun 2015 10:16:04 -0400 Received: from mail-wg0-f45.google.com ([74.125.82.45]:34570) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z4rej-0008P3-9p for Qemu-devel@nongnu.org; Tue, 16 Jun 2015 10:16:01 -0400 Received: by wgv5 with SMTP id 5so13381982wgv.1 for ; Tue, 16 Jun 2015 07:16:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:content-type:content-transfer-encoding :subject:date:message-id:cc:to:mime-version; bh=o/cptFr7bia0BTiMcWpRtP02iNrpFMFLBIZ5piwX2ts=; b=ml4kaTRxaFzIiS2/4oiG1Eifr0f7tzL9ONgZH0IeF46YDdVNtcGHpxVDr/EstPXm31 9aBql8uka53yK1Osl19Ho94Es0Y/ufYbiLgoq4eBhIXNJoMlr6T3usrpzxhaKm6MLFcz pS5LIaKejT2Pf74ypOBZ6NjFir3VdGz003sHXI0OzMdgk6Og9oeHIpC4WIpr8y2089pJ hNk7BddmJAoQytTrzjk4v49EHt1zhAgTqIbOzNSHSFvq0MYKN3/kKQM4F2VRkFAFv4Xz Li730fYTO+DKNf4U9JxuzUHWLeBERAXsF2jFKFnJOvmt7AQ/9jO6FWgD9YPQx6Gj23l1 xreQ== X-Gm-Message-State: ALoCoQkvlU77zwHxsx1Jo0wWqV40bvyPItB+bELyZcpZAx87cJ1VrG2EG5N0M7lfQjPNmlIX2UEF X-Received: by 10.180.81.194 with SMTP id c2mr7153149wiy.94.1434464160442; Tue, 16 Jun 2015 07:16:00 -0700 (PDT) Received: from [172.16.62.12] ([109.99.239.84]) by mx.google.com with ESMTPSA id i6sm1867829wjf.29.2015.06.16.07.15.58 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 16 Jun 2015 07:15:59 -0700 (PDT) From: Liviu Ionescu Date: Tue, 16 Jun 2015 17:15:54 +0300 Message-Id: <499A9B83-4600-4B16-ACA2-C7AAE2C472B3@livius.net> To: QEMU Developers Mime-Version: 1.0 (Mac OS X Mail 8.2 \(2098\)) X-Mailer: Apple Mail (2.2098) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 74.125.82.45 Cc: Peter Maydell , Peter Crosthwaite Subject: [Qemu-devel] [RFC] generic-gpio-led & stm32-gpio-led X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org # Intro For my multiple Cortex-M boards, I need a LED device that will display a message when a GPIO bit is written. # Goal The goal is to pack the LED into an object that is very easy to instantiate and configure. # Solution My solution is an abstract class "generic-gpio-led" and derived classes like "stm32-gpio-led" that implements the specifics of a certain Cortex-M family. The derived class doesn't have to do much, just to return the desired GPIO device from the specific MCU. The abstract class includes the construction logic, the connection logic and the parametrised handler used to blink the LED. # Usage The LED instantiation is very simple, the object is created using a structure that packs all LED specifics and a reference to the MCU: GenericGPIOLEDInfo h103_machine_green_led = { .desc = "STM32-H103 Green LED, GPIOC[12], active low", .port_index = STM32_GPIO_PORT_C, .port_bit = 12, .active_low = true, .on_message = "[Green LED On]\n", .off_message = "[Green LED Off]\n", .use_stderr = true }; static void stm32_h103_board_init_callback(MachineState *machine) { ... DeviceState *led = qdev_alloc(NULL, TYPE_STM32_GPIO_LED); { STM32_GPIO_LED_GET_CLASS(led)->construct(OBJECT(led), &h103_machine_green_led, mcu); } qdev_realize(led); } diff --git a/include/hw/display/generic-gpio-led.h b/include/hw/display/generic-gpio-led.h new file mode 100644 index 0000000..e84ec0e --- /dev/null +++ b/include/hw/display/generic-gpio-led.h @@ -0,0 +1,96 @@ +/* + * Generic GPIO connected LED device emulation. + * + * Copyright (c) 2015 Liviu Ionescu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef GENERIC_GPIO_LED_H_ +#define GENERIC_GPIO_LED_H_ + +#include "hw/qdev.h" +#include "qemu/typedefs.h" + +/* ------------------------------------------------------------------------- */ + +#define DEFINE_PROP_GENERIC_GPIO_LED_PTR(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, GenericGPIOLEDInfo*) + +/** + * This structure must be passed via the constructor, to configure the + * LED connectivity, logic and message. + */ +typedef struct { + const char *desc; + int port_index; + int port_bit; // + bool active_low; + const char *on_message; + const char *off_message; // + bool use_stderr; +} GenericGPIOLEDInfo; + +/* ------------------------------------------------------------------------- */ + +#define TYPE_GENERIC_GPIO_LED "generic-gpio-led" + +#define GENERIC_GPIO_LED_GET_CLASS(obj) \ + OBJECT_GET_CLASS(GenericGPIOLEDClass, (obj), TYPE_GENERIC_GPIO_LED) +#define GENERIC_GPIO_LED_CLASS(klass) \ + OBJECT_CLASS_CHECK(GenericGPIOLEDClass, (klass), TYPE_GENERIC_GPIO_LED) + +typedef struct { + /*< private >*/ + DeviceClass parent_class; + /*< public >*/ + + /** + * Constructor; it uses the Info structure and a pointer to the MCU + * to get the GPIO(n) port and to connect to the pin. + */ + void (*construct)(Object *obj, GenericGPIOLEDInfo* info, DeviceState *mcu); + + /** + * Abstract function, to be implemented by all derived classes. + */ + DeviceState *(*get_gpio_dev)(DeviceState *dev, int port_index); +} GenericGPIOLEDClass; + +/* ------------------------------------------------------------------------- */ + +#define GENERIC_GPIO_LED_STATE(obj) \ + OBJECT_CHECK(GenericGPIOLEDState, (obj), TYPE_GENERIC_GPIO_LED) + +typedef struct { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + + GenericGPIOLEDInfo *info; + + DeviceState *mcu; + DeviceState *gpio; + + /** + * The actual irq used to blink the LED. It works connected to + * a GPIO device outgoing irq. + */ + qemu_irq irq; + +} GenericGPIOLEDState; + +/* ------------------------------------------------------------------------- */ + +#endif /* GENERIC_GPIO_LED_H_ */ diff --git a/hw/display/generic-gpio-led.c b/hw/display/generic-gpio-led.c new file mode 100644 index 0000000..a5875ea --- /dev/null +++ b/hw/display/generic-gpio-led.c @@ -0,0 +1,122 @@ +/* + * Generic GPIO connected LED device emulation. + * + * Copyright (c) 2015 Liviu Ionescu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "hw/display/generic-gpio-led.h" + +/** + * This is an abstract class that implements a generic LED connected to + * a GPIO device. It requires a derived class to implement the get_gpio_dev() + * virtual call, to access the actual GPIO device specific to a family. + */ + +static void generic_gpio_led_irq_handler(void *opaque, int n, int level) +{ + GenericGPIOLEDInfo *info = GENERIC_GPIO_LED_STATE(opaque)->info; + + /* There should be only one IRQ for the LED */ + assert(n == 0); + + FILE *file; + if (info->use_stderr) { + file = stderr; + } else { + file = stdout; + } + /* + * Assume that the IRQ is only triggered if the LED has changed state. + * If this is not correct, we may get multiple LED Offs or Ons in a row. + */ + switch (level) { + case 0: + fprintf(file, "%s", + info->active_low ? info->on_message : info->off_message); + break; + + case 1: + fprintf(file, "%s", + info->active_low ? info->off_message : info->on_message); + break; + } +} + +static void generic_gpio_led_construct_callback(Object *obj, + GenericGPIOLEDInfo* info, DeviceState *mcu) +{ + qemu_log_function_name(); + + GenericGPIOLEDState *state = GENERIC_GPIO_LED_STATE(obj); + GenericGPIOLEDClass *klass = GENERIC_GPIO_LED_GET_CLASS(state); + + state->info = info; + state->mcu = mcu; + + DeviceState *gpio_dev = klass->get_gpio_dev(DEVICE(obj), info->port_index); + assert(gpio_dev); + + /* + * Allocate 1 single incoming irq, and attach handler, this device + * and n=0. (n==0 is checked in the handler by an assert) + */ + state->irq = qemu_allocate_irq(generic_gpio_led_irq_handler, obj, 0); + + /* + * Connect the LED interrupt to the originating GPIO pin. + * This will finally create a link inside the STM32 GPIO device. + */ + qdev_connect_gpio_out(gpio_dev, info->port_bit, state->irq); +} + +static void generic_gpio_led_realize_callback(DeviceState *dev, Error **errp) +{ + qemu_log_function_name(); +} + +#define DEFINE_PROP_DEVICE_STATE_PTR(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, DeviceState*) + +static Property generic_gpio_led_properties[] = { + DEFINE_PROP_GENERIC_GPIO_LED_PTR("info", GenericGPIOLEDState, info), + DEFINE_PROP_DEVICE_STATE_PTR("mcu", GenericGPIOLEDState, mcu), + DEFINE_PROP_END_OF_LIST() }; + +static void generic_gpio_led_class_init_callback(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->props = generic_gpio_led_properties; + dc->realize = generic_gpio_led_realize_callback; + + GenericGPIOLEDClass *gl_class = GENERIC_GPIO_LED_CLASS(klass); + gl_class->construct = generic_gpio_led_construct_callback; +} + +static const TypeInfo generic_gpio_led_type_info = { + .abstract = true, + .name = TYPE_GENERIC_GPIO_LED, + .parent = TYPE_DEVICE, + .instance_size = sizeof(GenericGPIOLEDState), + .class_init = generic_gpio_led_class_init_callback, + .class_size = sizeof(GenericGPIOLEDClass) }; + +static void generic_gpio_led_type_init() +{ + type_register_static(&generic_gpio_led_type_info); +} + +type_init(generic_gpio_led_type_init); diff --git a/include/hw/display/stm32-gpio-led.h b/include/hw/display/stm32-gpio-led.h new file mode 100644 index 0000000..f1bb581 --- /dev/null +++ b/include/hw/display/stm32-gpio-led.h @@ -0,0 +1,61 @@ +/* + * STM32 GPIO connected LED device emulation. + * + * Copyright (c) 2015 Liviu Ionescu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef STM32_GPIO_LED_H_ +#define STM32_GPIO_LED_H_ + +#include "hw/display/generic-gpio-led.h" + +/* ------------------------------------------------------------------------- */ + +#define TYPE_STM32_GPIO_LED "stm32-gpio-led" + +#define STM32_GPIO_LED_GET_CLASS(obj) \ + OBJECT_GET_CLASS(STM32GPIOLEDClass, (obj), TYPE_STM32_GPIO_LED) +#define STM32_GPIO_LED_CLASS(klass) \ + OBJECT_CLASS_CHECK(STM32GPIOLEDClass, (klass), TYPE_STM32_GPIO_LED) + +typedef struct { + /*< private >*/ + GenericGPIOLEDClass parent_class; + /*< public >*/ + + /** + * Constructor; does not much, just passes the Info structure + * and a pointer to the MCU to the base class. + */ + void (*construct)(Object *obj, GenericGPIOLEDInfo* info, DeviceState *mcu); +} STM32GPIOLEDClass; + +/* ------------------------------------------------------------------------- */ + +#define STM32_GPIO_LED_STATE(obj) \ + OBJECT_CHECK(STM32GPIOState, (obj), TYPE_GENERIC_GPIO_LED) + +typedef struct { + /*< private >*/ + GenericGPIOLEDState parent_obj; + /*< public >*/ + + /* Currently there is nothing new here. */ +} STM32GPIOLEDState; + +/* ------------------------------------------------------------------------- */ + +#endif /* STM32_GPIO_LED_H_ */ diff --git a/hw/display/stm32-gpio-led.c b/hw/display/stm32-gpio-led.c new file mode 100644 index 0000000..9438efe --- /dev/null +++ b/hw/display/stm32-gpio-led.c @@ -0,0 +1,76 @@ +/* + * STM32 LED device emulation. + * + * Copyright (c) 2015 Liviu Ionescu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "hw/display/stm32-gpio-led.h" +#include "hw/arm/stm32-mcu.h" + +/** + * Implementation of the "generic-gpio-led" base class for the STM32 family. + */ + +/** + * Implementation of the parent class virtual function. + * It mainly returns a pointer to the device GPIO[i]. + */ +static DeviceState *stm32_gpio_led_get_gpio_dev(DeviceState *dev, + int port_index) +{ + GenericGPIOLEDState *gl_state = GENERIC_GPIO_LED_STATE(dev); + + /** + * Ask the MCU for the i-th (port_index) GPIO device. + */ + return stm32_mcu_get_gpio_dev(gl_state->mcu, port_index); +} + +static void stm_gpio_led_construct_callback(Object *obj, + GenericGPIOLEDInfo* info, DeviceState *mcu) +{ + qemu_log_function_name(); + + /* Explicitly call the parent constructor. */ + GENERIC_GPIO_LED_GET_CLASS(obj)->construct(obj, info, mcu); +} + +static void stm32_gpio_led_class_init_callback(ObjectClass *klass, void *data) +{ + STM32GPIOLEDClass *st_class = STM32_GPIO_LED_CLASS(klass); + st_class->construct = stm_gpio_led_construct_callback; + + /* Set virtual in parent class */ + GenericGPIOLEDClass *gl_class = GENERIC_GPIO_LED_CLASS(klass); + gl_class->get_gpio_dev = stm32_gpio_led_get_gpio_dev; +} + +/* + * The realize() would be empty here, and its pointer is not initialised. + */ +static const TypeInfo stm32_gpio_led_type_info = { + .name = TYPE_STM32_GPIO_LED, + .parent = TYPE_GENERIC_GPIO_LED, + .instance_size = sizeof(STM32GPIOLEDState), + .class_init = stm32_gpio_led_class_init_callback, + .class_size = sizeof(STM32GPIOLEDClass) }; + +static void stm32_gpio_led_type_init() +{ + type_register_static(&stm32_gpio_led_type_info); +} + +type_init(stm32_gpio_led_type_init); diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index e73cb7d..3f76c4e 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -34,3 +34,8 @@ obj-$(CONFIG_CG3) += cg3.o obj-$(CONFIG_VGA) += vga.o common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o + +# [GNU ARM Eclipse] +obj-$(CONFIG_GNU_ARM_ECLIPSE) += generic-gpio-led.o +obj-$(CONFIG_STM32) += stm32-gpio-led.o +# [GNU ARM Eclipse]