qdev: Implement named GPIOs
Implement named GPIOs on the Device layer. Listifies the existing GPIOs stuff using string keys. Legacy un-named GPIOs are preserved by using a NULL name string - they are just a single matchable element in the name list. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com> Signed-off-by: Andreas Färber <afaerber@suse.de>
This commit is contained in:
parent
6b1b144019
commit
a5f54290ce
@ -312,30 +312,82 @@ BusState *qdev_get_parent_bus(DeviceState *dev)
|
|||||||
return dev->parent_bus;
|
return dev->parent_bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
NamedGPIOList *ngl;
|
||||||
|
|
||||||
|
QLIST_FOREACH(ngl, &dev->gpios, node) {
|
||||||
|
/* NULL is a valid and matchable name, otherwise do a normal
|
||||||
|
* strcmp match.
|
||||||
|
*/
|
||||||
|
if ((!ngl->name && !name) ||
|
||||||
|
(name && ngl->name && strcmp(name, ngl->name) == 0)) {
|
||||||
|
return ngl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngl = g_malloc0(sizeof(*ngl));
|
||||||
|
ngl->name = g_strdup(name);
|
||||||
|
QLIST_INSERT_HEAD(&dev->gpios, ngl, node);
|
||||||
|
return ngl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler,
|
||||||
|
const char *name, int n)
|
||||||
|
{
|
||||||
|
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
|
||||||
|
|
||||||
|
gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler,
|
||||||
|
dev, n);
|
||||||
|
gpio_list->num_in += n;
|
||||||
|
}
|
||||||
|
|
||||||
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
|
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
|
||||||
{
|
{
|
||||||
dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler,
|
qdev_init_gpio_in_named(dev, handler, NULL, n);
|
||||||
dev, n);
|
}
|
||||||
dev->num_gpio_in += n;
|
|
||||||
|
void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
|
||||||
|
const char *name, int n)
|
||||||
|
{
|
||||||
|
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
|
||||||
|
|
||||||
|
assert(gpio_list->num_out == 0);
|
||||||
|
gpio_list->num_out = n;
|
||||||
|
gpio_list->out = pins;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
|
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
|
||||||
{
|
{
|
||||||
assert(dev->num_gpio_out == 0);
|
qdev_init_gpio_out_named(dev, pins, NULL, n);
|
||||||
dev->num_gpio_out = n;
|
}
|
||||||
dev->gpio_out = pins;
|
|
||||||
|
qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n)
|
||||||
|
{
|
||||||
|
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
|
||||||
|
|
||||||
|
assert(n >= 0 && n < gpio_list->num_in);
|
||||||
|
return gpio_list->in[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
|
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
|
||||||
{
|
{
|
||||||
assert(n >= 0 && n < dev->num_gpio_in);
|
return qdev_get_gpio_in_named(dev, NULL, n);
|
||||||
return dev->gpio_in[n];
|
}
|
||||||
|
|
||||||
|
void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
||||||
|
qemu_irq pin)
|
||||||
|
{
|
||||||
|
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
|
||||||
|
|
||||||
|
assert(n >= 0 && n < gpio_list->num_out);
|
||||||
|
gpio_list->out[n] = pin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
|
void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
|
||||||
{
|
{
|
||||||
assert(n >= 0 && n < dev->num_gpio_out);
|
qdev_connect_gpio_out_named(dev, NULL, n, pin);
|
||||||
dev->gpio_out[n] = pin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
|
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
|
||||||
@ -844,6 +896,7 @@ static void device_initfn(Object *obj)
|
|||||||
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
|
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
|
||||||
(Object **)&dev->parent_bus, NULL, 0,
|
(Object **)&dev->parent_bus, NULL, 0,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
|
QLIST_INIT(&dev->gpios);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void device_post_init(Object *obj)
|
static void device_post_init(Object *obj)
|
||||||
@ -854,10 +907,22 @@ static void device_post_init(Object *obj)
|
|||||||
/* Unlink device from bus and free the structure. */
|
/* Unlink device from bus and free the structure. */
|
||||||
static void device_finalize(Object *obj)
|
static void device_finalize(Object *obj)
|
||||||
{
|
{
|
||||||
|
NamedGPIOList *ngl, *next;
|
||||||
|
|
||||||
DeviceState *dev = DEVICE(obj);
|
DeviceState *dev = DEVICE(obj);
|
||||||
if (dev->opts) {
|
if (dev->opts) {
|
||||||
qemu_opts_del(dev->opts);
|
qemu_opts_del(dev->opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) {
|
||||||
|
QLIST_REMOVE(ngl, node);
|
||||||
|
qemu_free_irqs(ngl->in);
|
||||||
|
g_free(ngl->name);
|
||||||
|
g_free(ngl);
|
||||||
|
/* ngl->out irqs are owned by the other end and should not be freed
|
||||||
|
* here
|
||||||
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void device_class_base_init(ObjectClass *class, void *data)
|
static void device_class_base_init(ObjectClass *class, void *data)
|
||||||
|
@ -131,6 +131,17 @@ typedef struct DeviceClass {
|
|||||||
const char *bus_type;
|
const char *bus_type;
|
||||||
} DeviceClass;
|
} DeviceClass;
|
||||||
|
|
||||||
|
typedef struct NamedGPIOList NamedGPIOList;
|
||||||
|
|
||||||
|
struct NamedGPIOList {
|
||||||
|
char *name;
|
||||||
|
qemu_irq *in;
|
||||||
|
int num_in;
|
||||||
|
qemu_irq *out;
|
||||||
|
int num_out;
|
||||||
|
QLIST_ENTRY(NamedGPIOList) node;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeviceState:
|
* DeviceState:
|
||||||
* @realized: Indicates whether the device has been fully constructed.
|
* @realized: Indicates whether the device has been fully constructed.
|
||||||
@ -148,10 +159,7 @@ struct DeviceState {
|
|||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
int hotplugged;
|
int hotplugged;
|
||||||
BusState *parent_bus;
|
BusState *parent_bus;
|
||||||
int num_gpio_out;
|
QLIST_HEAD(, NamedGPIOList) gpios;
|
||||||
qemu_irq *gpio_out;
|
|
||||||
int num_gpio_in;
|
|
||||||
qemu_irq *gpio_in;
|
|
||||||
QLIST_HEAD(, BusState) child_bus;
|
QLIST_HEAD(, BusState) child_bus;
|
||||||
int num_child_bus;
|
int num_child_bus;
|
||||||
int instance_id_alias;
|
int instance_id_alias;
|
||||||
@ -252,7 +260,11 @@ void qdev_machine_creation_done(void);
|
|||||||
bool qdev_machine_modified(void);
|
bool qdev_machine_modified(void);
|
||||||
|
|
||||||
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
|
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
|
||||||
|
qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n);
|
||||||
|
|
||||||
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
|
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
|
||||||
|
void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
||||||
|
qemu_irq pin);
|
||||||
|
|
||||||
BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
|
BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
|
||||||
|
|
||||||
@ -262,6 +274,10 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
|
|||||||
/* GPIO inputs also double as IRQ sinks. */
|
/* GPIO inputs also double as IRQ sinks. */
|
||||||
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
|
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
|
||||||
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
|
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
|
||||||
|
void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler,
|
||||||
|
const char *name, int n);
|
||||||
|
void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
|
||||||
|
const char *name, int n);
|
||||||
|
|
||||||
BusState *qdev_get_parent_bus(DeviceState *dev);
|
BusState *qdev_get_parent_bus(DeviceState *dev);
|
||||||
|
|
||||||
|
@ -613,14 +613,20 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
|
|||||||
{
|
{
|
||||||
ObjectClass *class;
|
ObjectClass *class;
|
||||||
BusState *child;
|
BusState *child;
|
||||||
|
NamedGPIOList *ngl;
|
||||||
|
|
||||||
qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
|
qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
|
||||||
dev->id ? dev->id : "");
|
dev->id ? dev->id : "");
|
||||||
indent += 2;
|
indent += 2;
|
||||||
if (dev->num_gpio_in) {
|
QLIST_FOREACH(ngl, &dev->gpios, node) {
|
||||||
qdev_printf("gpio-in %d\n", dev->num_gpio_in);
|
if (ngl->num_in) {
|
||||||
|
qdev_printf("gpio-in \"%s\" %d\n", ngl->name ? ngl->name : "",
|
||||||
|
ngl->num_in);
|
||||||
|
}
|
||||||
|
if (ngl->num_out) {
|
||||||
|
qdev_printf("gpio-out \"%s\" %d\n", ngl->name ? ngl->name : "",
|
||||||
|
ngl->num_out);
|
||||||
}
|
}
|
||||||
if (dev->num_gpio_out) {
|
|
||||||
qdev_printf("gpio-out %d\n", dev->num_gpio_out);
|
|
||||||
}
|
}
|
||||||
class = object_get_class(OBJECT(dev));
|
class = object_get_class(OBJECT(dev));
|
||||||
do {
|
do {
|
||||||
|
13
qtest.c
13
qtest.c
@ -234,6 +234,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
|
|||||||
if (strcmp(words[0], "irq_intercept_out") == 0
|
if (strcmp(words[0], "irq_intercept_out") == 0
|
||||||
|| strcmp(words[0], "irq_intercept_in") == 0) {
|
|| strcmp(words[0], "irq_intercept_in") == 0) {
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
|
NamedGPIOList *ngl;
|
||||||
|
|
||||||
g_assert(words[1]);
|
g_assert(words[1]);
|
||||||
dev = DEVICE(object_resolve_path(words[1], NULL));
|
dev = DEVICE(object_resolve_path(words[1], NULL));
|
||||||
@ -253,10 +254,18 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QLIST_FOREACH(ngl, &dev->gpios, node) {
|
||||||
|
/* We don't support intercept of named GPIOs yet */
|
||||||
|
if (ngl->name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (words[0][14] == 'o') {
|
if (words[0][14] == 'o') {
|
||||||
qemu_irq_intercept_out(&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out);
|
qemu_irq_intercept_out(&ngl->out, qtest_irq_handler,
|
||||||
|
ngl->num_out);
|
||||||
} else {
|
} else {
|
||||||
qemu_irq_intercept_in(dev->gpio_in, qtest_irq_handler, dev->num_gpio_in);
|
qemu_irq_intercept_in(ngl->in, qtest_irq_handler,
|
||||||
|
ngl->num_in);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
irq_intercept_dev = dev;
|
irq_intercept_dev = dev;
|
||||||
qtest_send_prefix(chr);
|
qtest_send_prefix(chr);
|
||||||
|
Loading…
Reference in New Issue
Block a user