]>
Commit | Line | Data |
---|---|---|
a783f8ad PD |
1 | /* |
2 | * Copyright (c) 2018 Citrix Systems Inc. | |
3 | * | |
4 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
5 | * See the COPYING file in the top-level directory. | |
6 | */ | |
7 | ||
8 | #include "qemu/osdep.h" | |
9 | #include "qemu/error-report.h" | |
10 | #include "qapi/error.h" | |
11 | #include "hw/xen/xen-backend.h" | |
12 | #include "hw/xen/xen-bus.h" | |
13 | ||
14 | typedef struct XenBackendImpl { | |
15 | const char *type; | |
16 | XenBackendDeviceCreate create; | |
17 | XenBackendDeviceDestroy destroy; | |
18 | } XenBackendImpl; | |
19 | ||
20 | struct XenBackendInstance { | |
21 | QLIST_ENTRY(XenBackendInstance) entry; | |
22 | const XenBackendImpl *impl; | |
23 | XenBus *xenbus; | |
24 | char *name; | |
25 | XenDevice *xendev; | |
26 | }; | |
27 | ||
28 | static GHashTable *xen_backend_table_get(void) | |
29 | { | |
30 | static GHashTable *table; | |
31 | ||
32 | if (table == NULL) { | |
33 | table = g_hash_table_new(g_str_hash, g_str_equal); | |
34 | } | |
35 | ||
36 | return table; | |
37 | } | |
38 | ||
39 | static void xen_backend_table_add(XenBackendImpl *impl) | |
40 | { | |
41 | g_hash_table_insert(xen_backend_table_get(), (void *)impl->type, impl); | |
42 | } | |
43 | ||
c4583c8c PD |
44 | static const char **xen_backend_table_keys(unsigned int *count) |
45 | { | |
46 | return (const char **)g_hash_table_get_keys_as_array( | |
47 | xen_backend_table_get(), count); | |
48 | } | |
49 | ||
a783f8ad PD |
50 | static const XenBackendImpl *xen_backend_table_lookup(const char *type) |
51 | { | |
52 | return g_hash_table_lookup(xen_backend_table_get(), type); | |
53 | } | |
54 | ||
55 | void xen_backend_register(const XenBackendInfo *info) | |
56 | { | |
57 | XenBackendImpl *impl = g_new0(XenBackendImpl, 1); | |
58 | ||
59 | g_assert(info->type); | |
60 | ||
61 | if (xen_backend_table_lookup(info->type)) { | |
62 | error_report("attempt to register duplicate Xen backend type '%s'", | |
63 | info->type); | |
64 | abort(); | |
65 | } | |
66 | ||
67 | if (!info->create) { | |
68 | error_report("backend type '%s' has no creator", info->type); | |
69 | abort(); | |
70 | } | |
71 | ||
72 | impl->type = info->type; | |
73 | impl->create = info->create; | |
74 | impl->destroy = info->destroy; | |
75 | ||
76 | xen_backend_table_add(impl); | |
77 | } | |
78 | ||
c4583c8c PD |
79 | const char **xen_backend_get_types(unsigned int *count) |
80 | { | |
81 | return xen_backend_table_keys(count); | |
82 | } | |
83 | ||
a783f8ad PD |
84 | static QLIST_HEAD(, XenBackendInstance) backend_list; |
85 | ||
86 | static void xen_backend_list_add(XenBackendInstance *backend) | |
87 | { | |
88 | QLIST_INSERT_HEAD(&backend_list, backend, entry); | |
89 | } | |
90 | ||
91 | static XenBackendInstance *xen_backend_list_find(XenDevice *xendev) | |
92 | { | |
93 | XenBackendInstance *backend; | |
94 | ||
95 | QLIST_FOREACH(backend, &backend_list, entry) { | |
96 | if (backend->xendev == xendev) { | |
97 | return backend; | |
98 | } | |
99 | } | |
100 | ||
101 | return NULL; | |
102 | } | |
103 | ||
eb6ae7a6 DW |
104 | bool xen_backend_exists(const char *type, const char *name) |
105 | { | |
106 | const XenBackendImpl *impl = xen_backend_table_lookup(type); | |
107 | XenBackendInstance *backend; | |
108 | ||
109 | if (!impl) { | |
110 | return false; | |
111 | } | |
112 | ||
113 | QLIST_FOREACH(backend, &backend_list, entry) { | |
114 | if (backend->impl == impl && !strcmp(backend->name, name)) { | |
115 | return true; | |
116 | } | |
117 | } | |
118 | ||
119 | return false; | |
120 | } | |
121 | ||
a783f8ad PD |
122 | static void xen_backend_list_remove(XenBackendInstance *backend) |
123 | { | |
124 | QLIST_REMOVE(backend, entry); | |
125 | } | |
126 | ||
127 | void xen_backend_device_create(XenBus *xenbus, const char *type, | |
128 | const char *name, QDict *opts, Error **errp) | |
129 | { | |
1de7096d | 130 | ERRP_GUARD(); |
a783f8ad PD |
131 | const XenBackendImpl *impl = xen_backend_table_lookup(type); |
132 | XenBackendInstance *backend; | |
a783f8ad PD |
133 | |
134 | if (!impl) { | |
135 | return; | |
136 | } | |
137 | ||
138 | backend = g_new0(XenBackendInstance, 1); | |
139 | backend->xenbus = xenbus; | |
140 | backend->name = g_strdup(name); | |
141 | ||
1de7096d | 142 | impl->create(backend, opts, errp); |
a783f8ad PD |
143 | |
144 | backend->impl = impl; | |
145 | xen_backend_list_add(backend); | |
146 | } | |
147 | ||
148 | XenBus *xen_backend_get_bus(XenBackendInstance *backend) | |
149 | { | |
150 | return backend->xenbus; | |
151 | } | |
152 | ||
153 | const char *xen_backend_get_name(XenBackendInstance *backend) | |
154 | { | |
155 | return backend->name; | |
156 | } | |
157 | ||
158 | void xen_backend_set_device(XenBackendInstance *backend, | |
159 | XenDevice *xendev) | |
160 | { | |
161 | g_assert(!backend->xendev); | |
162 | backend->xendev = xendev; | |
163 | } | |
164 | ||
165 | XenDevice *xen_backend_get_device(XenBackendInstance *backend) | |
166 | { | |
167 | return backend->xendev; | |
168 | } | |
169 | ||
170 | ||
171 | bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp) | |
172 | { | |
173 | XenBackendInstance *backend = xen_backend_list_find(xendev); | |
174 | const XenBackendImpl *impl; | |
175 | ||
176 | if (!backend) { | |
177 | return false; | |
178 | } | |
179 | ||
180 | impl = backend->impl; | |
eb6ae7a6 DW |
181 | if (backend->xendev) { |
182 | impl->destroy(backend, errp); | |
183 | } | |
a783f8ad PD |
184 | |
185 | xen_backend_list_remove(backend); | |
186 | g_free(backend->name); | |
187 | g_free(backend); | |
188 | ||
189 | return true; | |
190 | } |