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; | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|     dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler, | ||||
|                                         dev, n); | ||||
|     dev->num_gpio_in += n; | ||||
|     qdev_init_gpio_in_named(dev, handler, NULL, 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) | ||||
| { | ||||
|     assert(dev->num_gpio_out == 0); | ||||
|     dev->num_gpio_out = n; | ||||
|     dev->gpio_out = pins; | ||||
|     qdev_init_gpio_out_named(dev, pins, NULL, n); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|     assert(n >= 0 && n < dev->num_gpio_in); | ||||
|     return dev->gpio_in[n]; | ||||
|     return qdev_get_gpio_in_named(dev, NULL, 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) | ||||
| { | ||||
|     assert(n >= 0 && n < dev->num_gpio_out); | ||||
|     dev->gpio_out[n] = pin; | ||||
|     qdev_connect_gpio_out_named(dev, NULL, n, pin); | ||||
| } | ||||
| 
 | ||||
| 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 **)&dev->parent_bus, NULL, 0, | ||||
|                              &error_abort); | ||||
|     QLIST_INIT(&dev->gpios); | ||||
| } | ||||
| 
 | ||||
| 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.  */ | ||||
| static void device_finalize(Object *obj) | ||||
| { | ||||
|     NamedGPIOList *ngl, *next; | ||||
| 
 | ||||
|     DeviceState *dev = DEVICE(obj); | ||||
|     if (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) | ||||
|  | ||||
| @ -131,6 +131,17 @@ typedef struct DeviceClass { | ||||
|     const char *bus_type; | ||||
| } 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: | ||||
|  * @realized: Indicates whether the device has been fully constructed. | ||||
| @ -148,10 +159,7 @@ struct DeviceState { | ||||
|     QemuOpts *opts; | ||||
|     int hotplugged; | ||||
|     BusState *parent_bus; | ||||
|     int num_gpio_out; | ||||
|     qemu_irq *gpio_out; | ||||
|     int num_gpio_in; | ||||
|     qemu_irq *gpio_in; | ||||
|     QLIST_HEAD(, NamedGPIOList) gpios; | ||||
|     QLIST_HEAD(, BusState) child_bus; | ||||
|     int num_child_bus; | ||||
|     int instance_id_alias; | ||||
| @ -252,7 +260,11 @@ void qdev_machine_creation_done(void); | ||||
| bool qdev_machine_modified(void); | ||||
| 
 | ||||
| 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_named(DeviceState *dev, const char *name, int n, | ||||
|                                  qemu_irq pin); | ||||
| 
 | ||||
| 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.  */ | ||||
| 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_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); | ||||
| 
 | ||||
|  | ||||
| @ -613,14 +613,20 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent) | ||||
| { | ||||
|     ObjectClass *class; | ||||
|     BusState *child; | ||||
|     NamedGPIOList *ngl; | ||||
| 
 | ||||
|     qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)), | ||||
|                 dev->id ? dev->id : ""); | ||||
|     indent += 2; | ||||
|     if (dev->num_gpio_in) { | ||||
|         qdev_printf("gpio-in %d\n", dev->num_gpio_in); | ||||
|     } | ||||
|     if (dev->num_gpio_out) { | ||||
|         qdev_printf("gpio-out %d\n", dev->num_gpio_out); | ||||
|     QLIST_FOREACH(ngl, &dev->gpios, node) { | ||||
|         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); | ||||
|         } | ||||
|     } | ||||
|     class = object_get_class(OBJECT(dev)); | ||||
|     do { | ||||
|  | ||||
							
								
								
									
										19
									
								
								qtest.c
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								qtest.c
									
									
									
									
									
								
							| @ -233,7 +233,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) | ||||
|     g_assert(command); | ||||
|     if (strcmp(words[0], "irq_intercept_out") == 0 | ||||
|         || strcmp(words[0], "irq_intercept_in") == 0) { | ||||
| 	DeviceState *dev; | ||||
|         DeviceState *dev; | ||||
|         NamedGPIOList *ngl; | ||||
| 
 | ||||
|         g_assert(words[1]); | ||||
|         dev = DEVICE(object_resolve_path(words[1], NULL)); | ||||
| @ -253,10 +254,18 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) | ||||
| 	    return; | ||||
|         } | ||||
| 
 | ||||
|         if (words[0][14] == 'o') { | ||||
|             qemu_irq_intercept_out(&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out); | ||||
|         } else { | ||||
|             qemu_irq_intercept_in(dev->gpio_in, qtest_irq_handler, dev->num_gpio_in); | ||||
|         QLIST_FOREACH(ngl, &dev->gpios, node) { | ||||
|             /* We don't support intercept of named GPIOs yet */ | ||||
|             if (ngl->name) { | ||||
|                 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; | ||||
|         qtest_send_prefix(chr); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Peter Crosthwaite
						Peter Crosthwaite