1 | /* |
2 | * QEMU IndustryPack emulation |
3 | * |
4 | * Copyright (C) 2012 Igalia, S.L. |
5 | * Author: Alberto Garcia <berto@igalia.com> |
6 | * |
7 | * This code is licensed under the GNU GPL v2 or (at your option) any |
8 | * later version. |
9 | */ |
10 | |
11 | #include "qemu/osdep.h" |
12 | #include "qapi/error.h" |
13 | #include "qemu/module.h" |
14 | #include "hw/ipack/ipack.h" |
15 | #include "hw/irq.h" |
16 | #include "hw/qdev-properties.h" |
17 | #include "migration/vmstate.h" |
18 | |
19 | IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot) |
20 | { |
21 | BusChild *kid; |
22 | |
23 | QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) { |
24 | DeviceState *qdev = kid->child; |
25 | IPackDevice *ip = IPACK_DEVICE(qdev); |
26 | if (ip->slot == slot) { |
27 | return ip; |
28 | } |
29 | } |
30 | return NULL; |
31 | } |
32 | |
33 | void ipack_bus_new_inplace(IPackBus *bus, size_t bus_size, |
34 | DeviceState *parent, |
35 | const char *name, uint8_t n_slots, |
36 | qemu_irq_handler handler) |
37 | { |
38 | qbus_create_inplace(bus, bus_size, TYPE_IPACK_BUS, parent, name); |
39 | bus->n_slots = n_slots; |
40 | bus->set_irq = handler; |
41 | } |
42 | |
43 | static void ipack_device_realize(DeviceState *dev, Error **errp) |
44 | { |
45 | IPackDevice *idev = IPACK_DEVICE(dev); |
46 | IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(dev)); |
47 | IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); |
48 | |
49 | if (idev->slot < 0) { |
50 | idev->slot = bus->free_slot; |
51 | } |
52 | if (idev->slot >= bus->n_slots) { |
53 | error_setg(errp, "Only %" PRIu8 " slots available." , bus->n_slots); |
54 | return; |
55 | } |
56 | bus->free_slot = idev->slot + 1; |
57 | |
58 | idev->irq = qemu_allocate_irqs(bus->set_irq, idev, 2); |
59 | |
60 | k->realize(dev, errp); |
61 | } |
62 | |
63 | static void ipack_device_unrealize(DeviceState *dev, Error **errp) |
64 | { |
65 | IPackDevice *idev = IPACK_DEVICE(dev); |
66 | IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); |
67 | Error *err = NULL; |
68 | |
69 | if (k->unrealize) { |
70 | k->unrealize(dev, &err); |
71 | error_propagate(errp, err); |
72 | return; |
73 | } |
74 | |
75 | qemu_free_irqs(idev->irq, 2); |
76 | } |
77 | |
78 | static Property ipack_device_props[] = { |
79 | DEFINE_PROP_INT32("slot" , IPackDevice, slot, -1), |
80 | DEFINE_PROP_END_OF_LIST() |
81 | }; |
82 | |
83 | static void ipack_device_class_init(ObjectClass *klass, void *data) |
84 | { |
85 | DeviceClass *k = DEVICE_CLASS(klass); |
86 | |
87 | set_bit(DEVICE_CATEGORY_INPUT, k->categories); |
88 | k->bus_type = TYPE_IPACK_BUS; |
89 | k->realize = ipack_device_realize; |
90 | k->unrealize = ipack_device_unrealize; |
91 | k->props = ipack_device_props; |
92 | } |
93 | |
94 | const VMStateDescription vmstate_ipack_device = { |
95 | .name = "ipack_device" , |
96 | .version_id = 1, |
97 | .minimum_version_id = 1, |
98 | .fields = (VMStateField[]) { |
99 | VMSTATE_INT32(slot, IPackDevice), |
100 | VMSTATE_END_OF_LIST() |
101 | } |
102 | }; |
103 | |
104 | static const TypeInfo ipack_device_info = { |
105 | .name = TYPE_IPACK_DEVICE, |
106 | .parent = TYPE_DEVICE, |
107 | .instance_size = sizeof(IPackDevice), |
108 | .class_size = sizeof(IPackDeviceClass), |
109 | .class_init = ipack_device_class_init, |
110 | .abstract = true, |
111 | }; |
112 | |
113 | static const TypeInfo ipack_bus_info = { |
114 | .name = TYPE_IPACK_BUS, |
115 | .parent = TYPE_BUS, |
116 | .instance_size = sizeof(IPackBus), |
117 | }; |
118 | |
119 | static void ipack_register_types(void) |
120 | { |
121 | type_register_static(&ipack_device_info); |
122 | type_register_static(&ipack_bus_info); |
123 | } |
124 | |
125 | type_init(ipack_register_types) |
126 | |