提交 a5f54290 编写于 作者: P Peter Crosthwaite 提交者: Andreas Färber

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: NPeter Maydell <peter.maydell@linaro.org>
Signed-off-by: NPeter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: NAndreas Färber <afaerber@suse.de>
上级 6b1b1440
...@@ -312,30 +312,82 @@ BusState *qdev_get_parent_bus(DeviceState *dev) ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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 { ...@@ -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); ...@@ -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); ...@@ -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) ...@@ -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 : "",
if (dev->num_gpio_out) { ngl->num_in);
qdev_printf("gpio-out %d\n", dev->num_gpio_out); }
if (ngl->num_out) {
qdev_printf("gpio-out \"%s\" %d\n", ngl->name ? ngl->name : "",
ngl->num_out);
}
} }
class = object_get_class(OBJECT(dev)); class = object_get_class(OBJECT(dev));
do { do {
......
...@@ -233,7 +233,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) ...@@ -233,7 +233,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
g_assert(command); g_assert(command);
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) ...@@ -253,10 +254,18 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
return; return;
} }
if (words[0][14] == 'o') { QLIST_FOREACH(ngl, &dev->gpios, node) {
qemu_irq_intercept_out(&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out); /* We don't support intercept of named GPIOs yet */
} else { if (ngl->name) {
qemu_irq_intercept_in(dev->gpio_in, qtest_irq_handler, dev->num_gpio_in); continue;
}
if (words[0][14] == 'o') {
qemu_irq_intercept_out(&ngl->out, qtest_irq_handler,
ngl->num_out);
} else {
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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册