]>
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 | ||
44 | static const XenBackendImpl *xen_backend_table_lookup(const char *type) | |
45 | { | |
46 | return g_hash_table_lookup(xen_backend_table_get(), type); | |
47 | } | |
48 | ||
49 | void xen_backend_register(const XenBackendInfo *info) | |
50 | { | |
51 | XenBackendImpl *impl = g_new0(XenBackendImpl, 1); | |
52 | ||
53 | g_assert(info->type); | |
54 | ||
55 | if (xen_backend_table_lookup(info->type)) { | |
56 | error_report("attempt to register duplicate Xen backend type '%s'", | |
57 | info->type); | |
58 | abort(); | |
59 | } | |
60 | ||
61 | if (!info->create) { | |
62 | error_report("backend type '%s' has no creator", info->type); | |
63 | abort(); | |
64 | } | |
65 | ||
66 | impl->type = info->type; | |
67 | impl->create = info->create; | |
68 | impl->destroy = info->destroy; | |
69 | ||
70 | xen_backend_table_add(impl); | |
71 | } | |
72 | ||
73 | static QLIST_HEAD(, XenBackendInstance) backend_list; | |
74 | ||
75 | static void xen_backend_list_add(XenBackendInstance *backend) | |
76 | { | |
77 | QLIST_INSERT_HEAD(&backend_list, backend, entry); | |
78 | } | |
79 | ||
80 | static XenBackendInstance *xen_backend_list_find(XenDevice *xendev) | |
81 | { | |
82 | XenBackendInstance *backend; | |
83 | ||
84 | QLIST_FOREACH(backend, &backend_list, entry) { | |
85 | if (backend->xendev == xendev) { | |
86 | return backend; | |
87 | } | |
88 | } | |
89 | ||
90 | return NULL; | |
91 | } | |
92 | ||
93 | static void xen_backend_list_remove(XenBackendInstance *backend) | |
94 | { | |
95 | QLIST_REMOVE(backend, entry); | |
96 | } | |
97 | ||
98 | void xen_backend_device_create(XenBus *xenbus, const char *type, | |
99 | const char *name, QDict *opts, Error **errp) | |
100 | { | |
101 | const XenBackendImpl *impl = xen_backend_table_lookup(type); | |
102 | XenBackendInstance *backend; | |
103 | Error *local_error = NULL; | |
104 | ||
105 | if (!impl) { | |
106 | return; | |
107 | } | |
108 | ||
109 | backend = g_new0(XenBackendInstance, 1); | |
110 | backend->xenbus = xenbus; | |
111 | backend->name = g_strdup(name); | |
112 | ||
113 | impl->create(backend, opts, &local_error); | |
114 | if (local_error) { | |
115 | error_propagate(errp, local_error); | |
116 | g_free(backend->name); | |
117 | g_free(backend); | |
118 | return; | |
119 | } | |
120 | ||
121 | backend->impl = impl; | |
122 | xen_backend_list_add(backend); | |
123 | } | |
124 | ||
125 | XenBus *xen_backend_get_bus(XenBackendInstance *backend) | |
126 | { | |
127 | return backend->xenbus; | |
128 | } | |
129 | ||
130 | const char *xen_backend_get_name(XenBackendInstance *backend) | |
131 | { | |
132 | return backend->name; | |
133 | } | |
134 | ||
135 | void xen_backend_set_device(XenBackendInstance *backend, | |
136 | XenDevice *xendev) | |
137 | { | |
138 | g_assert(!backend->xendev); | |
139 | backend->xendev = xendev; | |
140 | } | |
141 | ||
142 | XenDevice *xen_backend_get_device(XenBackendInstance *backend) | |
143 | { | |
144 | return backend->xendev; | |
145 | } | |
146 | ||
147 | ||
148 | bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp) | |
149 | { | |
150 | XenBackendInstance *backend = xen_backend_list_find(xendev); | |
151 | const XenBackendImpl *impl; | |
152 | ||
153 | if (!backend) { | |
154 | return false; | |
155 | } | |
156 | ||
157 | impl = backend->impl; | |
158 | impl->destroy(backend, errp); | |
159 | ||
160 | xen_backend_list_remove(backend); | |
161 | g_free(backend->name); | |
162 | g_free(backend); | |
163 | ||
164 | return true; | |
165 | } |